路由分发,名称空间,虚拟环境,视图层,CBV的源码剖析
路由分发
# 目前来说,一个django项目只有一个总路由文件 urls.py
# 由于django项目可以有多个app应用,每一个App应用都可以有自己的路由文件,称为子路由
# 在应用里面默认是没有urls.py的,需要手动创建一个
'''为什么要路由分发? 当总路由中有非常多的路由时候,就会显得杂乱无章,我们这个时候就可以按照应用进行路由分发,把不同的路由写到对应的应用里面去,然后总路由文件做分发处理'''
# 第一种方式
# 总路由做分发
# app01/reg/
url(r'^app01/', include(app01_urls)),
# app02/reg/
url(r'^app02/', include(app02_urls)),
# 第二种方式
# 总路由做分发
# app01/reg/
# url(r'^app01/', include(app01_urls)),
url(r'^app01/', include('app01.urls')),
# app02/reg/
# url(r'^app02/', include(app02_urls)),
url(r'^app02/', include('app02.urls')),
'''路由中的后缀坚决不能加 $'''
名称空间
'''路由分发之后 针对相同的别名能否自动反向解析出不同的应用前缀
默认情况下是无法直接识别应用前缀的'''
如果想要正常识别区分有两种方式
方式1:名称空间
总路由
path('app01/', include(('app01.urls', 'app01'), namespace='app01')),
path('app02/', include(('app02.urls', 'app02'), namespace='app02')),
反向解析
reverse('app01:index_view')
reverse('app02:index_view')
方式2:别名不冲突即可
多个应用别名不冲突可以用应用名作为别名的前缀
path('index/', views.index, name='app01_index_view')
path('index/', views.index, name='app02_index_view')
伪静态的概念
# 静态文件:写死的一些东西
# 伪静态
把一些动态的网页伪装成静态网页
'''为什么要伪装呢?'''
# 其实是因为静态的网页更加容易被搜索引擎抓取到
# 搜索引擎其实是一个巨大的爬虫程序,你在百度中搜索一个美女,百度拿着这个关键词去网络上去爬取数据,然后把爬到的数据处理好,返回到百度的页面
# 为了把我们的网页被搜索引擎更好的抓取到
seo----------------->免费的
sem------------------>收费的----------------->广告--------->rmb
虚拟环境
项目1需要使用:django1.11 python38
项目2需要使用:django2.22 pymysql requests python38
项目3需要使用:django3.22 request_html flask urllib3 python38
实际开发项目中我们只会给项目配备所需的环境,不需要的一概不配!!!
虚拟环境:能够针对相同版本的解释器创建多个分身 每个分身可以有自己独立的环境
pycharm创建虚拟环境:(每创建一个虚拟环境就相当于重新下载了一个全新的解释器)
命令行的方式: python -m venv pyvenv38
注意:python命令此处不支持多版本共存的操作 python27 python36 python38
激活
activate
关闭
deactivate
pip install --index-url http://mirrors.aliyun.com/pypi/simple/ django==1.11.11 --trusted-host mirrors.aliyun.com
视图层之必会三板斧
用来处理请求的视图函数都必须返回HttpResponse对象 完全正确
class HttpResponse:
pass
return HttpResponse()
def render():
return HttpResponse()
return render()
def redirect():
redirect_class = 类(祖先有个类是HttpResponse)
return redirect_class()
return redirect()
JsonResponse对象
from django.http import JsonResponse
def index_func(request):
# return HttpResponse('哈哈哈')
# return render()
# return redirect()
# 返回给浏览器一个json格式的字符串
user_dict = {'name': 'jason老师', 'age': 18}
# import json
# user_json = json.dumps(user_dict, ensure_ascii=False)
# return HttpResponse(user_json)
return JsonResponse(user_dict)
ps:以后写代码很多时候可能需要参考源码及所学知识扩展功能
class JsonResponse():
def __init__(self,data,json_dumps_params=None):
json.dumps(data,**json_dumps_params)
#字典前面加**可以把键值对转换成关键字参数
'''
JsonResponse主要序列化字典 针对非字典的其他可以被序列化的数据需要修改safe参数为False
'''
视图层之request对象获取文件
form表单携带文件类型的数据需要做到以下几点
1.method必须是post
2.enctype必须是multipart/form-data
django后端需要通过request.FILES获取文件类型的数据
ex:
file_obj = request.FILES.get(文件字典的K)
file_obj#(文件对象)
file_obj.name不要用这个了,这个名字一般我们会重命名,自己写一个生成随机数的方法,调用这个方法,得到一个随机数,拿着个随机数去拼接图片的后缀名
def random():
import uuid
return uuid.uuid4()
with open(r'%s'%file_obj.name,'wb') as f:
for line in file_obj: #文件对象支持for循环一行行读取内容
f.write(line)
视图层之FBV与CBV
FBV
基于函数的视图
def index(request):return HttpResponse对象
CBV
基于类的视图
from django import views
class MyLoginView(views.View):
def get(self, request):
return HttpResponse('from CBV get function')
def post(self, request):
return HttpResponse('from CBV post function')
path('login/', views.MyLoginView.as_view())
会自动根据请求方法的不同自动匹配对应的方法并执行
getattr()函数
用来返回函数的一个对象属性值
语法:
getattr(object,name,default)
object -- 对象。
name -- 字符串,对象属性。
default -- 默认返回值,如果不提供该参数,在没有对应属性时,将触发 AttributeError。
>>>class A(object):
... bar = 1
...
>>> a = A()
>>> getattr(a, 'bar') # 获取属性 bar 值
1
>>> getattr(a, 'bar2') # 属性 bar2 不存在,触发异常
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'bar2'
>>> getattr(a, 'bar2', 3) # 属性 bar2 不存在,但设置了默认值
3
>>>
CBV的源码剖析
# 看源码首先先找入口,CBV的入口就在路由:path('login/', views.MyLogin.as_view()),
"""
类来调用方法:
1. 被@classmethod装饰器修饰的方法
2. 被@staticmethod装饰器修饰的方法
我们在MyLogin类中并没有写as_view(), 可能会在父类中
views.MyLogin.as_view()-------------------->View类里面的as_view方法中得view方法的内存地址
"""
path('login/', views.MyLogin.as_view()), # 本质上放的还是函数的内存地址
path('index/', views.index),
# 当请求来了,会自定触发view函数的执行
def view(request, *args, **kwargs):
self = cls(**initkwargs) # # self = MyLogin(**initkwargs)
return self.dispatch(request, *args, **kwargs)
# view函数执行完毕之后,来到了return self.dispatch(request, *args, **kwargs)
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
if request.method.lower() in self.http_method_names:
# handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
handler = getattr(self, 'get', self.http_method_not_allowed)
# handler----------->get函数的内存地址
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
# 权限 频率等的源码稍微复杂
'''源码时让你用来看的,不是让你用来改的'''
class MyLogin(View):
http_method_names = ['get', 'post']
# 我写的这个类只允许get请求,怎么做?
# 通过get请求方式会访问到这个方法
def get(self, request):
return HttpResponse('get')
# 通过post请求方式会访问到这个方法
def post(self, request):
return HttpResponse('post')
CBV源码个人解析
先从路由导入切入:path('login/',views.myloginView.as_view()),
看看myloginView
类有没有as_view
方法,如果没有的话就去源码找
类调用对象就2种方式:
一个是@staticmethod
静态方法,
一个是@classmethod
方法会将类当成第一个参数传入进去
按住ctrl+左键点进去发现是一个闭包函数
class View:
@classonlymethod
def as_view(cls, **initkwargs):
self = cls(**initkwargs) self为调用函数这个类产生的对象
...
def view(request, *args, **kwargs):
...
return self.dispatch(request, *args, **kwargs)
...
return view
通过执行as_view()
函数就会返回view函数的内存地址
那么 myloginView.as_view() = view
这个时候如果调用前面的路由login/就会执行后面view函数的内存地址来调用view函数
然后会返回一个dispatch(request, *args, **kwargs)
函数
这个时候看视图类中存不存在dispatch方法,如果不存在就在源码里找**
if request.method.lower() in self.http_method_names:
将浏览器请求转成小写的形式看看是否在对象调用的这个属性里面
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
如果存在的话则通过getattr函数返回属性
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
getattr(对象,字符串或者属性,默认返回值)存在则返回第二个参数,不存在则返回默认值
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
如果不存在http_method_names
里面的话则调用http_method_not_allowed``方法报错
存在的话则是返回get(request, *args, **kwargs)
或则post(request, *args, **kwargs)
来调用视图层的方法
(目前只学了这两种请求)