路由分发,名称空间,虚拟环境,视图层,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

image

视图层之必会三板斧

用来处理请求的视图函数都必须返回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)来调用视图层的方法
(目前只学了这两种请求)

posted @ 2023-04-24 21:38  无敌大帅逼  阅读(84)  评论(0)    收藏  举报