路由系统,进行路径分发.
官方文档:(https://docs.djangoproject.com/en/1.11/topics/http/urls/)
一.基本格式:
1.1版本
urlpatterts = [
url(正则表达式,views视图,参数,别名)
]
1.正则表达式:一个正则表达式字符串
2.views视图:一个可调用对象,通常为一个视图函数
3.参数:可选的要传递给视图函数的默认参数(字典形式)
4.别名:一个可选的name参数
eg:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/([0-9]{4})/$', views.year_archive), #年份
url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), #年月
url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail), #年月日
]
2.0版本
eg:
from django.urls import path,re_path
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:slug>/', views.article_detail),
]
二.正则表达式详解
^ #以什么开头
$ #以什么结尾
[] #里的内容任意一个都可以
{} #个数
? #0个或1个
+ #1个或多个
* #个或多个
. #除了换行符之外的任意字符
\d #数字
\w #字母和数字
注意事项:
1.urlpatterts中的元素.按照书写顺序从上往下逐一匹配正则表达式,一旦匹配成功,则不再继续匹配,需要写的严谨,加上^ $
2.若要从url中捕获一个值,只需要在它周围放置()(正则表达式的机制)
3.路径前不需要加/ eg::应该是^articles 而不是 ^/articles。
4.每个正则表达式前面的’r’是可写可不写,但是建议写上
5.网址结尾’/‘可手动加也可以不写,django会自动补全
原因:
Django中 默认这个参数为 APPEND_SLASH = True。 # 其作用就是当url访问地址后面不加/,时,django自动在网址结尾加’/’,从而不影响网址的正常使用
需要注意的是:Django settings.py配置文件中默认没有 APPEND_SLASH 这个参数.
#当我们访问网址,输入http://www.example.com/blog 时,默认将网址自动转换为 http://www.example/com/blog/
#但是如果在settings.py中设置了 APPEND_SLASH=False,
此时我们请求 http://www.example.com/blog 时就会提示找不到页面。
原因是: APPEND_SLASH=False django就不会补全网址,也就是浏览器不会返回要请求的页面.
eg:
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^blog/$', views.blog),
]
三.分组匹配
1.分组命名正则表达式组的语法:
(?Ppattern) #name是组的名称,pattern是要匹配的模式。 注意P大写
eg:
1.(?P<month>[0-9]{2}) #分组别名为month 0到9任意取2个数字
2.(?P<day>[0-9]{2}) #分组别名为day 0到9任意取2个数字
3.(?P<year>[0-9]{4}) # 分组别名为year 0到9任意取4个数字
4.
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
#以下三个对上面的一个路由做了一个分组命名匹配
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),#年份
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive), #年月
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),#年月日
]
2.无论使用什么样的正则表达式,获取到的参数永远都是字符串
#每个在URLconf中捕获的参数都作为一个普通的Python**字符串**传递给视图,无论正则表达式使用的是什么匹配方式。
eg:
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
# 传递到视图函数中的year_archive() 中的year参数永远是一个**字符串类型**。
3.视图函数中的指定默认值
多个地址,可以匹配同一个视图函数
eg:
# urls.py中
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^blog/$', views.page), #不会额外传参
url(r'^blog/page(?P<num>[0-9]+)/$', views.page),] #会额外传一个关键字参数
#views.py中(可以为num指定默认值)
def page(request, num="1"):
#如果urls中未传参,使用num=1这个默认参数,如果urls传参,则使用urls传过来的参数
pass
在上面的例子中,两个URL模式指向相同的view - views.page -
如果第一个模式匹配上了,page()函数将使用其默认参数num=“1”,
如果第二个模式匹配上,获取url上通过正则表达式获取到的num值,
并且以关键字参数的形式传递给page()的形参num。
4.include
作用:进行一个分类
一般不进行修改settings中的ROOT_URLCINF的值,主要是用include
url与视图的对应关系写在哪里没有关系,重点是django项目的settings中的ROOT_URLCINF的值,
ROOT_URLCINF的值:表示的是从哪一个app项目中去找该django项目的url与视图的对应关系(即urls)
一般放到目录分级的应用中
eg:
from django.conf.urls import url,include
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^blog/', include('blog.urls')),
# 只有用上'blog/'和blog里的urls中的'路径'才可以找到对应的视图函数,才能获取到相应的页面
#可以包含其他的URLconfs文件
四.url的命名和反向解析
4.1.传参方式一:位置传参(定义的时候,使用分组)
步骤:
第一步:定义,给url起一个别名(在urls中)
在url中,最后加上一个name=‘别名’
url(正则表达式,views视图,参数,name=‘别名’)
eg:
from django.conf.urls import url
from . import views
urlpatterns = [
# ...
url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
#位置参数传参
# ...]
4.1.2.第二步:使用,进行反向解析(两种方式:1在模板中,2在视图函数中)
1.解析方式一:在模板中进行反向解析(可以通过一个html页面.跳转到起别名的html页面)
{% url ‘别名’ ‘参数’%} #参数之间以空格分割 参数如果是以arg就是位置传参.但是kwargs就是关键字传参
#获取到的结果是一个完整的路径(取别名的的那个url里的路径),数据类型是字符串
eg:
<a href="{% url 'news-year-archive' '2012' %}">2012 Archive</a>
#参数是反向解析的时候定义,位置传参
<ul>
{% for yearvar in year_list %}
<li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
#参数是反向解析的时候定义 位置传参
{% endfor %}
</ul>
2.解析方式二:在视图函数中进行反向解析
1.引用reverse
from django.urls import reverse
2.使用reverse函数
reverse(‘别名’,args=(参数,)) #注意参数要以元祖的形式,参数是反向解析的时候进行定义, 参数如果是以arg就是位置传参.但是kwargs就是关键字传参
#reverse函数获取到的结果是一个完整的路径(取别名的的那个url里的路径),数据类型是字符串
eg:
from django.urls import reverse
from django.shortcuts import redirect
def redirect_to_year(request):
# ...
year = 2006
# ...
return redirect(reverse('news-year-archive', args=(year,)))
#获取到完整的路径,直接进行跳转:http/127.0.0.1:8000/articles/([0-9]{4})/
#参数是一个元祖,但是参数是反向解析的时候进行定义
4.2.传参方式二:关键字传参(定义的时候,使用了命名分组,命名分组传参可以用位置参数,需要一一对应)
步骤:
4.2.1.第一步:定义,给url起一个别名(在urls中)
在url中,最后加上一个name=‘别名’
url(正则表达式,views视图,参数,name=‘别名’)
eg:
from django.conf.urls import url
from . import views
urlpatterns = [
# ...
url(r'^articles/?P<year>([0-9]{4})/$', views.year_archive, name='news-year-archive'), #命名分组 关键字传参
# ...]
4.2.2.第二步:使用,进行反向解析(两种方式:1在模板中,2在视图函数中)
1.解析方式一:在模板中进行反向解析(可以通过一个html页面.跳转到起别名的html页面)
{% url ‘别名’ ‘参数’%} #参数之间以空格分割 参数如果是以arg就是位置传参.但是kwargs就是关键字传参
eg:
<a href="{% url 'news-year-archive' year='2012' %}">2012 Archive</a>
#参数是反向解析的时候定义,关键字传参
<ul>
{% for yearvar in year_list %}
<li><a href="{% url 'news-year-archive' year=yearvar %}">{{ yearvar }} Archive</a></li>
#参数是反向解析的时候定义 关键字传参
{% endfor %}
</ul>
2.解析方式二:在视图函数中进行反向解析
1.引用reverse
from django.urls import reverse
2.使用reverse函数
reverse(‘别名’,kwargs={key:value}) #注意参数要以元祖的形式,参数是反向解析的时候进行定义, 参数如果是以kwargs就是关键字传参
#reverse函数获取到的结果是一个完整的路径(取别名的的那个url里的路径),数据类型是字符串
eg:
from django.urls import reverse
from django.shortcuts import redirect
def redirect_to_year(request):
# ...
year = 2006
# ...
return redirect(reverse('news-year-archive', kwargs={'year':year}))
#获取到完整的路径,直接进行跳转:http/127.0.0.1:8000/articles/([0-9]{4})/
#参数是一个字典,参数是反向解析的时候进行定义
五…命名空间模式
名称空间指的是将名称空间进行隔离,当有两个重名的url时,后执行的url的内容会覆盖先执行的url的内容
1.定义
定义语法:namespace=‘名称’
urls中
from django.conf.urls import url, include
urlpatterns = [
url(r'^app01/', include('app01.urls', namespace='app01')), #进行命名空间定义
url(r'^app02/', include('app02.urls', namespace='app02')),
app01中的urls.py
from django.conf.urls import url
from app01 import views
app_name = 'app01'
urlpatterns = [
url(r'^(?P<pk>\d+)/$', views.detail, name='detail')
]
app02中的urls.py
from django.conf.urls import url
from app02 import views
app_name = 'app02'
urlpatterns = [
url(r'^(?P<pk>\d+)/$', views.detail, name='detail')
]
现在,我的两个app中 url名称重复了,我反转URL的时候就可以通过命名空间的名称得到我当前的URL。
使用语法:
'命名空间名称:名称'
2.使用
1.方法一:模板中使用:
{% url 'app01:detail' pk=12 %}
{% url 'app02:detail' pk=22 %}
2.方法二:views中的函数中使用
v = reverse('app01:detail', kwargs={'pk':11})
v = reverse('app02:detail', kwargs={'pk':11})
这样即使app中URL的命名相同,我也可以反转得到正确的URL了。
六…删除三合一
步骤:
1.在urls中,定义删除的对应关系
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^show/$', views.show, name='show'),
url(r'^show_books/', views.show_book, name='show_books'),
url(r'^show_authors/', views.show_author, name='show_authors'),
url(r'^show_publisher/', views.show_publisher, name='show_publisher'),
url(r'delete_(publisher|books|authors)/(\d+)/', views.delete, name='delete'),]
#删除三和一的对应关系
2.在展示页面中确定要删除的pk
show_books.html页面中
<td><a href="{% url 'delete' 'books' books_obj.pk %}">删除</a></td>
show_authors.html页面中
<td><a href="{% url 'delete' 'authors' author_obj.pk %}?page=01">删除</a></td>
show_publisher.html页面中
<td><a href="{% url 'delete' 'publisher' publisher_obj.pk %}?page=02">删除</a></td>
3.在views中写上函数逻辑
#参数是从html页面中传来,object代表的是删除的哪一个
def delete(request, object, pk):
#获取到表对象(通过反射 ) object.capitalize()找到对应的表,从而可以获取要删除的对象
object_class = getattr(models, object.capitalize())
#获取要删除的对象,并且删除
object_class.objects.filter(pk=pk).delete()
#重定向,到展示页面
return redirect(reverse('show_{}'.format(object)))