目录
django的生命周期是:前端请求--->nginx--->uwsgi.--->中间件--->url路由---->view视图--->orm---->拿到数据返回给view---->试图将数据渲染到模版中拿到字符串---->中间件--->uwsgi---->nginx---->前端渲染。
django请求声明周期流程图
浏览器基于http协议发送请求>>>进入django的web服务网关接口(wsgiref, tashidjango默认的网关接口,但是并发量很低,所以上线后都会切换为uwsgi以提高并发量, [wsgi是一个协议, 剩下两个都是基于此协议的模块]), 当请求来的时候拆解数据,相应走的时候封装数据, >>>进到django后端[整个django框架]
先经过django中间件,类似于安保系统, 经过筛选后才会将数据传到后边,>>>>进入urls.py 路由层. 在路由曾栗晚成路径匹配, 有了确定路径之后进入视图层,>>>views.py 视图层执行核心业务逻辑,若是全栈项目就需要用到HTML页面,若只写后端接口则不用HTML, >>>>templates文件夹,模板层, >>>>模型层 models.py 去跟数据库做交涉, 模型层链接数据库MySQL. 视图层需要模板的话去模板层拿模板,需要数据的话去模型层拿数据, 根据orm去MySQL里操作, MySQL返回数据,orm将它封装成数据对象,在视图层通过模板语法做一个模板语法渲染, 渲染完之后,直接由视图层返回到中间件,再次经过校验,然后中间件将数据交给网关接口去打包,打包完成之后发送给浏览器, >>>浏览器接收数据.其实在wsgiref之前还有一个nginx,做一个反向代理,提升其并发量, 在整个流程外还有一个缓存数据库,想要请求数据时, 会先去缓存数据库里找, 没有找到的情况下才会去MySQL找.
学习先从 路由层开始, >>>视图层>>>模板层>>模型层>>>django插件>>>django中间件
中间件的作用非常大,可以处理所有的请求内容,中间件其实就是一个类,这个类中一共有5个方法,
分别是
process_request,
process_response,
process_view,
process_exception,
process_render_template,
下面说一下它的运算顺序
当一个请求,首先从上往下运行这些类中process_request方法,之后进入django的从上往下执行每个类中的process_view方法,在然后就进入我们自定义的view.py文件,如果你的试图中有错误,那就会从下往上执行中间件中的process_exception方法,然后把错误信息在通过process_response中返回给客户端。
process_request:在这个方法中是没有return方法的,如果有那就会执行process_response方法,直接返回给客户端,一般情况下我们是不会在这里返回内容的,除非你有需求,判断发过来的请求过来的内容,如果不是很友好的请求,那么我们直接就可以在这返回,直接卡死,让这个请求直接都进不了我们的django中的内部程序,
process_response:在这个方法中我们必须要有return方法,这样才能一步一步的返回给客户端,当然你也可以写一些东西在response里,在这里写就是会在所有的response里都会有你所添加的内容!
process_view:这个方法中是没有return方法的,如果有那就走process_response方法;
process_exception:在这个方法中是一定要有return方法的,这个方法是专门返回你的错误信息的,我可以在所有的视图函数只要出现错误就会执行这个方法,可以返回一个错误模版信息!
urls.py
- from django.conf.urls import url
-
- urlpatterns = [
- url(正则表达式, views视图函数,参数,别名)
- ]
-
参数说明
注意事项
1. urlpatterns中的元素按照书写顺序从上往下逐一匹配,一旦匹配成功则不再继续
2. 若要从URL中捕获一个值, 只需要在他周围放置一对括号(分组匹配)
3. 不需要添加一个前导的斜杠, 因为每个URL都有, 例如:应该是^articlrs 而不是^/articles
4.每个正则表达式前面的r是可选的, 但是建议加上.
是否开启URL访问地址后面不为/跳转至带有/的路径配置项 APPEND_SLASH = True
django settings.py配置文件中默认没有APPEND_SALSH这个参数. 但是django默认这个参数为APPEND_SALSH=True. 其作用就是自动在网址结尾加/.
访问 http://www.example.com/blog
时,默认将网址自动转换为 http://www.example/com/blog/
如果在settings.py中设置了 APPEND_SLASH=False,此时我们再请求 http://www.example.com/blog
时就会提示找不到页面
- urlpatterns = [
- url(正则表达式, views视图函数,参数,别名)
- ]
由于第一个参数是正则表达式, 那么就可以给正则的条件加上(),进行分组
- urlpatterns = [
- url(r'^test/(\d+)/',views.test)
- ]
然后就会报错:test() takes 1 positional argument but 2 were given
说我们给了两个参数
views.py
- def test(request,a):
- print(a)
- return HttpResponse('你好啊,大漂亮')
再启动
无名分组>>>>路由匹配时,如果对正则表达式进行分组,那么会传入除了request参数外,还会分组后匹配到的内容
有名分组其实就是对正则表达式分组之后,对分组的内容起了个别名, 同时传入视图函数的时候, 需要特定这个别名的关键字参数来接收
- urlpatterns = [
- url(r'^test/(?P
\d+)/' ,views.test) - ]
形参中必须要有正则表达式分组起了别名的关键字参数
- def test(request, user_id):
- return HttpResponse(f'test url,{user_id}')
无名分组和有名分组不能还在同一个url中混用, 但是可以某种类型重复使用
URLconfs 具有一个钩子,让你传递一个python字典作为额外的参数传递给视图函数.
django.conf.urls.url() 函数可以接收一个可选的第三个参数,他是一个字典, 表示想要传递给视图函数的额外关键字参数
- from django.conf.urls import url
- from . import views
-
- urlpatterns = [
- url(r'^blog/(?P
[0-9]{4})/$' , views.year_archive, {'foo': 'bar'}), - ]
在这个例子中, ,对于/blog/2005/请求,Django 将调用views.year_archive(request, year='2005', foo='bar')
通过name属性来命名, 注意: 多个URL命名是不可重复的
- urlpatterns = [
- url(r'^home/', views.home, name= 'home'),
- ]
那么给URL命名的场景是什么?
在urls.py中给某个路径的后缀起了别名之后, 在模板HTML文件中,就可以直接根据{% url'别名''%}直接拿到别名的路径, 而不是手动拼接路径. 这样做的好处在于. 入股哦有修改ur的时候, 就不需要手动到模板文件中一个个修改了
- urlpatterns = [
- url(r'^home/', views.home, name= 'home_view'),
- url(r'^index/', views.index, name= 'index_view'),
- ]
views.py
- from django.shortcuts import render, HttpResponse, redirect
-
- def home(request):
-
- return render(request, 'home.html')
-
- def index(request):
- return HttpResponse('from index')
home.html
- "en">
- "UTF-8">
-
Title
此时修改urls.py
- urlpatterns = [
- url(r'^home/', views.home, name= 'home_view'),
- url(r'^index666/', views.index, name= 'index_view'),
- ]
会发现反向解析的链接,能够自动解析新的路径!!
方式一:reverse模块
views.py
文件
- # 模块导入
- from django.shortcuts import redirect, reverse
-
-
- def func(request):
- _url = reverse('index_view')
-
- return redirect(f'{_url}')
urls.py
- urlpatterns = [
- url(r'^home/', views.home, name= 'home_view'),
- url(r'^index/', views.index, name= 'index_view'),
- url(r'^func/', views.func, name= 'func_view'),
- ]
结果:
“GET /func/ HTTP/1.1” 302 0
“GET /index/ HTTP/1.1” 200 10
方式二:
views.py
文件
- # 模块导入
- from django.shortcuts import redirect
-
-
- def func(request):
- # 可以直接写别名,也会自动跳转
- return redirect('index_view')
“GET /func/ HTTP/1.1” 302 0
“GET /index/ HTTP/1.1” 200 10
- urlpatterns = [
- url(r'^test/(\d+)/',views.test,name='test_view'),
- ]
-
- def test(request, a):
- res = reverse('index_view')
- print(res)
- return HttpResponse('from test')
-
当url中对正则表达式进行分组之后,视图函数反向解析出/test/之后,需要继续做后缀的匹配,如果不给一个确切的值的话,那么/test/1/、/test/2/、/test/666/都符合匹配规则,所以视图函数还需要一个参数来匹配/test/之后的参数
后端语法:
-
- def test(request,a):
- res = reverse('index_view', args=(666,))
- print(res)
- return HttpResponse('from test')
结果展示为:/test/666/
如果无名分组有多个,那么在args括号内一次传入多个即可
前端模板语法:{% url ‘index_view’ 666 %}
- urlpatterns = [
- url(r'^test/(?P
\d+)/' ,views.test,name='test_view'), - ]
后端语法:
- def test(request, user_id):
- res = reverse('index_view', kwargs={'user_id':666, })
- print(res)
- return HttpResponse('from test')
前端模板语法: {% url 'index_view' user_id=666 %}
当一个项目的应用非常多时,在urls.py文件中urlpatterns列表中的路由会非常多,这样会导致非常不好管理路由,这时考虑将一个urls.py文件拆分开,每一个应用单独新建一个urls,py,通过总的路由文件对每个应用的路由文件进行统筹管理
子路由中的路由配置还是按照之前的方式,但是总路由的配置需要改变
导入模块include
- from django.conf.urls import include, url
-
- urlpatterns = [
- url(r'^admin/', admin.site.urls),
- url(r'^app01/', include('app01.urls')), # 可以包含其他的URLconfs文件
- url(r'^app02/', include('app02.urls')), # 可以包含其他的URLconfs文件
- ]
-
路由匹配时,如果匹配到/app01/会直接到app01.urls.py文件中去继续做路由匹配
Django 项目中有两个应用–app01与app02,分别有其各自的urls.py
如果两个项目都有一个url(r’^index/',views.index,name=‘index_view’), 即多个应用出现路由命名冲突的情况!
此时,对index_view这个别名进行反向解析时,能够解析出是属于app01的,还是app02的呢?
直接说结论:当一个项目中有相同的路由命名,只会识别到最后一个起了这个名字的路由,其他的相同命名的路由,无法被反向解析出来
解决办法:在总路由进行路由分发的时候,给每个应用进行命名空间namesapce=的起别名操作
创建多个应用 并去配置文件中注册
- INSTALLED_APPS = [
- ‘app01’,
- ‘app02’
- ]
总路由:
- from django.conf.urls import include, url
-
- urlpatterns = [
- url(r'^admin/', admin.site.urls),
- url(r'^app01/', include('app01.urls',namespace='app01')),
- url(r'^app02/', include('app02.urls',namespace='app02')),
- ]
各自的app的urls.py
- urlpatterns = [
- url(r'^index/',view.index,name='index_view')
- ]
这样在各自的视图函数进行反向解析的时候会有不同的提示
其实,该问题的解决方法还可以在给路由重命名时,加上应用的前缀app01_index_view这样可以不使用名称空间,同样达到相同的效果