django路由
基本格式
"""
from django.conf.urls import url
urlpatterns = [
url(正则表达式, views视图函数,参数,别名),
]
正则表达式:一个正则表达式字符串
views视图函数:一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
参数:可选的要传递给视图函数的默认参数(字典形式)
别名:一个可选的name参数
"""
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),
]
"""
1.要从URL捕获值,只需在其周围加上括号即可。
2.无需添加斜杠,因为每个URL都有该斜杠。例如^articles,不是^/articles。
3.每个正则表达式字符串前面的“ r”是可选的,但建议使用。 它告诉Python字符串是“原始”字符串–字符串中的任何内容都不应转义。
4.urlpatterns中的元素按照书写顺序从上往下逐一匹配正则表达式,一旦匹配成功则不再继续。
"""
## PS: Django 2.0版本中的路由系统已经替换成下面的写法:
from django.urls import 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),
]
## urls.py
url(r'test',views.test),
url(r'testadd',views.testadd)
"""
上面两个url写法是错误的,当我们本机测试输入127.0.0.1:8000/testadd/匹配到的是第一路由,执行的是views.test视图函数,这是因为路由匹配是通过正则来匹配的,规范的写法如下。
"""
urlpatterns = [
url(r'^admin/', admin.site.urls),
# 首页
url(r'^$',views.home),
# 路由匹配
url(r'^test/$',views.test),
url(r'^testadd/$',views.testadd),
# 尾页(了解)
url(r'',views.error),
]
"""
当你在浏览器输入url(127.0.0.1:8000/login)的时候会默认加斜杠(127.0.0.1:8000/login/)
django内部帮你做了重定向
第一次没匹配到
第二次url后面加斜杠再匹配
"""
# 取消自动加斜杠(settings.py)
APPEND_SLASH = False/True # 默认为True
无名分组
"""
分组:就是给某一段正则表达式用小括号扩起来
"""
## urls.py
urlpatterns = [
url(r'^admin/', admin.site.urls),
# 下述正则表达式会匹配url地址的路径部分为:article/数字/,匹配成功的分组部分会以位置参数的形式传给视图函数,有几个分组就传几个位置参数
url(r'^article/(\d+)/$',views.article),
]
## views.py
def article(request,xx):
print(xx)
return HttpResponse('article')
# 无名分组就是将括号内正则表达式匹配到的内容当作位置参数传递给后面的视图函数
有名分组
"""
可以给正则表达式起一个别名
"""
## urls.py
urlpatterns = [
url(r'^admin/', admin.site.urls),
# 该正则会匹配url地址的路径部分为:article/数字/,匹配成功的分组部分会以关键字参数(article_id=匹配成功的数字)的形式传给视图函数,有几个有名分组就会传几个关键字参数
url(r'^aritcle/(?P<article_id>\d+)/$',views.article),
]
## views.py
def aritcle(request,article_id):
print(year)
return HttpResponse('aritcle')
# 有名分组就是将括号内正则表达式匹配到的内容当作关键字参数传递给后面的视图函数
"""
无名分组和有名分组不可以混合使用,但单独可以多次使用
url(r'^index/(\d+)/(\d+)/(\d+)/',views.index)
url(r'^index/(?P<year>\d+)/(?P<age>\d+)/(?P<month>\d+)/',views.index)
"""
分组匹配指定默认值
# 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"):
pass
"""
在上面的例子中,两个URL模式指向相同的视图函数但是第一个模式并没有从URL中捕获任何东西。
如果第一个模式匹配上了,page()函数将使用其默认参数num=“1”,如果第二个模式匹配,page()将使用正则表达式捕获到的num值。
"""
反向解析
# 通过一些方法得到一个结果 该结果可以直接访问对应的url触发视图函数
## html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<!--强调:login_page必须加引号-->
<form action="{% url 'login_page' %}" method="post">
{% csrf_token %} <!--强调:必须加上这一行,后续我们会详细介绍-->
<p>用户名:<input type="text" name="name"></p>
<p>密码:<input type="password" name="pwd"></p>
<p><input type="submit" value="提交"></p>
</form>
</body>
</html>
## urls.py
## 先给路由与视图函数起一个别名
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/$', views.login,name='login_page'), # 路径login/的别名为login_page
]
## views.py
from django.shortcuts import render
from django.shortcuts import reverse # 用于反向解析
from django.shortcuts import redirect #用于重定向页面
from django.shortcuts import HttpResponse
def login(request):
if request.method == 'GET':
# 当为get请求时,返回login.html页面,页面中的{% url 'login_page' %}会被反向解析成路径:/login/
return render(request, 'login.html')
# 当为post请求时,可以从request.POST中取出请求体的数据
name = request.POST.get('name')
pwd = request.POST.get('pwd')
if name == 'kevin' and pwd == '123':
url = reverse('index_page') # reverse会将别名'index_page'反向解析成路径:/index/
return redirect(url) # 重定向到/index/
else:
return HttpResponse('用户名或密码错误')
无名有名分组反向解析
# 无名分组反向解析
url(r'^index/(\d+)/',views.index,name='xxx')
## 前端
{% url 'xxx' 123 %}
## 后端
reverse('xxx', args=(1,))
"""
这个数字一般情况下放的是数据的主键值
{%for user_obj in user_queryset%}
<a href="{% url 'xxx' user_obj.id %}">编辑</a>
{%endfor%}
url(r'^edit/(\d+)/',views.edit,name='xxx')
def edit(request,edit_id):
reverse('xxx',args=(edit_id,))
"""
# 有名分组反向解析
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开发完,只需要将app全部拷贝到一个新的django项目中 然后在配置文件里面注册所有的app再利用路由分发的特点将所有的app整合起来。
- 当一个django项目中的url特别多的时候 总路由urls.py代码非常冗余不好维护这个时候也可以利用路由分发来减轻总路由的压力。
- 利用路由分发之后 总路由不再干路由与视图函数的直接对应关系而是做一个分发处理(识别当前url是属于哪个应用下的 直接分发给对应的应用去处理)
# 总路由
## 写法一
from django.conf.urls import url, include
from app01 import urls as app01_urls ## 给模块起别名
from app02 import urls as app02_urls
urlpatterns = [
url(r'^admin/', admin.site.urls),
## 路由分发
url(r'^app01/',include(app01_urls)), # 只要url前缀是app01开头 全部交给app01处理
url(r'^app02/',include(app02_urls)) # 只要url前缀是app02开头 全部交给app02处理
]
## 写法二(推荐)
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^app01/',include('app01.urls')),
url(r'^app02/',include('app02.urls'))
]
"""注意事项:总路由里面的url千万不能加$结尾"""
# 子路由
## app01 urls.py(app文件下是没有urls.py的,这是要我们自己去创建)
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^reg/',views.reg)
]
## app02 urls.py
from django.conf.urls import url
from app02 import views
urlpatterns = [
url(r'^reg/',views.reg)
]
名称空间(了解)
当多个应用出现了相同的别名 我们怎么实现反向解析
"""
正常情况下的反向解析是没有办法自动识别前缀的
"""
"""第一种方法定义名称空间"""
# 总路由
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^app01/',include('app01.urls',namespace='app01')),
url(r'^app02/',include('app02.urls',namespace='app02'))
]
## app01 urls.py
urlpatterns = [
url(r'^reg/',views.reg,name='reg')
]
## app02 urls.py
urlpatterns = [
url(r'^reg/',views.reg,name='reg')
]
## app01 views.py
def reg(request):
print(reverse('app01:reg'))
## app02 views.py
def reg(request):
print(reverse('app02:reg'))
## html中使用
{% url 'app01:reg' %}
{% url 'app02:reg' %}
"""第二种方法保证别名不冲突(推荐)"""
"""
一般情况下 有多个app的时候我们在起别名的时候会加上app的前缀
这样的话就能够确保多个app之间名字不冲突的问题
"""
# 总路由
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^app01/',include('app01.urls')),
url(r'^app02/',include('app02.urls'))
]
## app01 urls.py
urlpatterns = [
url(r'^reg/',views.reg,name='app01_reg')
]
## app02 urls.py
urlpatterns = [
url(r'^reg/',views.reg,name='app02_reg')
]
## app01 views.py
def reg(request):
print(reverse('app01_reg'))
## app02 views.py
def reg(request):
print(reverse('app02_reg'))
伪静态(了解)
"""
静态网页:数据是写死的 万年不变
伪静态:将一个动态网页伪装成静态网页
为什么要伪装呢?
1.伪装的目的在于增大本网站的seo查询力度
2.并且增加搜索引擎收藏本网上的概率
"""
urlpatterns = [
url(r'^reg.html',views.reg,name='app02_reg')
]