URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表。

你就是以这种方式告诉Django,对于这个URL调用这段代码,对于那个URL调用那段代码。

一、路由匹配

'''
路由匹配规则:

1. URLconf 不检查请求的方法。换句话讲,所有的请求方法 —— 同一个URL的POST、GET、HEAD等等 —— 都将路由到相同的函数。

2. 每个在URLconf中捕获的参数都作为一个普通的Python字符串传递给视图,无论正则表达式使用的是什么匹配方式。

3. 视图函数可以指定参数默认值,当该参数从URL中获取到值,则使用该值,否则使用默认值

4. django.conf.urls.url() 函数可以接收一个可选的第三个参数,它是一个字典,表示想要传递给视图函数的额外关键字参数。

1、路由匹配:django1.1

from django.conf.urls import url

urlpatterns = [
     url(正则表达式, views视图函数,kwargs=None,name=None),
]

'''
参数介绍:
    1. 正则表达式:一个正则表达式字符串
    2. views视图函数:一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
    3. kwargs:可选的要传递给视图函数的默认参数(字典形式)
    	kwargs={k:v, ...}
    4. name:一个可选的name参数
'''

2、路由匹配:django2.x

from django.urls import re_path

urlpatterns = [
    re_path(regex, view, kwargs=None, name=None),
    ...
]

'''
re_path参数介绍:
	1. regex:正则表达式,用于匹配URL地址的路径部分,无需考虑请求方式
		在django种对于相同的URL,任何请求方式:POST、GET、HEAD等,都会被路由到相同功能的view上
		url地址:https://www.baidu.com/myapp/
		url地址:https://www.baidu.com/myapp/?name=zzw
			对于以上url,正则表达式匹配的部分是 myapp/
			切记,正则表达式开头无需加/
		
	2. view::通常为一个视图函数,用来处理业务逻辑
	3. kwargs:额外传递给视图函数的参数,可选。
		kwargs={k:v, ...}
	4. name:为正则表达式匹配到的url地址起别名,可选。
'''

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),
]
----------------------------------------------------
'''
django1.X路由层使用的是url方法

而在django2.X和3.X版本中路由层使用的是path方法
	url()第一个参数支持正则
	path()第一个参数是不支持正则的,写什么就匹配什么
	
	
如果你习惯使用正则匹配,那么在django2.x、3.x也给你提供了另外一个方法
	from django.urls import path, re_path
	re_path(r'^index/',index),
		
2.X和3.X里面的re_path就等价于1.X里面的url
		
也可以重新将django1.x中的url方法,但是不建议!	
	from django.conf.urls import url
	url(r'^login/',login)
'''

2.1 转换器

虽然path不支持正则 但是它的内部支持五种转换器

path('index/<int:id>/',index)

# 将第二个路由里面的内容先转成整型然后以关键字的形式传递给后面的视图函数
	def index(request,id):
        print(id,type(id))
        return HttpResponse('index')
    
'''
五种转换器:
	str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
	int,匹配正整数,包含0。
	slug,匹配字母、数字以及横杠、下划线组成的字符串。
	uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
	path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)
'''

2.2 自定义转换器

除了有默认的五个转换器之外,django2.x还支持自定义转换器(了解)

# 在app应用中创建path_converts.py文件,写入以下代码
class MonthConverter:
    	regex='\d{2}' # 属性名必须为regex

    	def to_python(self, value):
        	return int(value)

    	def to_url(self, value):
        	return value # 匹配的regex是两个数字,返回的结果也必须是两个数字
	
在urls.py文件中使用register_converter将其注册到URL配置中:
	#导入转换器
	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'),

]

3、正则表达式详细

from django.conf.urls import url

from app目录名 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. urlpatterns中的元素按照书写顺序从上往下逐一匹配正则表达式,一旦匹配成功则不再继续。
    2. 若要从URL中捕获一个值,只需要在它周围放置一对圆括号(分组匹配)。
    3. 不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
    4. 每个正则表达式前面的'r' 是可选的但是建议加上。
'''

3.1 URL末尾反斜杠

'''
在使用django框架时,在浏览器输入url时,会默认在url末尾加上/ 再次发起一次请求,这个是django附带的一次请求,为的是让路由匹配时,如果原生路由无法匹配,那么会再次使用带有/末尾的路由匹配一次,从而能够匹配到末尾带有 '/'的路由

Django settings.py配置文件中默认没有 APPEND_SLASH 这个参数,但 Django 默认这个参数为 APPEND_SLASH = True。 其作用就是自动在网址结尾加'/'。
	我们在浏览器输入:http://127.0.0.1:8001/index,Django会拿着路径部分index去路由表中自上而下匹配正则表达式,并不会匹配成功任何正则表达式( r'^index/$'匹配的是必须以 / 结尾,所以不会匹配成功index)
	那么django会在路径后加/(即index/)再去路由表中匹配,如果匹配失败,则会返回路径未找到,如果匹配成功,则会返回重定向信息给浏览器,要求浏览器重新向 http://127.0.0.1:8001/index/ 地址发起请求

取消django自动加 / 功能(在settings.py文件中添加)
	APPEND_SLASH = False (默认为True)
'''

3.2 分组命名匹配

无名、有名不可混合使用

'''
分组:将正则表达式使用括号括起来,这就是一个分组
'''

'''
无名、有名不可混合使用

但是同一类型的分组,可以在正则中出现N多次,但是使用N个分组,就需要在视图函数增加对应的形参,当然可以使用(*args,**kwargs)
a. 无名分组

无名分组就是将括号内正则表达式匹配到的内容作为位置参数传递给后面的视图函数

url('正则1(正则2)',视图函数)

'''
正则2:正则2匹配的路由传递给视图函数作为 *args参数
'''
b. 有名分组

有名分组就是将括号内正则表达式匹配到的内容当作关键字参数传递给后面的视图函数

'''
可以给正则表达式起一个别名
r'xxx(?P<year>\d+)'	year 就是 \d+ 正则表达式的别名

在url('正则1(?P<别名>正则2)',视图函数)

有名分组就是将括号内正则表达式匹配到的内容当作关键字参数传递给后面的视图函数
	关键字就是别名
'''

捕获的值作为关键字参数而不是位置参数传递给视图函数,如下:
'''
views.py文件:

from django.shortcuts import HttpResponse

def login(request, year):
    print(year)
    return HttpResponse('hehe')
----------------------------------------------------
urls.py文件:

from django.conf.urls import url
from app01 import views

urlpatterns = [
    url(r'^login/(?P<year>\d+)/', views.login)
]
'''

4、反向解析

通过一些方法得到一个结果,该结果可以直接访问对应的url,触发视图函数

'''
先给路由与视图函数起一个别名
	url(r'^func_kkk/',views.func,name='ooo')
	
反向解析
	后端反向解析
        from django.shortcuts import reverse
        reverse('ooo')
        
    前端反向解析
  		<a href="{% url 'ooo' %}">111</a>

效果:
    当我们点击到了前端包含反向解析的<a>标签,就会自动触发其中的URL,从而实现该URL对应的视图函数
'''

a. 无名分组反向解析

# 无名分组反向解析
	url(r'^index/(\d+)/',views.index, name='别名')
    
# 后端
	print(reverse('别名', args=(1,)))
    # loaclhost/index/1
'''
别名:就是url中 name字段创建的别名

args:
	传递给无名分组的值,必须为元组类型。
	为补全URL,且需要被无名分组正则匹配

返回结果:
	loaclhost/index/1
'''
----------------------------------------------
# 无名分组反向解析
	url(r'^index/(\d+)/',views.index, name='别名')

# 前端
	<a href="{% url '别名' 默认值 %}">XXX</a>

'''
别名:就是url中 name字段创建的别名

默认值:
	传递给无名分组的值
	
返回值:
	当我们点击前端页面的<a>标签时,会自动执行href中URL对应的视图函数
'''

b. 有名分组反向解析

# 有名分组反向解析
   url(r'^func/(?P<year>\d+)/',views.func,name='别名')
    
# 前端
	<a href="{% url '别名' year=123 %}">111</a>  了解
	<a href="{% url '别名' 123 %}">222</a>  		记忆

'''
别名:就是url中 name字段创建的别名

year:给URL有名分组year传递默认值
123:给URL有名分组year传递默认值123
'''
----------------------------------------------
# 有名分组反向解析
   url(r'^func/(?P<year>\d+)/',views.func,name='别名')
    
# 后端	
	# 有名分组反向解析 写法1  了解
   print(reverse('别名',kwargs={'year':123}))

   # 简便的写法  减少你的脑容量消耗 记跟无名一样的操作即可
   print(reverse('别名',args=(111,)))

'''
别名:就是url中 name字段创建的别名

year:给URL有名分组year传递默认值
123:给URL有名分组year传递默认值123
'''