Django----路由控制

一、概述

'''
URL是服务器的入口,用户通过浏览器发送过来的任何请求,都是发送到一个指定的url地址,然后被响应
在Django项目中编写路由,就是向外界暴露我们接收哪些url请求,除此之外的任何url都不被处理,也没有返回。通俗的理解,url就是web服务对外暴露的api 
要设计应用程序的url,可以创建一个非正式的称为URLconf的Python模块。此模块是纯Python代码,是URL路径表达式与Python函数之间的映射
'''

、简单的路由配置

from django.conf.urls import url
from django.contrib import admin
from app01 import views      # 导入后端逻辑

urlpatterns = [
    url(正则表达式,views视图函数,参数,别名),
]
  • 正则表达式:一个正则表达式字符串,每个正则表达式前面的r是可选的但是建议加上,它是告诉Python这个字符串是原始的,字符串中的任何字符都不能转义 
  • views视图函数:一个可调用的对象,通常为一个视图函数或一个指定视图函数路径的字符串
  • 参数:可选的要传递给视图的默认参数(字典形式)
  • 别名:一个可选的name参数
  • urlpatterns中的元素是书写顺序从上往下逐一匹配正则表达式,一旦匹配成功则不再继

path  re_path  path的区别:

'''
url格式: url(r'^admin/', admin.site.urls)
    需要到导入url模块: from django.conf.urls import url 
    可用使用正则表达式
    Django1.0中使用
re_path: re_path(r'^publish/([0-9]{4})/([0-9]{2})$',views.publish),
    Django2.0中使用,完全兼容url
需要导入re_path模块: from django.urls import re_path
path:
需要导入path模块: from django.urls import path 不能使用正则表达式,2.0独有
'''

三、django2.0版的path 

from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('server/<int:proj_id>/',views.proj_detail)
]
  •  要捕获一段URL中的值,需要使用尖括号<> ,而不是之前的小括号()
  • 捕获值中可以包含一个转换器类型(converter type),比如使用<int:proj_id>捕获一个整数变量,如果没有转换器,将匹配任意字符
  • 如果使用int转换器类型,而url中实际传入了string字符,将没法匹配到这条路由 直接抛出404  例如 http://127.0.0.1:8000/server/project/
  • 使用path转换器,默认情况下不能使用正则匹配(可以注册自定义转换器),所以要么使用url/re_path 正则匹配,要么使用path 

django默认支持的以下5个转换器

  • str 匹配除了路径分隔符(/)之外的非空字符串,默认就是str
  • init 匹配整数,包含0 
  • slug 匹配字母、数字以及横杠、下划线组成的字符串
  • uuid 匹配格式化的uuid 如 353b3f42-4b83-11e9-8eff-9cb6d0129e8e
  • path 匹配任何非空字符 包含了路径分隔符,不能用?

注册自定义转换器

class FourDigitYearConverter:
    regex = '[0-9]{4}'      # 匹配规则

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

    def to_url(self, value):
        return '%04d' % value
    # 两个def是固定语法

使用 register_converter将其注册到url配置中

from django.contrib import admin
from django.urls import path,register_converter
from app01 import views,converteres

register_converter(converteres.FourDigitYearConverter.,'yyyy')
urlpatterns = [ 
    path('admin/', admin.site.urls),
    path('app/<int:proj_id>/',views.proj_detail),
    path('articles/2003/', views.special_case_2003),
    path('articles/<yyyy:year>/', views.year_archive)
]

四、APPEND_SLASH 

# 是否开启URL访问地址后面不为/ 跳转至带有/ 的路径配置项
APPEND_SLASH = True 

# django setting.py配置文件中没有APPEND_SLASH这个参数,但django默认这个参数为APPEND_SLASH = True,其作用就是自动在url结尾后面加/
# 如果 APPEND_SLASH = False url中如果没有加/ 会报404

五、无名分组

  • 按位置传参
  • 分组后,会把分组出来的数据,当做位置从参数传给视图函数,视图函数必须要定义形参接收,否则报错
  • url示例:re_path(r'^publish/([0-9]{4})/([0-9]{2})$',views.publish),
  • 视图函数示例:def publish(request,*args):

六、有名分组

  • 按关键字传参
  • 分组后,会把分组出来的数据,当关键字参数传给视图函数,所以视图函数需要定义形参,形参名要跟分组的名字对应,与顺序无关
  • url示例: re_path('^app/(?P<proj_id>[0-9]{2})',views.proj_detail),
  • 视图函数示例:  def proj_detail(request,proj_id):
  • 注意:有名分组和无名分组不要混用
  • 分组后捕获的数据默认都是str类型
from django.contrib import admin
from django.urls import path,re_path

urlpatterns = [
    path('admin/', admin.site.urls),
    re_path('^app/(?P<proj_id>[0-9]{2})',views.proj_detail),
]
from django.shortcuts import render,HttpResponse

# Create your views here.


def proj_detail(request,proj_id):
    print(proj_id,type(proj_id))
    return HttpResponse('ok')

 七、反向解析(通俗的理解就是,通过url层中的name反向解析出真正的url地址)

'''
在使用django项目时,一个常见的需求是获得url的最终形式,以用于嵌入到生成的内容中(视图中和限时给用户的url等)或用于处理服务端的导航(重定向等)。
此时这些url尽量不要写死(如果多出调用这个URL,会导致扩展时容易产生错误),或者设计一种与URLconf毫不相关的专门的UR生成机制
因为这样容易导致一定程度上产生过期的URL  

在需要URL的地方,对于不同的层级,django提供不同的工具用于URL反差
    模板层: 使用url模板标签
    视图层: 使用from django.urls import reverse()函数  
'''

1、无参数(未分组)

url('^proj/app/index', views.index, name='app_index') #name就是反向解析的名字
from django.conf.urls import url  # 导入url
from django.urls import path, re_path  # 导入path re_path
from app01 import views

urlpatterns = [
    url('^proj/app/index', views.index, name='app_index'),
    url('^proj/app/edit', views.edit, name='app_edit')
]

 模板层调用:# 实际等于:<a href="/proj/app/edit">新增项目</a>

<a href="{% url 'app_edit' %}">新增项目</a>    

视图层调用:(需要导入reverse模块)

from django.shortcuts import render,reverse,redirect

# Create your views here.

def index(request):
    return render(request,'index.html')


def edit(request):
    url=reverse('app_index')  # 传url中定义的name值
    print(url)
    return redirect(url)

2、无名分组

url层

url('^proj/app/delete/([0-9]{1})',views.app_delete,name='app_delete')

模板层调用,通过位置传参:

<a href="{% url 'app_delete' 1 %}">删除项目</a>      # 参数紧跟name后面

视图函数中调用:

def index(request):
    url=reverse('app_detail',args=(1,))     # 通过args传参
    print(url)
    return redirect(url)

3、有名分组

url层

url('^proj/app/delete/(?P<app_id>[0-9]{1})',views.app_delete,name='app_delete')

模板层调用:

{#<a href="{% url 'app_delete' 1 %}">删除项目</a>#}        # 既可以按位置传参
<a href="{% url 'app_delete' app_id=1 %}">删除项目</a>     # 也可以按关键字传参   注意:此处的关键字就是url中有名分组中定义的

视图层中调用:

from django.shortcuts import render,HttpResponse,reverse,redirect

def index(request):
    # url=reverse('app_detail',kwargs={'app_id':1})     # 既可以按kwargs关键字传参
    url=reverse('app_detail',args=(1,))                 # 也可以按args位置传参
    return redirect(url)

 八、路由分发

当一个django项目里面有多个APP目录时,前期共用的一个url系统,会容易造成混淆,维护非常不方便,于是路由分发就让每个APP拥有自己的单独的url,然后向总的url中注册。

 总路由(不能加结束符$)

from django.conf.urls import url,include

urlpatterns = [
    url(r'^server/', include('server.urls')),      
    url(r'^account/', include('account.urls'))

]

子路由

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

urlpatterns = [
    url(r'^server_add/$',views.server_add),
]

 九、名称空间

名称空间(namespace)是标识符的可见范围。一个标识符可在多个名称空间中定义,它在不同空间中的含义是互不相干的。这样在一个新的名称空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其他名称空间中

由于name没有作用域,django在反向解析url时,会在项目全局顺序搜索,当查到第一个name指定的url时,立即返回

在开发项目时,会经常使用name属性反解出url,当不小心在不同app的urls中定义相同的name时,可能会导致url反解错误,为了避免这种事情发生,引入了名称空间

不同app的urls中定义相同的name时,可能出现反解错误

总urls.py 

from django.conf.urls import url, include

urlpatterns = [
    url(r'^server/', include('server.urls')),
    url(r'^account/', include('account.urls'))

]

account的urls.py

from django.conf.urls import url

from account import views

urlpatterns = [
    url(r'^account_list',views.account_list,name='list'),
    url(r'^account_add/$',views.account_add,name='add'),

]

server的urls.py

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

urlpatterns = [
    url(r'^server_list/$',views.server_list,name='list'),
    url(r'^server_add/$',views.server_add,name='add')

]

account的视图函数

from django.shortcuts import HttpResponse, reverse, redirect


# Create your views here.

def account_list(request):
    return HttpResponse('this is account_list page')


def account_add(request):
    url = reverse('list')
    print(url)
    return redirect(url)

server的视图函数

from django.shortcuts import HttpResponse, reverse, redirect


# Create your views here.

def server_list(request):
    return HttpResponse('this is a server_list page')


def server_add(request):
    url = reverse('list')
    print(url)
    return redirect(url)

这样就会在反解时,出现错误,如下图,访问server和account都跳account的路由

如何解决呢

在总urls.py里指定namespace

from django.conf.urls import url, include

urlpatterns = [
    url(r'^server/', include(('server.urls', 'server'))),
    url(r'^account/', include(('account.urls', 'account')))

]

# django2.0 不支持namespace格式,include中把子路由和namespace用元组包起来

在视图函数反向解析的时候,指定是哪个名称空间下的

def account_add(request):
    url = reverse('account:list')
    print(url)
    return redirect(url)

在模板里:

<a href="{% url 'server:list' %}">服务器列表</a> 

 十、伪静态

'''
  伪静态是相对真实静态来讲的,通常我们为了增强搜索引擎的友好面,都将文章内容生成静态页面,
但是有的朋友为了实时的显示一些信息。或者还想运用动态脚本解决一些问题。
不能用静态的方式来展示网站内容。但是这就损失了对搜索引擎的友好面。
怎么样在两者之间找个中间方法呢,这就产生了伪静态技术。就是展示出来的是以html一类的静态页面形式
'''

urls.py中配置

url(r'^server_edit/(?P<id>[0-9]{1}).html',views.server_edit)

浏览器中访问:必须带html

http://127.0.0.1:8000/server/server_edit/1.html

 十一、根路径响应到指定函数

根路径的url配置必须放到第一行(因为URLconf是自上而下匹配的)

urlpatterns = [
    url(r'^$',views.server_index),    # 根路径响应到指定函数
    url(r'^server_list/$', views.server_list, name='list'),
    url(r'^server_add/$', views.server_add, name='add'),
    url(r'^server_edit/(?P<id>[0-9]{1}).html',views.server_edit),
]

十二、没有配置的路径,响应到指定错误的视图函数

必须写到url配置文件中的最后一行

urlpatterns = [
    url(r'^$',views.server_index),
    url(r'^server_list/$', views.server_list, name='list'),
    url(r'^server_add/$', views.server_add, name='add'),
    url(r'^server_edit/(?P<id>[0-9]{1}).html',views.server_edit),
    url(r'',views.server_error)    # 最后一行
 
]
原文地址:https://www.cnblogs.com/lichunke/p/10566670.html