Django-路由层URLconf

URL配置(URLconf)  本质是URL与要为该URL调用的视图函数之间的映射表

简单的路由配置

from django.urls import path,re_path 

from app01 import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('timer/',views.timer),


    
    # 导入re_path;^以什么开头,$是控制尾意思是不再加什么东西
    re_path(r'^articles/2003/$',views.special_case_2003),
    re_path(r'^articles/([0-9]{4})/$',views.archive_year), # year_archive(request,1999)。django2.1.5不用传第二个参数了
    re_path(r'^articles/([0-9]{4})/([0-9]{2})/$',views.month_archive),
    # re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
  ([0-9]{4})分组(任意四个数字的组合,都可以运行),会以位置参数传给后面的函数,    
]

注意:

  • 若要从URL 中捕获一个值,只需要在它周围放置一对圆括号。

  • 不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles

  • 每个正则表达式前面的'r' 是可选的但是建议加上。它告诉Python 这个字符串是“原始的” —— 字符串中任何字符都不应该转义

有名分组

# urls
    # 有名分组,?P<year>相当于是给参数起了个名字,在视图函数传参数名即可,不需要关注顺序
    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$',views.month_archive),
   '''
   month_archive(request,year=2009,momth=12)  
   这样在views视图,不管传入的参数的顺序是什么,year就是year,month就是month,但是名字必须是year和month
   '''

#views
def month_archive(request, month,year):  # 参数名需正确,顺序怎样都不影响
    return HttpResponse('year:%s,month:%s' % (year,month))

路由分发

URL为更好解耦,应用创建一个新的urls.py文件,存放与自己相关的urls;然后再在公共项目的urls里导入应用的urls

导入include分发函数

#demo urls.py
from
django.contrib import admin from django.urls import path,re_path,include from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('timer/', views.timer), # 路由分发 re_path(r"app01/",include("app01.urls")), # 第一种形式:是加着app01应用 re_path(r"^",include("app01.urls")), # 第二种形式,不用加app01应用即可执行 ]
#app01 urls.py
from
django.urls import path,re_path from app01 import views urlpatterns = [ re_path(r'^articles/2003/$', views.special_case_2003), #^控制头,$控制尾(不再加其他东西) re_path(r'^articles/([0-9]{4})/$', views.year_archive), #([0-9]{4})分组(任意四个数字的组合,都可以运行),会以位置参数传给后面的函数 re_path(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), # re_path(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail), re_path(r'^articles/(?P<y>[0-9]{4})/(?P<m>[0-9]{2})/(?P<d>[0-9]+)/$', views.article_detail), ]

反向解析

方法一:给url起一个别名,后嵌入到html中;每次改变URL名字,嵌入到html中的别名均不需改

#urls
from django.contrib import admin
from django.urls import path

from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('timer/', views.timer),
    path('login/',views.login,name='LOG') #给这个URL起的别名 name='LOG'
]


# view
def login(request):
        if request.method == 'GET':
            return render(request,"login.html")
        else:
            print(request.GET)
            print(request.POST)
            user=request.POST.get("user")
            pwd=request.POST.get("pwd")

            if user=='yuan' and pwd=='123':
                return HttpResponse("OK")
            else:
                return HttpResponse('登录失败')

#html
<form action="{% url 'LOG' %}" method="post">     # 格式 action="{% url 'LOG'%}",到 urls中找一个别名为 LOG的url
    用户名<input type="text" name="user">
    密码<input type="password" name="pwd">
    <input type="submit">
</form>

方法二:利用reverse反向解析函数,通过别名,解析出URL

#app01/urls.py

from django.contrib import admin from django.urls import path,re_path,include from app01 import views urlpatterns = [ #分发的url,在反向解析的时候 会加上app01 re_path(r'^articles/2003/$', views.special_case_2003,name='s_c_2003'), re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive,name='y_a'), re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive), # re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail), ]
#view

def
special_case_2003(request): url=reverse("s_c_2003") #利用reverse反向解析函数,通过别名,解析出URL(在哪个函数中都无所谓);此URL不含正则,固不需参数 url=reverse('y_a',args=(1003,)) # articles/(?P<year>[0-9]{4}) 有正则表达式,需用一个参数,用一个4位数代替 print(url) # 获取的URL /app01/articles/1003/ return HttpResponse("special_case_2003") # HttpResponse里面写的是响应体的内容

名称空间

在项目中可能会在不同应用遇见相同的url别名,会反解错误;为避免反解错误,可以给应用添加不同的名称空间

first_pro/urls.py

from django.contrib import admin
from django.urls import path,re_path,include

from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('timer/', views.timer),
    path('login/',views.login,name='LOG'),
    #分发
    re_path(r"^app01/",include(("app01.urls","app01"))),#这条分发放置在app01这个名称空间里
    re_path(r"^app02/",include(("app02.urls",'app02'))),#名称空间不能重名
]

app01/url.py

from django.urls import path,re_path,include
from app01 import views

urlpatterns = [

    #分发的url,在反向解析的时候 会加上app01
    re_path(r'^articles/2003/$', views.special_case_2003,name='s_c_2003'),
    re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive,name='y_a'),
    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
    # re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
    re_path('index/',views.index,name='index')
]

app01/views

def index(request):
    return HttpResponse(reverse("app01:index")) #加上名称空间app01

---------------app02同样操作---------------

#app02/urls

from django.urls import path,re_path,include
from app02 import views

urlpatterns = [

    re_path("index/",views.index,name='index')
]



#app02/views.py

from django.urls import reverse
def index(request):

    return HttpResponse(reverse("app02:index")) #加上名称空间app02

path方法(django2.0)

re_path有两个问题:

1.不能进行字符转换。

def month_archive(request, month, year):
    print(type(month))  # str
    print(type(year))  # str
    return HttpResponse('year:%s,month:%s' % (year, month))

2.同样的正则表达式,需要写多遍,不易于维护。

urlpatterns = [  
    re_path('articles/(?P<year>[0-9]{4})/', year_archive),  
    re_path('article/(?P<article_id>[a-zA-Z0-9]+)/detail/', detail_view),  
    re_path('articles/(?P<article_id>[a-zA-Z0-9]+)/edit/', edit_view),  
    re_path('articles/(?P<article_id>[a-zA-Z0-9]+)/delete/', delete_view),  
]

path可以解决这两个问题

# urls
from django.urls import path
path('articles/<int:year>',views.path_year)

#views
def path_year(request,year):
    print(type(year))   # int
    return HttpResponse('path year')

基本规则:

  • 使用尖括号(<>)从url中捕获值。

  • 捕获值中可以包含一个转化器类型(converter type),比如使用 <int:name> 捕获一个整数变量。若果没有转化器,将匹配任何字符串,当然也包括了 / 字符。

  • 无需添加前导斜杠。

path转换器

Django默认支持以下5个转化器:

  • str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式

  • int,匹配正整数,包含0。

  • slug,匹配字母、数字以及横杠、下划线组成的字符串。

  • uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。

  • path,匹配任何非空字符串,包含了路径分隔符

自定义path转换器

在实际开发中,django自带的转换器是不能满足我们的需求的,这就需要自定义转换器了

 

对于一些复杂或者复用的需要,可以定义自己的转化器。转化器是一个类或接口,它的要求有三点:

  1. regex 类属性,字符串类型
  2. to_python(self, value) 方法,value是由类属性 regex 所匹配到的字符串,返回具体的Python变量值,以供Django传递到对应的视图函数中。
  3. to_url(self, value) 方法,和 to_python 相反,value是一个具体的Python变量值,返回其字符串,通常用于url反向引用。

操作步骤:

1.在app里创建一个类,写自定义转换的规则

url_convert.py

class MonConvert:
    regex="[0-9]{2}"  # regex

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

    def to_url(self,value): # 用于反向解析
        return '%04d' % value

first_pro/urls  注册自定义URL转换器

from django.contrib import admin
from django.urls import path,re_path,include,register_converter  #register_converter帮你把写好的转换器注册进去
from app01.urlconvert import MonConvert #导入MonConvert;

#注册自定义URL转换器,mm是自定义转化器的名字
register_converter(MonConvert,'mm')

from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('timer/', views.timer),
    path('login/',views.login,name='LOG'),
    path("articles/<mm:month>",views.path_month), # 注意是<mm:month>,路由分发,执行视图函数
]

app01/view.py

def path_month(request,month):
    print(month)
    print(type(month))
    return HttpResponse('path month')



原文地址:https://www.cnblogs.com/hexiaorui123/p/10498825.html