05 路由层 分组 反向解析 路由分发 名称空间 2.0和1.0差别
django请求的生命周期
一、路由层
(django2.0中路由层使用的是path,不是url,见手撸御姐系列)
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'', views.home), #这样写完蛋了,你输入什么都走这个了,其他接口永远别想走 url(r'^$', views.home), #这样才是主页,127.0.0.1:8000会跳到这里 url(r'test/', views.test), #这样写只要字符串中有test四个字都会跳到这里,如xxxtest,testadd url(r'^test/', views.test), #只要test/开头都会跳到这里,如test/xxxooo url(r'^test/$', views.test), #这样就只能是test/才能访问 url(r'^testadd/', admin.testadd), #testadd也可以访问这里,从上至下匹配不到,系统会自动加上/再来找一次(前提是没有被上面的test半路抢劫)
1. url()方法 第一个参数 其实是一个正则表达式,请求来了会从上往下进行匹配,一旦前面的正则匹配到了内容 就不会再往下继续匹配 而是直接执行对应的视图函数 2. 正是由于上面的特性 当你的项目特别庞大的时候 url的前后顺序也是你需要你考虑,极有可能会出现url错乱的情况,后面的被前面的半路抢劫 3.django在路由的匹配的时候如果浏览器中没有敲最后的斜杠,django会先拿着你没有敲斜杠的结果去从上往下匹配,
如果都没有匹配上,会自动在末尾加斜杠再发一次请求 再匹配一次,匹配上了就调用视图函数,如果还匹配不上才会报错 如果你想取消该机制,不想二次匹配可以在settings配置文件中 指定: APPEND_SLASH = False # 该参数默认是True,通常不这样干,都想省事嘛
二、有名分组和无名分组、反向解析
1.参数传递
1.无名分组 url(r'^test/([0-9]{4})/', views.test) 路由匹配的时候 会将括号内正则表达式匹配到的内容 当做位置参数传递给视图函数,即视图函数除了接收request参数外还要接收一个额外参数,名字随便 例如:test(request,xxx)——> test(request,1234)
2.有名分组 url(r'^test/(?P<year>\d+)/', views.test) #?P<名字> 是给正则\d+起名字叫year 路由匹配的时候 会将括号内正则表达式匹配到的内容 当做关键字参数year=1234传递给视图函数,即视图函数除了接收request参数外还要接收一个额外关键字参数year test(request,year))——> test(request,1234)
3.不能混用
# 无名有名不能混合使用 !!! url(r'^test/(\d+)/(?P<year>\d+)/', views.test), 4.支持多个
虽然不能混用,但是用一种分组下 可以使用多个
# 无名分组支持多个 url(r'^test/(\d+)/(\d+)/', views.test), # 有名分组支持多个 url(r'^test/(?P<year1>\d+)/(?P<year2>\d+)/', views.test),
2. 常规 反向解析
eg:56代码
假设你这个网站还未上线,经理心血来潮临时要求修改url,但是这个路径你已经在后端和前端都用了,而且成千上万个,基于这种情况如何修改?一个一个改?不如删库跑路吧!
其实很简单,我们可以使用反向解析,动态的获取到对应函数的路径
第一步:要给这个路由和视图函数对应关系起一个名字,后面直接用这个名字就可以了,具体做法如下:
url(r'^index/$',views.index,name='kkk')
第二步:根据前后端位置使用不同方法解析:
后端反向解析 后端可以在任意位置通过reverse反向解析出对应的url from django.shortcuts import render,HttpResponse,redirect,reverse reverse('kkk') 前端反向解析<a href="{% url 'kkk' %}">111</a>
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$', views.home), # 书籍展示页面 url(r'^booklist/',views.book_list,name='list'), #name用于反向解析 # 书籍新增 url(r'^add_book/',views.add_book,name='add'), ]
<div class="list-group"> <a href="#" class="list-group-item active"> 首页 </a> <!-- /下面是路由反向解析 ++++++++++++++++++++++++++++++++++++++++++++++++ --> <a href="{% url 'list' %}" class="list-group-item">图书列表</a> <a href="#" class="list-group-item">出版社列表</a> <a href="#" class="list-group-item">作者列表</a> <a href="#" class="list-group-item">其他</a> </div>
3.分组的反向解析
#无名分组
#无名分组反向解析 url(r'^in/dex/(\d+)/$',views.index,name='kkk') 后端: reverse('kkk',args=(1,)) # 后面的数字通常都是数据的id值 前端: <a href="{% url 'kkk' 1 %}">按钮1</a> # 后面的数字通常都是数据的id值
#有名分组(用法同无名分组)
#有名分组反向解析 url(r'^index/(?P<year>\d+)/$',views.index,name='kkk') 后端: reverse('kkk',args=(1,)) # 推荐你使用上面这种 减少你的脑容量消耗 reverse('kkk',kwargs={'year':1}) 前端: <a href="{% url 'kkk' 1 %}">按钮1</a> # 推荐你使用上面这种 减少你的脑容量消耗 <a href="{% url 'kkk' year=1 %}">按钮2</a> 注意:在同一个应用下 别名千万不能重复!!!
#分组反向解析总结(统一格式)
总结:针对有名分组与无名分组的反向解析统一采用一种格式即可
后端
reverse('kkk',args=(10,)) # 这里的数字通常都是数据的主键值
前端
{% url 'kkk' 10 %}
反向解析的本质:本质上就是给url和视图函数对应关系起别名,然后通过别名获取到一个能够访问对应视图函数的具体URL地址
4.反向解析应用
我们想获取前端传过来的数据可以使用反向解析了
路由:
url(r'^edit/(\d+)/',views.edit,name='edit')
前端模板语法: {%for user_obj in user_list%} <a href='edit/{{ user_obj.pk }}/'></a> {% endfor %} 视图函数 from django.shortcuts import reverse def edit(request,edit_id): url = reverse('edit',args=(edit_id,)) 模板 {% url 'edit' edit_id %}
三、路由分发
当你的django项目特别庞大的时候 路由与视图函数对应关系特别特别多
那么你的总路由urls.py代码太过冗长 不易维护
实现多人分组开发 :等多人开发完成之后 我们只需要创建一个空的django项目
然后将多人开发的app全部注册进来 在总路由实现一个路由分发,而不再做路由匹配(来了之后, 我只给你分发到对应的app中)
每一个应用都可以有自己的urls.py,static文件夹,templates文件夹(******)
django每一个app下面都可以有自己的urls.py路由层,templates文件夹,static文件夹。
项目名下的/urls.py(总路由)不再做路由与视图函数的匹配关系,而是做路由的分发
具体做法:
#总urls中路由分发
from django.conf.urls import url,include from app01 import urls as app01_urls #名字重复起别名 from app02 import urls as app02_urls url(r'^app01/',include(app01_urls)) #直接include(app01_urls) 就可以达到分发的效果 url(r'^app02/',include(app02_urls)) #总路由中 一级路由的后面千万不加$符号
#各app中urls
from django.conf.urls import url from app01 import views urlpatterns = [ url(r'^index/',views.index) ]
ps:同样的思想,当你的应用下的视图函数特别特别多的时候 你也可以建一个views文件夹, 里面根据功能的细分再建不同的py文件(******)
四、名称空间
命名空间(英语:Namespace)是表示标识符的可见范围。一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。这样,在一个新的命名空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其它命名空间中。
多个app起了相同的别名 这个时候用反向解析 并不会自动识别应用前缀 如果想避免这种问题的发生,总路由分发时指定名称空间,前、后端解析的时候声明名称空间 方式1: 总路由 url(r'^app01/',include('app01.urls',namespace='app01')) url(r'^app02/',include('app02.urls',namespace='app02')) 后端解析 reverse('app01:index') reverse('app02:index') 前端解析 {% url 'app01:index' %} {% url 'app02:index' %} 方式2: 起别名的时候不要冲突即可 一般情况下在起别名的时候通常建议以应用名作为前缀 name = 'app01_index' name = 'app02_index'
五、伪静态
静态网页:数据是写死的 万年不变
伪静态网页的设计是为了增加百度等搜索引擎seo查询力度
url(r'^index.html',views.index,name='app01_index')
所有的搜索引擎其实都是一个巨大的爬虫程序,发现.html结尾误以为是静态网页,就会优先展示
网站优化相关 通过伪静态确实可以提高你的网站被查询出来的概率,但是再怎么优化也抵不过RMB玩家
六、虚拟环境
平时我们的python中下载了很多模块,创建项目的时候会全部加载,累的一批,那么怎样只让python只保留我们当前项目需要的模块资源呢?慢慢删除不需要的模块?累哭你
可以创建虚拟环境,我们会给每一个项目 配备该项目所需要的模块 不需要的一概不装
虚拟环境 就类似于为每个项目量身定做的解释器环境
如何创建虚拟环境:
每创建一个虚拟环境 就类似于你又下载了一个全新的python解释器(所以虚拟环境不能一直创建,消耗的都是资源啊老哥)
七、django版本区别
1.path差别
django1.X跟django2.X版本区别 路由层1.X用的是url 而2.X用的是path 2.X中的path第一个参数不再是正则表达式,而是写什么就匹配什么 是精准匹配 当你使用2.X不习惯的时候 2.X还有一个叫re_path 2.x中的re_path就是你1.X的url 虽然2.X中path不支持正则表达式 但是它提供了五种默认的转换器 1.0版本的url和2.0版本的re_path分组出来的数据都是字符串类型 默认有五个转换器,感兴趣的自己可以去试一下 str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式 int,匹配正整数,包含0。 slug,匹配字母、数字以及横杠、下划线组成的字符串。 uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。 path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)
from django.urls import path from . import views urlpatterns = [ path('articles/2003/', views.special_case_2003), path('articles/<int:year>/', views.year_archive), path('articles/<int:year>/<int:month>/', views.month_archive), path('articles/<int:year>/<int:month>/<slug>/', views.article_detail), # path才支持,re_path不支持 path('order/<int:year>',views.order), ]
基本规则:
- 使用尖括号(
<>
)从url中捕获值。 - 捕获值中可以包含一个转化器类型(converter type),比如使用
<int:name>
捕获一个整数变量。若果没有转化器,将匹配任何字符串,当然也包括了/
字符。 - 无需添加前导斜杠。
以下是根据 2.0官方文档 而整理的示例分析表:(跟上面url的匹配关系)
2.自定义转换器
对于一些复杂或者复用的需要,可以定义自己的转化器。转化器是一个类或接口,它的要求有三点:
regex
类属性,字符串类型
to_python(self, value)
方法,value是由类属性regex
所匹配到的字符串,返回具体的Python变量值,以供Django传递到对应的视图函数中。to_url(self, value)
方法,和to_python
相反,value是一个具体的Python变量值,返回其字符串,通常用于url反向引用
class FourDigitYearConverter: regex = '[0-9]{4}' def to_python(self, value): return int(value) def to_url(self, value): return '%04d' % value
使用register_converter
将其注册到URL配置中:
from django.urls import register_converter, path from . import converters, views register_converter(converters.FourDigitYearConverter, 'yyyy') urlpatterns = [ path('articles/2003/', views.special_case_2003), path('articles/<yyyy:year>/', views.year_archive), ... ]