django请求生命周期流程图以及django的路由层

Django 请求生命周期流程图

image-20220901163652195

注:

  1. 我们当前用的web服务网关接口是wsgiref,因为其并发量极小。待项目上线时,会切换为uwsgi,它的并发量要大很多。它们都基于WSGI协议。
  2. 各层分别对应的django文件分别是:
    • 路由层:urls.py
    • 视图层:views.py
    • 模版层:templates文件夹
    • 模型层:models.py

路由匹配

在django2.X版本中,路由匹配默认是path(),而django1.X版本是url()两者有所不同。

path('网址后缀',函数名)

一旦网址后缀匹配上了就会自动执行后面的函数,并结束整个路由的匹配

路由结尾的斜杠

当我们在urls.py中写入路由与视图函数关系映射

urlpatterns = [
    path('home/',views.home)
]

在浏览器端输出网址后缀:http://127.0.0.1:8000/home不加尾部的斜杠,也可以匹配到。

因为django做了二次处理:第一次匹配不上,会让浏览器加斜杠再次请求。

image-20220901170631231

并且,我们可以在settings.py配置文件中指定是否自动添加斜杠

APPEND_SLASH=False  # 取消自动添加斜杠,默认为True

path转换器

当网址后缀不固定的时候,可以使用转换器来匹配

'int':IntConverter()  
'path':PathConverter()
'slug':SlugConverter()
'str':StringConverter()
'uuid':UUIDConverter()

语法

path('网址后缀',函数名)

具体使用

先在urls文件添加路径对应关系

urlpatterns = [
    path('home/<int:year>',views.home)
]

在去views.py创建home函数

def home(request):
    return HttpResponse("下午好")
image-20220901172012818

报错显示缺少关键字参数year,需要我们自己将year关键字传进括号

# 修改
def home(request,year):
    print(year)
    return HttpResponse("下午好")

这样就能成功显示页面

image-20220901172423686 image-20220901172326902

也可以在同一个路径下用多个转换器

path('home/<int:year>/<str:name>/',views.home)

这样,在views.py中也需要传入对应的关键字yearname,否则也会报错。它们的类型分别为int,str

re_path正则匹配

一旦网址后缀的正则能够匹配到内容就会自动执行后面的函数,并结束整个路由。

语法

re_path(正则表达式,函数名)

具体使用

# 需要导入re_path
re_path('^home/$',views.home)  

当网址后缀不固定的时候,可以用转换器来匹配

正则匹配值无名分组

语法

re_path('^home/(\d+)/', views.home)

正则表示式匹配到的内容会当做视图函数的位置参数传递会视图函数,原理和path转换器一样,但是不需要像转换器一样固定参数名,无名分组的参数名随意定。

正则匹配之有名分组

语法

re_path('^home/(?P<name>(.*?))',views.home)

基本使用

  1. urls.py中添加home路径
from django.contrib import admin
from django.urls import path,re_path
from app01 import views
urlpatterns = [
    path('admin/', admin.site.urls),
    re_path('^home/(?P<user_id>\d+)/(?P<other>(.*?))$',views.home)
]
  1. views.py中添加对应视图函数,当有多个关键字参数时,可以用**kwargs统一接收,结果会以字典形式
def home(request,**kwargs):
    print(kwargs)
    return HttpResponse("下午好")
  1. 在浏览器输入对应路径

image-20220901180119889

  1. 查看视图函数中kwargs打印结果
image-20220901180233280

django版本区别

  • 在django1.1.11中:只支持正则匹配,并且方法是url()
  • django2.3.4中:支持 path()、re_path()(等价于url())

反向解析

页面上提前写死了很多路由,一旦路由发生变化会导致所有页面相关链接失效。

为了防止出现该问题,我们需要使用反向解析。反向解析就是:返回一个结果,该结果可以访问到对应的路由

路由层对应关系起别名

urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/',views.index),
    path('home/',views.home,name='home_view')
]

使用反向解析语法

  • html页面
<body>
 <a href="{% url 'home_view' %}">点我 </a>
</body>
  • 后端
def index(request):
    print(reverse('home_view'))
    return render(request,'index.html')
image-20220901182356859

总结

  • 反向解析的操作三个方法都一样:path()、re_path()、url()

  • 使用反向解析,可以使前端页面动态获取到路由的路径,并执行视图函数。后端可以通过reverse函数动态获取到反向解析的路径名。

无名有名反向解析

urls.py

urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/',views.index),
    path('home/<str:name>/$',views.home,name='home_view')  # 起别名
]

当路由中不不确定的匹配因数,反向解析的时候需要人为给出一个具体的值

views.py

def index(request):
    return render(request,'home.html')
def home(request,name):
    print(name)
    print(reverse('home_view', args=('jason',)))  # 需要传入具体的值
    return HttpResponse('你好啊')

html页面

<body>
 <a href="{% url 'home_view' 'jason' %}">点我 </a>
</body>

如果路由路径是多个参数,那么需要再args括号内添加对应个数的数据值。

反向解析的操作三个方法都一样:path()、re_path()、url()

路由分发

django中的应用都是可以有自己独立的urls.py、templates文件夹、static文件夹

好处:能够让基于django开发的多个应用完全独立,便于小组开发。充分解耦合,各小组完全不同担心名字冲突。

应用场景:项目中多个应用涉及到反向解析别名冲突时候无法正常解析

具体使用

总路由

path('app01/',include('app01.urls')),
path('app02/',include('app01.urls'))

子路由

# app01
path('test',view.test)

# app02
path('test',view.test)

当项目特别大,应用特别多的时候,可以使用路由分发,非常方便。

名称空间

当路由分发情况下,使用反向解析别名冲突的时候无法解析时,我们有如下解决方案

解决方式1

名称空间:namespace

总路由:

path('app01/',include(('app01.urls','app01'),namespace='app01')),
path('app02/',include(('app02.urls','app02'),namespace='app02'))

子路由:

# app01
path('test/',views.test,name='test_view')

# app02
path('test/',views.test,name='test_view')

视图函数views.py:

# app01
def test(request):
    print(reverse('app01:test_view'))
    return HttpResponse("hello")
  
# app02
def test(request):
    print(reverse('app02:test_view'))
    return HttpResponse("hello world!")
image-20220901200730938

这样就利用名称空间解决了别名冲突问题。

解决方式2

子路由的别名添加app名字前缀

总路由:

path('app01/',include('app01.urls')),
path('app02/',include('app02.urls'))

子路由

# app01
path('test/',views.test,name='app01_test_view')

#app02
path('test/',views.test,name='app02_test_view')

以上两种解决方案都保证了django项目下没有重复的别名。

posted @ 2022-09-01 20:16  荀飞  阅读(70)  评论(0编辑  收藏  举报