django2

路由控制器

Route路由,是一种映射关系。路由是把客户端请求的url路径和用户请求的应用程序,这里意指django里面的视图进行绑定映射的一种关系。

请求路径和视图函数不是一一对应的关系

在django中所有的路由最终都被保存到一个叫urlpatterns的文件里,并且该文件必须在主应用下的urls.py里进行声明,这是由setting文件决定的

在django运行中,当客户端发送了一个http请求到服务端,服务端的web服务器则会从http协议中提取url地址, 从程序内部找到项目中添加到urlpatterns里面的所有路由信息的url进行遍历匹配。如果相等或者匹配成功,则调用当前url对象的视图方法。

(1)include基本使用

其实在于项目名同名的app文件下的urls.py里有提供一段路由的使用,第三个使用的就是include函数

具体使用方法就是首先要导入这个模块和路由

from django.urls import include, path, re_path

urlpatterns = [
  path('ZJR/',include('ReginaApp.urls'))
]

ReginaApp.urls这个文件是不存在的,所以直接手动创建一个

from django.urls import path, include

from django.shortcuts import HttpResponse
from ReginaApp import views

urlpatterns = [
    path('regina/',views.get_ZJR)
]

这样做的目的就在于我们可以把路由分级,不需要把所有的路由函数都堆在同一个目录下面,当我们再访问127.0.0.1:8090时,此时是报错的,因为总路由里面没有根目录这个东西,如果想访问到get_ZJR这个视图函数,url需要加上ZJR/regina

(2)re_path基本使用

re_path和path的作用是一样的。只不过’re_path’是在写url的时候可以用正则表达式,功能更加强大

写正则表达式都推荐使用原生字符串。也就是以‘r’开头的字符串

在正则表达式中定义变量,需要使用圆括号括起来。这个参数是有名字的,那么需要使用’?P<参数的名字>’。然后在后面添加正则表达式的规则。

Eg:

(一)固定输出

在选择某个月的日历的时候,输入年月会相应的返回当时的文章


#djangoRegina.urls:
path('1999-12',views.article)

# reginaApp.views:
def article(request):
    return HttpResponse("1999-12 文章")

那如果我要挑选的选项很多,path就会有非常多的路由要一一列举,所以这样做就很繁琐。

(二)加入正则

d表示数字,我们将原来的路由改为

re_path("article/\d{4}/\d{2}/",views.article)

但是这样做,多月两位数月份就合理,一位数月份就会报错

所以再把格式修改一下re_path("article/\d{4}/\d{1,2}/",views.article)

(三)匹配参数

上图得知,我需要根据url里得到的年份去匹配文章,所以在路由中就要进行分组

re_path("article/(\d{4})/(\d{1,2})/",views.article)




def article(request,year,month):
    return HttpResponse("{}-{} 文章".format(year,month))

(四)覆盖
re_path("regina/(\d{4})/",views.articleByYear),
re_path("regina/(\d{4})/(\d{1,2})/",views.articleByMonth)

在拥有相同的路由的时候,更短的路由具有更高的优先级

def articleByYear(request,year):
    return HttpResponse("{}文章".format(year))

def articleByMonth(request,year,month):
    return HttpResponse("{}-{}文章".format(year,month))

如果想要区分开路由,则需要添加\(符号`re_path(“regina/(\d{4})/\)“,views.articleByYear),`

(五)有名分组

顾名思义想给我选定的分组起个名字,如果在不起名字的时候,视图函数的参数顺序是必须要固定的,乱序则会影响功能。所以给起个名字

re_path("regina/(?P<year>\d{4})/(?P<month>\d{1,2})/",views.articleByMonth)

def articleByMonth(request,month,year):
    return HttpResponse("{}-{}文章".format(year,month))

(3)路由转发器

首先要在app下导入from django.urls import register_converter

#APP.urls
from django.urls import register_converter

class MobileConvert():
    regex = '1[3-9]\d{9}'
    def to_python(self,value):
        print(type(value))
        # 将匹配结果传递到视图内部时使用
        # 返回str还是int主要看需求,纯数字的可以返回int
        return value
# register_converter(路由转换器的类名,调用别名)
register_converter(MobileConvert,"mobile")


urlpatterns = [
    path('regina/',views.get_ZJR),
    path("<mobile:number>",views.ZJrui) 这里的mobile要和注册时起的名字一致
#APP.views 这里的number要和路由中命名的名字一致
def ZJrui(request,number):
    return HttpResponse("HI,{}用户".format(number))

(4)反向解析

这样做的好处就是可以把每一个正则规则放到子app下面

在使用Django 项目时,一个常见的需求是获得URL 的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。人们强烈希望不要硬编码这些URL(费力、不可扩展且容易产生错误)或者设计一种与URLconf 毫不相关的专门的URL 生成机制,因为这样容易导致一定程度上产生过期的URL。

在需要URL 的地方,对于不同层级,Django 提供不同的工具用于URL 反查:

  • 在模板中:使用url模板标签
  • Python 代码中:使用from django.urls import reverse 函数。

urls.py中为url设置别名参数:

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

urlpatterns = [
    #...
    url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
    #...
]

应用之在模板中反向解析:

<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
<a href="/articles/2012/">2012 Archive</a>

应用之在py文本中反向解析:

from django.shortcuts import redirect
from django.urls import reverse

def redirect_to_year(request):
    year = 2006
    reverse_path=reverse('news-year-archive', args=(year,))
    return redirect(reverse_path)  # 等效 redirect("/articles/2006/")