11_04、Django请求生命周期流程图、路由层、cbv源码
一、Django请求生命周期流程图
二、路由层
1、路由文件
项目中url.py文件中,添加路由设置
urlpatterns = [ url(r'^test/', views.test), ]
r'^test/' # 正则表达式,匹配以test开头,以/结尾的字符,r是去掉转义符,保证斜杠只是斜杠字符,而不会发生转义
views.test # view.py文件中的test函数内存地址
注意:settings.py文件中的APPEND_SLASH控制斜杠自动匹配
APPEND_SLASH = True # 控制斜杠自动匹配(默认) APPEND_SLASH = False # 取消斜杠自动匹配
2、有名分组和无名分组
1.什么是分组
有名分组和无名分组是正则分组的两种形式。
分组是通过括号把正则表达式括起来,特征是组内优先展示。
路由文件中的r'^test/'是一个正则表达式,所以也可以通过有名分组和无名分组的方式书写
2.为什么要用到分组
url中的前半部分(r'^test/'),是用户输入的网址后缀。
是为了给后半部分(views.test)这个函数名的内存地址匹配。
通过正则分组可以作为位置实参给函数传参
但是注意,有几个分组(参数),函数内就必须有相应的位置形参用于接收。
3、实例演示
有名分组:
# url.py文件 urlpatterns = [ url(r'^test/(\d+)/(\a+)', views.test), ]
# view.py文件 def test(request, first, second): print(first) # (\d+)匹配的内容 print(second) # (\a+)匹配的内容 return render(request, 'test.html', locals())
无名分组:
# url.py文件 urlpatterns = [ url(r'^test/(?P<year>\d+)/(?P<month>\a+)', views.test), # 有名分组,给正则名称:year,month ]
# view.py文件 def test(request, first, second): print(first) # (\d+)匹配的内容是关键字year print(second) # (\a+)匹配的内容匹配的内容是关键字month return render(request, 'test.html', locals())
注意:如果参数太多,可以用*args,**kwargs接收
# view.py文件 def test(request, args, **kwargs): print(*args) print(**kwargs) return render(request, 'test.html', locals())
3、反向解析
1、起别名
针对过长匹配的url,我们可以用name给其重命名
urlpatterns = [ url(r'^test/test1/test2/test3/', views.test, name='test'), # 给r'^test/test1/test2/test3/'重命名为test ]
2、反向解析
反向解析就是通过name反向解析出原来的url
后端反向解析
# view.py文件 from django.shortcuts import reverse def test(request): print(reverse('test')) # /test/test1/test2/test3/ return render(request, 'test.html', locals())
前端反向解析
# test.html文件 <body> <a href="{% url 'test' %}">前端反向解析</a> </body>
无名分组前端反向解析
无名分组后端反向解析
有名分组前端反向解析
有名分组后端反向解析
4、路由分发
1、为什么要路由分发
随着时间和用户的增多,我们的Django项目也会越来越大,那么毫无疑问我们的总路由文件也会也来越大
这会导致项目非常难以维护,为此我们会把总路由分开到不同的应用下面去,这是受Django框架支持的。
Django支持每个应用下面有自己的:
# 1、url.py文件 # 2、static文件夹 # 3、templates文件夹
2、怎么路由分发
第一步:
把总路由复制到各个应用中,并修改
# app02中的urls.py from django.conf.urls import url from django.contrib import admin from app02 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index), ]
# app02中的urls.py from django.conf.urls import url from django.contrib import admin from app03 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index), ]
第二步:总路由分发(include)
方式一:
""" 总路由文件urls.py 导入include 给分路由重命名 """ from django.conf.urls import url, include from django.contrib import admin from app01 import views from app02 import urls as app02_url from app03 import urls as app03_url # url.py文件 urlpatterns = [ # 总路由分发 url(r'^app02/', include(app02_url),), url(r'^app03/', include(app03_url),), ]
方式二:
""" 总路由文件urls.py 无需导入 """ from django.conf.urls import url, include from django.contrib import admin from app01 import views # url.py文件 urlpatterns = [ url(r'^app02/', include('app02.urls')), url(r'^app03/', include('app03.urls')), ]
第三步:效果展示
查看app02
查看app03
5、名称空间
我们再给路由起别名的时候,如果两个url命名为相同的名字
在根据别名反向解析的时候,默认解析的是最后一个
如果要精准解析,这里就要用到名称空间的知识了(namespace = '自定义名称空间名字')
# 总路由文件urls.py urlpatterns = [ url(r'^app02/', include('app02.urls', namespace='app02')), url(r'^app03/', include('app03.urls', namespace='app03')), ]
方向解析的时候
from django.shortcuts import render,HttpResponse,reverse def index(request): print(reverse('app02:test')) return HttpResponse('app02:index')
三、虚拟环境
应用于多个多个项目,每个项目需要应用不同的模块、版本。
虚拟环境就是一个纯净版的python解释器,我们可以在这个虚拟环境上安装每个应用需要的插件
我们可以同时拥有多个虚拟环境
四、JsonResponse(json序列化)
json格式的数据用于跨语言传输,
编码就是把不用语言转成二进制,解码就是把二进制在转成各种不同的语言
序列化就是通过json通过把python的语言转换成json字符串,
反序列化就是通过json把json字符串转换成python格式
后端中的序列化和反序列化:
序列化:json.dumps
反序列化:json.loads
前端中的序列化和反序列化:
序列化:JSON.stringify()
反序列化:JSON.parse()
注意:
前后端分离的项目,需要用到json格式的数据
混合项目开发项目,用不到json格式的数据
django框架通过对json进一步封装,方便了我们实现数据的序列和反序列化
from django.http import JsonResponse def my_json(request): my_dict = {'username': '鲁迅', 'gender': 'male'} # 字典类型 my_list = [1, 2, 3] # 非字典类型 # res = json.dumps(my_dict, ensure_ascii=False) # json转码 # return HttpResponse(res) # json序列化 # return JsonResponse(my_json, json_dumps_params={'ensure_ascii': False}) # 字典类型的序列化 return JsonResponse(my_list, safe=False) # 非字典类型的序列化
五、CBV的书写
CBV和FBV是一个概念的东西
FBV:function base views,顾名思义,基于视图的函数(views.py中的函数)
CBV:class base views,同理,基于视图的类(views.py中的类)
'''views.py文件''' # cbv必须继承View类 from django.views import View class IndexClass(View): # 注意类中的方法名必须指定为八种请求方式中的一种,不能随意指定 # 八种方式:get post push def get(self, request): return HttpResponse('get') def post(self, request): return HttpResponse('post')
'''urls.py''' urlpatterns = [ url(r'^my_cbv/', views.IndexClass.as_view()), ]
六、CBV的源码分析
七、form表单上传文件
之前我们学过get请求和post请求可以通过request.get和request.post接收请求数据
文件也有自己的接收方式:request.FILES
'''views.py文件''' def my_form(request): if request.method == 'POST': print(request.GET) # get请求的对象request.GET,此处为<QueryDict: {}> print(request.POST) # post请求的对象request.POST,此处为<QueryDict: {}> print(request.FILES) # 文件对象在request.FILES,<MultiValueDict: {'myfile': [<InMemoryUploadedFile: 测试图片.png (image/png)>]}> # request.FILES只接收文件数据,其他请求一概不接收 # 字典取值 file_obj = request.FILES.get('myfile') print(file_obj.name) # 文件的名称:微信截图_20220313203813.png # 上传文件 with open(file_obj.name, 'wb') as f: # 上传文件的时候要一行一行读取,防止内存溢出 for line in file_obj: f.write(line) # 上传的文件存放在项目的根目录 return render(request, 'my_form.html')
{# HTML文件 #} {#注意:form表单上传文件的两个必须条件method="post" enctype="multipart/form-data"#} <form action="" method="post" enctype="multipart/form-data"> <p> 上传文件:<input type="file" name="myfile"> </p> <input type="submit" value="提交"> </form>
'''urls.py文件''' urlpatterns = [ url(r'^my_form/', views.my_form), # 上传图片 ]
注意:上传的文件存放在项目根目录 ,但是再次上传图片文件,会把原先上传的覆盖掉
我们可以通过导入随机数重命名,解决这个问题
'''views.py文件''' def my_form(request): if request.method == 'POST': print(request.GET) # get请求的对象request.GET,此处为<QueryDict: {}> print(request.POST) # post请求的对象request.POST,此处为<QueryDict: {}> print(request.FILES) # 文件对象在request.FILES,<MultiValueDict: {'myfile': [<InMemoryUploadedFile: 测试图片.png (image/png)>]}> # request.FILES只接收文件数据,其他请求一概不接收 # 字典取值 file_obj = request.FILES.get('myfile') print(file_obj.name) # 文件的名称:微信截图_20220313203813.png import uuid rend_str = uuid.uuid4() file_path = str(rend_str) + '.png' # 上传文件 with open(file_path, 'wb') as f: # 上传文件的时候要一行一行读取,防止内存溢出 for line in file_obj: f.write(line) # 上传的文件存放在项目的根目录 return render(request, 'my_form.html')
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通