week11 day4 路由层
一、路由匹配
1.1 路由匹配注意事项
urlpatterns = [
url(r'^admin/', admin.site.urls),
# 首页
yrl(r'^$',views.home)
# 路由匹配
url(r'^test/$',views.test)
url(r'^testadd/$',views.testadd),
# 尾页(了解):后期使用异常捕获处理,这样的尾页让django的第二次在路径中\APPEND_SLASH=True失去了意义,第二次重定向追加斜杠的机制等于失效了
yrl(r'',views.error),
"""
1.url方法的第一个参数是一个正则表达式,只要第一个参数正则表达式能够匹配到内容,那么就会立刻停止向下匹配,而是直接调用匹配到的视图函数
2.不需要添加一个前导的但斜杠,因为每个url都有。例如,应该是^test,而不是^/test
3.每个正则表达式前面的'r'是可选的。r是raw的意思表示后面是原生字符串,不要进行转义。
4.在第一个正则表达式没有匹配到内容的情况下,会在匹配的内容后面加一个/,然后django内部帮你重定向一次重新从头开始匹配
5.每个由正则匹配成功后所获得的参数都作为一个普通的python字符串传递给视图
"""
]
1.2 取消路由匹配第一次匹配不成功,在匹配内容后面加一个斜杠\,重定向重新匹配
在提交了test之后会发现浏览器提交了两次请求,第一次是test,被django框架检测到之后重定向(3xx状态码)了,加上了/后缀。
# 取消自动加斜杠: 到settings.py文件中写入以下内容
APPEND_SLASH = False # 默认是True自动加斜杠
二、分组命名匹配
2.1 无名分组
无名分组就是将匹配到的内容当作位置参数传递给与之绑定的视图函数。
# 无名分组:无需定义名字
路由书写:url('^test/(\d+)',views.test)
内部逻辑:括号内正则表达式匹配到的内容将会当作位置参数传递给与之绑定的视图函数index
视图函数:
def test(request, a):
print(a)
return HttpResponse('from test')
2.2 有名分组
有名分组就是将匹配到的内容当作关键字参数传递给视图层的视图函数。
# 有名分组:需要定义名字
路由书写:url('^testadd/(?P<ID>\d+)', views.testadd)
内部逻辑:括号内正则表达式匹配到的内容将会被当作关键字传给与之绑定的寒素index
视图函数:
def testadd(request, id):
print(id)
return HttpResponse('from testadd')
2.3 无名有名是否可以通用
# 无名有名分组不可混用,但是可以单种多次使用
url(r'^testadd/(\d+)/(.+)/', views.testadd)
url(r'^testadd/(?P<id1>\d+)/(?P<id2>.+)/',views.testadd)
# 多次使用如果是无名分组,视图函数中可以使用*args接收参数
def index(request, *args):
print(args)
return HttpResponse('index')
# 多次使用如果是有名分组,视图函数中可以使用**kwargs接收参数
def index(request, **kwargs):
print(kwargs)
return HttpResponse('index')
三、传递额外的参数给试图函数(了解)
URLconfs 具有一个钩子,让你传递一个Python 字典作为额外的参数传递给视图函数。
django.conf.urls.url()
函数可以接收一个可选的第三个参数,它是一个字典,表示想要传递给视图函数的额外关键字参数。
例如:
Copy
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
]
在这个例子中,对于/blog/2005/请求,Django 将调用views.year_archive(request, year='2005', foo='bar')
。
这个技术在Syndication 框架中使用,来传递元数据和选项给视图。
四、反向解析
反向解析也叫反向URL匹配、反向URL查询或者简单的URL反查。
4.1 什么是反向解析?
反向解析就是通过一些方法得到一个结果,该结果可以直接访问对应的URL触发视图函数。
4.2 反向解析的基本使用
第一步:在urls.py中给路由与视图函数取一个别名(注意:别名不能重复,一定要唯一)
url('^index/', views.index, name='xxx')
第二步:使用反向解析
在模板层使用:
{ % url 'xxx' % }
<a href="{% url 'xxx' %}">111</a>
在视图层使用:
from django.shortcuts import reverse
reverse('xxx')
4.3 无名有名分组反向解析
4.3.1 无名分组反向解析
# 路由层配置无名分组反向解析
url(r'^index/(\d+)/', views.index.name='xxx')
# 模板层使用反向解析
{% url 'xxx' 123 %}
# 视图层使用反向解析
reverse('xxx', args=(1,))
"""
路由层分组匹配机制这个数字不是写死的,
一般情况下放的是数据的主键值,我们可以通过获取到的数据的主键值进而定位到数据对象,
从而可以对数据进行编辑和删除,如下实例:
"""
# 路由层配置无名分组反向解析
url(r'^edit/(\d+)/', views.edit, name='xxx')
# 视图层使用反向解析
def edit(request, edit_id):
reverse('xxx', args=(edit_id,))
# 模板曾使用反向解析
{% for user_obj in user_queryset %}
<a href="{% url 'xxx' user_obj.id %}">编辑</a>
{% end for %}
4.3.2 有名分组反向解析
# 有名分组反向解析
url(r'^func/(?P<year>\d+)/',views.func,name='ooo')
# 模板层使用反向解析
第一种写法:
<a href="{% url 'ooo' year=123 %}">111</a>
第二种写法: 推荐
<a href="{% url 'ooo' 123 %}">222</a>
# 视图层使用反向解析
第一种写法:
print(reverse('ooo',kwargs={'year':123}))
第二种写法:
print(reverse('ooo',args=(111,)))
五、路由分发
"""
django的每一个应用都可以有自己爹templates文件夹,urls.py,以及static文件夹,只有基于上述的这种特点,django才能非常好的做到分组开发,也就是说每个人只写自己手中的app功能就可以了。
因此作为组长,只需要将手下书写的app全部拷贝到一个新的django项目中,然后再配置文件里面注册所有的app再利用路由分发的特点将所有的app整合起来就可以了。
因此,当一个django项目中的url特别多的时候,总路由urls.py代码非常冗余不好维护这个时候也可以利用路由分发来减少总路由的压力。
利用路由分发之后,总路由不再干路由与视图函数的直接对应关系,而是做一个分发处理,进而识别当前url所属的应用,最后直接分发给对应的应用去处理就行了。
"""
总路由:
from django.conf.urls import url
from django.conf.urls import include
from django.contrib import admin
urlpatterns = [
url(r'^admin', admin.site.urls),
# 方式一:
from app01 import urls as app01_urls
from app02 import urls as app02_urls
url(r'^app01', include(app01_urls)), # 只要url前缀是app01开头的,全部交给app01处理
url(r'^app02', include(app02_urls)),
# 方式二:推荐
url(r'^app01', include('app01.urls')),
yrl(r'^app02', include('app02.urls'))
]
# 注意:总路由中不要使用'^app01$'这种格式,否则无法分发给子路由
子路由设置:
# app01中urls.py的配置
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^index/',views.index),
]
# app02中urls.py的配置
from django.conf.urls import url
from app02 import views
urlpatterns = [
url(r'^index/',views.index),
]
参照CSDN地址:
https://blog.csdn.net/weixin_53587094/article/details/114884753?spm=1001.2014.3001.5501
https://blog.csdn.net/weixin_53587094/article/details/114836661?spm=1001.2014.3001.5501
https://blog.csdn.net/weixin_53587094/article/details/114832587?spm=1001.2014.3001.5501
六、名称空间(了解)
为什么需要名称空间?
"""
当多个应用设置了相同的别名,使用反向解析的时候,如果经过路由匹配规则匹配之后的结果一样,
就会出现后面的覆盖前面的,如果你是想触发的是前面的视图函数,那么将访问不到。
正常情况下的反向解析是没有办法自动识别前缀的。
注意!!!这里说的是正常情况下,如果反向解析的别名不同,那么是可以识别的。
"""
总路由中配置的名称空间:
from django.conf.urls import url
from django.conf.urls import include
urlpatterns = [
url('^app01/', include('app01.urls', namespace='app01')),
url('^app02/', include('app02.urls', namespace='app02')),
]
子路由中匹配规则与别名相同:
# app01中urls.py的配置
from django.conf.urls import url
from app01 import views
urlpatterns = [
url('^reg/', views.reg, name='reg'),
]
# app02中urls.py的配置
from django.conf.urls import url
from app02 import views
urlpatterns = [
url('^reg/', views.reg, name='reg'),
]
子路由使用反向解析(可以是无参反向解析,无名分组反向解析,也可以是有名分组反向解析):
# 视图层使用名称空间语法进行反向解析
reverse('app01:reg')
reverse('app02:reg')
# 模板层使用名称空间语法进行反向解析
{% url 'app01:reg' %}
{% url 'app02:reg' %}
补充:其实只要保证名字不冲突,就没有必要使用名称空间。
"""
一般情况下,有多个app的时候我们在其别名的时候会加上app的前缀
这样的话能够确保多个app之间名字不冲突的问题
"""
urlpatterns = [
url(r'^reg/',views.reg, name='app01_reg')
]
urlpatterns = [
yrl(r'^reg/',views.reg, name='app02_reg')
]
七、伪静态(了解)
# 什么是静态网页?
静态网页数据是写死的,万年不变的。
# 什么是伪静态?
伪静态是将一个动态网页伪装成静态网页。
# 为什么要有静态网页呢?
https://www.cnblogs.com/Dominic-Ji/p/9234099.html
静态网页的目的在于增大本网站的seo查询力度,并且增加搜索引擎收藏本网站的概率。
(SEO全称search engine optimization)
其实,搜索引擎本质就是一个巨大的爬虫程序,
总结:无论你怎么优化,怎么处理,最终还是干不过人民币玩家。
路由层使用伪静态:reg.html
urlpatterns = [
url(r'^register.html', views.register),
]
#浏览器的url访问:
http://127.0.0.1:8002/app01/register.html/
八、虚拟环境(了解)
在正常开发环境中,我们会给每一个项目配比一个该项目独有的解释器环境,该环境内只有该项目用的模块,用不到的一概不装。
linux:缺什么才装什么
虚拟环境:
你每创建一个虚拟环境就类似于重新下载了一个纯净的python解释器
但是虚拟环境不要创建太多,是需要消耗硬盘存储空间的。
扩展:
每一个项目都需要用到很多模块,并且每个模块版本可能还不一样
那我还如何安装呢?一个个看着一个个装?
开发当中我们会给每一个项目配备一个requirements.txt文件
里面只要书写了该项目所有的模块及版本
你只需要直接输入一条命令即可一键安装所有模块及版本
九、django版本区别(了解)
9.1 django 1.x 路由层使用url方法,而2.x和3.x版本中路由层使用的是path方法
url()第一个参数支持正则
path()第一个参数是不支持正则的,写什么就匹配什么。
如果你不习惯使用path那么也给你提供了另外一个方法
from django.urls import path,re_path
from django.conf.urls import url
re_path(r'^index/',index),
url(r'^login',login)
提示:2.x和3.x里面的re_path就等价于1.x里面的url
9.2 虽然path不支持正则,但是它的内部支持五种转换器
path('index/<int:id>/',index)
# 将<int:id>中匹配到的内容, 先转成int类型, 再以关键字参数传递给与之绑定的index视图函数
def index(request,id):
print(id,type(id))
return HttpResponse('index')
str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
int,匹配正整数,包含0。
slug,匹配字母、数字以及横杠、下划线组成的字符串。
uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)
9.3 除了有默认的五个转换器之外,还支持自定义转换器(了解)
class MonthConverter:
regex='\d{2}' # 属性名必须为regex
def to_python(self, value):
return int(value)
def to_url(self, value):
return value # 匹配的regex是两个数字,返回的结果也必须是两个数字
from django.urls import path,register_converter
from app01.path_converts import MonthConverter
# 先注册转换器
register_converter(MonthConverter,'mon')
from app01 import views
urlpatterns = [
path('articles/<int:year>/<mon:month>/<slug:other>/', views.article_detail, name='aaa'),
]
9.4 模型层里面1.x外键默认都是级联删除更新的,但是到了2.x和3.x中需要手动配置参数
models.ForeignKey(to='Publish')
models.ForeignKey(on_delete=models.CASCADE, on_update=models.CASCADE)
十、总结
# 路由匹配
1.urls.py中url方法第一个参数是正则
2.django默认帮你开启了第一次匹配不成功,往匹配校验的路径末尾追加一个斜杠/,再进行重定向重新遍历循环匹配一次的操作。
取消重定向的配置:默认settings.py中没有,需要自己添加
APPEND_SLASH = False/True
3.定义首页url匹配规则:url(r'^$',views.home)
4.定义尾页url匹配规则:url(r'',views,error)
提示:尾页一般不使用这种方式,这种方式会让django的默认APPEND_SLASH机制失效
之后我们可以使用异常处理,来作为尾页内容。
# 分组
# 无名分组:无需定义名字
路由书写:url(r'^index/(\d+)',views.index)
内部逻辑:括号内正则表达式匹配到的内容将会当作位置参数传递给与之绑定的视图函数index
视图函数:
def index(request,xxx):
pass
# 有名分组:需要定义名字
路由书写:url(r'^index/?P<id>(\d+)',views.index)
内部逻辑:括号内正则表达式匹配到的内容将会当作位置参数传递给与之绑定的视图函数index
视图函数:
def index(request,id):
pass
#注意事项:
有名分组无名分组不可混用,不过可以单种多次使用。
url(r'^index/(\d+)/(\d+)/(\d+)'.views.index)
url(r'^index/?P<id1>(\d+)/?P<id2>(\d+)',views.index)
# 反向解析
# 什么是反向解析?
反向解析就是通过一些方法得到一个结果,该结果可以直接访问对应的url触发视图函数
# 反向解析的应用
第一步:在urls.py中给与视图函数取一个别名(注意:别名不能重复,一定要唯一)
url(r'^index/',views.index, name='index_page')
第二步:使用反向解析
在模板层使用:
{% url 'index_page' %}
<a href="{% url 'index_page' %}">111</a>
在试图层使用:
from django.shorcuts import reverse
reverse('index_page')
# 无名有名分组的反向解析
# 无名分组反向解析
# 路由层定义
url(r'^index/(\d+)',views.index,name='index')
# 模板层使用:
{% url 'index' 数字%}
# 视图层使用:
from django.shorcuts import reverse
def index(request,xxx):
reverse('index',args=(xxx,))
# 有名分组反向解析
# 路由层定义
url(r'^index/(?P<year>\d+), views.index, name='index')
# 模板层使用:
{% url 'index' year=数字 %}
{% url 'index' 数字 %}
# 视图层使用:
from django.shortcuts import reverse
def index(request, year)
reverse('index', kwagrs=({'year': 数字})
reverse('index', agrs=(数字, )
# 无名有名分组反向解析使用场景
应用:一般用作主键值
模板层应用:通过html页面绑定分组反向解析,等待用户提交时,同时携带用户数据的主键值,
视图层获取到不同的操作反馈过来的动态主键值,models就可以基于这个主键值,来对当前
操作用户的其他数据进行定位。
视图层应用:通过反向解析进行重定向操作
# 注意:
无名有名分组反向解析是针对单个情况的解析,对于反向解析时的参数,只要是满足对于路由的正则匹配规则就行。
# 路由分发
# 应该路由分发的部分:templates、urls.py、models.py
# 路由分发的优势:多应用之间路由不冲突,减轻总路由的压力及维护性的问题,解耦合可以更好的实现分组开发
# 总路由设置:
from django.conf.urls import url,include
urlpatterns = [
url(r'^admin/', admin.site.urls),
# 方式一:
from app01 import urls as app01_urls
from app02 import urls as app02_urls
url(r'^app01',include(app01_urls))
url(r'^app02',include(app02_urls))
# 方式二:推荐
url(r'^app01',include('app01.urls'))
url(r'^app02',include('aoo02.urls'))
]
# 子路由设置:
# app01中urls.py的配置
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^index/', views.index),
]
# app02中urls.py的配置
from django.conf.urls import url
from app02 import views
urlpatterns = [
url(r'^index/', views.index),
]
# 名称空间
# 为什么需要名称空间?
当多个路由中的路由设置了相同的别名,使用反向解析的时候,就会出现后面的覆盖前面的,如果你是想触发前面的视图函数,那么将访问不到
# 总路由中配置名称空间
from django.conf.urls import url
from django.conf.urls import include
urlpatterns = [
url('^app01/', include('app01.urls', namespace='app01')),
url('^app02/', include('app02.urls', namespace='app02')),
]
# 子路由中匹配规则与别名相同
# app01中urls.py的配置
from django.conf.urls import url
from app01 import views
urlpatterns = [
url('^reg/', views.reg, name='reg'),
]
# app02中urls.py的配置
from django.conf.urls import url
from app02 import views
urlpatterns = [
url('^reg/', views.reg, name='reg'),
]
# 子路由使用名称空间语法进行反向解析
# 视图层使用名称空间语法进行反向解析
reverse('app01:reg')
reverse('app02:reg')
# 模板层使用名称空间语法进行反向解析
{% url 'app01:reg' %}
{% url 'app02:reg' %}
# 补充: 其实只要保证名字不冲突 就没有必要使用名称空间
urlpatterns = [
url('^reg/', views.reg, name='app01_reg'),
]
urlpatterns = [
url('^reg/', views.reg, name='app02_reg'),
]
# 伪静态
静态网页:网页数据写死
伪静态:将动态网页伪装成静态网页
作用:提升网站SEO查询力度,增加收藏网页概率 -> 爬虫搜索引擎
路由层使用伪静态:
urlpatterns = [
url(r'^reg.html',views.reg,name='app01_reg'),
]
# 本地虚拟环境(与后面的开发虚拟环境区分开)
# django的区别
1.django1.x版本路由层使用的是url方法,而django2.x和3.x路由层使用的是path方法
1.x版本匹配支持正则
2.x和3.x版本path不支持正则,如果想要支持正则导入re_path。虽然保留了url方法但是不推荐使用了
2.django2.x和3.x版本虽然不支持正则,但是他们内部支持无重转换器
from django.urls import path
path(r'index/<int:id>',views.index)
将<>int:id>中匹配到的内容,先转成int类型,再以关键字参数传递给与之绑定的index视图函数
3.转换器支持自定义
4.模型层中1.x默认级联更新级联删除,而2.x和3.x版本需要手动指定
publish = models.ForeignKey(to='Publish', on_update=models.CASCADE, on_delete=models.CASCADE)
十一、url中的第三个参数{}
def url(regex, view, kwargs=None, name=None)
...
# urls.py
url(r'^third_params/', views.third_params, {'username': 'egon'}, name='third_params'),
# views.py
# def third_params(request, path): # 注意: 关键字形式传参
def third_params(request, username):
return HttpResponse(username) # username返回到前端页面就是egon