当用户从Django支持的站点请求页面时,这是由路由层确定要执行的Python代码:
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^hello/$',views.hello),
url(r'^helloword/$',views.helloword),
]
注意:第一个参数是正则表达式,匹配规则按照从上往下一次匹配,匹配到一个之后立即匹配,直接执行对应的视图函数
网站首页路由
url(r'^$',views.home)
网站不存在页面
url(r'',views.error)
url()函数有四个参数, 两个是必须的: regex 和 view , 两个可选的: kwargs 和 name
regex 是 regular expression 的简写,这是字符串中的模式匹配的一种语法,Django 将请求的URL从上至下依次匹配列表中的正则表达式,直到匹配到一个为止。
view 当 Django匹配了一个正则表达式就会调用指定的view逻辑, 上面代码中会调用app01/views.py中的hello函数。
kwargs任意关键字参数可传一个字典至目标view。
name命名你的 URL, 使 url 在 Django 的其他地方使用, 特别是在模板中。
一个路由匹配示例:
from django.conf.urls import url
from app01 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),
]
示例请求:
将加括号的正则表达式匹配到的内容当做位置参数自动传递给对应的视图函数.
url(r'^hello/(\d+)/',views.hello), # 匹配一个或多个数字
def hello(request,xxx):
print(xxx)
return HttpResponse('hello!')
将加括号的正则表达式匹配到的内容当做关键字参数自动传递给对应的视图函数.
url(r'^hello/(?P\d+)/' ,views.hello), # 匹配一个或多个数字
def hello(request,year):
print(year)
return HttpResponse('hello!')
注意:无名分组和有名分组不能混着用,但是支持用一类型多个形式匹配!!!
不支持
url(r'^test/(\d+)/(?P\d+)/' ,views.test) # 会报错
无名分组多个
url(r'^test/(\d+)/(\d+)/',views.test),
有名分组多个
url(r'^test/(?P\d+)/(?P\d+)/' ,views.test),
如果把网址写死网址,会使得在改了网址(正则)后,模板(template),视图(views.py,比如用于URL跳转),模型(models.py,获取记录访问地址等)用了此网址的,都必须进行相应的更改,修改的代价很大,一不小心,有的地方没改过来,就不能用了。所以需要根据名字动态获取到对应路径,这就是所谓的URL反向解析,反向URL匹配,反向URL查找或简单的URL反转。
Django提供了用于执行URL反转的工具,这些工具匹配需要URL的不同层:
from django.shortcuts import reverse
url(r'^index666/$',views.index,name='index')
前端使用
{% url 'index' %}
{% url '你给路由与视图函数对应关系起的别名' %}
后端使用
reverse('index')
reverse('你给路由与视图函数对应关系起的别名')
reverse 接收 url 中的 name 作为第一个参数,我们在代码中就可以通过 reverse() 来获取对应的网址(这个网址可以用来跳转,也可以用来计算相关页面的地址),只要对应的 url 的name不改,就不用改代码中的网址。
无名分组反向解析
url(r'^test/(\d+)/',views.test,name='list')
前端使用
{% url 'list' 10 %}
后端使用
reverse('list',args=(10,))
示例:
user_list = models.User.objects.all()
url(r'^edit/(\d+)/',views.edit,name='edit')
前端模板语法
{%for user_obj in user_list%}
<a href='{% url 'edit' edit_id %}'></a>
{% endfor %}
视图函数
from django.shortcuts import reverse
def edit(request,edit_id):
url = reverse('edit',args=(edit_id,))
有名分组反向解析
前端使用
# 前端有名分组和无名分组都可以用这种形式
{% url 'list' 10 %}
# 下面这个了解即可
{% url 'list' year=10 %}
后端使用
# 后端有名分组和无名分组都可以用这种形式
print(reverse('list',args=(10,)))
# 下面这个了解即可
print(reverse('list',kwargs={'year':10}))
总结:针对有名分组与无名分组的反向解析统一采用一种格式即可
后端
reverse('list',args=(10,)) # 这里的数字通常都是数据的主键值
前端
{% url 'list' 10 %}
反向解析的本质:就是获取到一个能够访问名字所对应的视图函数
Django每一个app下面都可以有自己的urls.py路由层,templates文件夹,static文件夹。项目名下 urls.py(总路由)不再做路由与视图函数的匹配关系而是做路由的分发。
from django.conf.urls import include
# 路由分发:注意路由分发总路由千万不要$结尾
url(r'^app01/',include(app01_urls)),
url(r'^app02/',include(app02_urls))
# 在应用下新建urls.py文件,在该文件内写路由与视图函数的对应关系即可
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^index/',views.index)
]
URL命名空间可以保证反查到唯一的URL,即使不同的app使用相同的URL名称。它还允许你在一个应用有多个实例部署的情况下反查URL。 换句话讲,因为一个应用的多个实例共享相同的命名URL,命名空间提供了一种区分这些命名URL 的方法。
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
urlpatterns = [
url(r'^index/',views.index,name='index')
]
app02.urls.py:
from django.conf.urls import url
from app02 import views
urlpatterns = [
url(r'^index/',views.index,name='index')
]
app01.views.py:
reverse('app01:index')
app02.views.py:
reverse('app02:index')
django1.0与django2.0之间的区别:
django2.0里面的path第一个参数不支持正则,你写什么就匹配,100%精准匹配
django2.0里面的re_path对应着django1.0里面的url
虽然django2.0里面的path不支持正则表达式,但是它提供五个默认的转换器
str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
int,匹配正整数,包含0。
slug,匹配字母、数字以及横杠、下划线组成的字符串。
uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)
自定义转换器
1.正则表达式
2.类
3.注册
自定义转换器
class FourDigitYearConverter:
regex = '[0-9]{4}'
def to_python(self, value):
return int(value)
def to_url(self, value):
return '%04d' % value # 占四位,不够用0填满,超了则就按超了的位数来!
register_converter(FourDigitYearConverter, 'yyyy')
PS:路由匹配到的数据默认都是字符串形式