Django - 路由配置

  • 作者:lwj
  • 分类:Django
  • 发表日期:2021-09-12 08:52:52
  • 阅读(47)
  • 评论(0)

路由简单的来说就是根据用户请求的URL链接来判断对应的处理程序, 并返回处理结果, 也就是URL与Django的视图建立映射关系,Django的根路由文件在setting.py文件中指定

ROOT_URLCONF = 'demo.urls'

Django1.x版本

url()方法:普通路径和正则路径均可使用,需要自己手动添加正则首位限制符号

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

urlpatterns = [
    # 普通路径  http://127.0.0.1:8888/index
    url(r'^index/$', views.index), 
    # 正则路径  http://127.0.0.1:8888/re_test/1234/
    url(r'^re_test/([0-9]{4})/$', views.re_test), 
]

Django 2.2.x 之后的版本

path()方法:用于普通路径,不需要自己手动添加正则首位限制符号,底层已经添加

re_path()方法:用于正则路径,需要自己手动添加正则首位限制符号

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

urlpatterns = [
    # 普通路径  http://127.0.0.1:8888/index
    path('index/', views.index),
    # 正则路径  http://127.0.0.1:8888/re_test/2021/
    re_path(r'^re_test/([0-9]{4})/$', views.re_test),
]

总结:Django1.1.x 版本中的 url 和 Django 2.2.x 后版本中的 re_path 用法相同


路由末尾的"/"

URL  http://127.0.0.1:8000/blog
在服务器端xxx叫文件, xxx/叫目录(或路径)
当你末尾没加反斜杠的时候,这个URL指向的是/blog,也就是127.0.0.1:8000下的blog文件
这时候浏览器的工作是在127.0.0.1:8000下寻找blog文件,如果没有该文件再查找一个与该文件同名的目录,即blog/(这才能解释为什么会有一个301重定向到http://127.0.0.1:8000/blo/)
当我们末尾加上反斜杠的时候,就省去查找blog文件这一步骤,直接查找blog/目录,就高效多了

提取URL

正则路径无名分组:无名分组按位置传参, views函数中除了request, 其他形参的数量要与urls中的分组数量一致, 一一对应

# In urls.py文件
from django.conf.urls import re_path
from . import views

# re_path(路径, 视图函数名)
urlpatterns = [
    # http://127.0.0.1:8000/re_test_1/shanghai/2019/
    re_path(r'^re_test_1/([a-z]+)/(\d{4})/$', views.re_test_1),
]

# In views.py文件
from django.http import HttpResponse
def re_test_1(request, city, year):  # city ->([a-z]+)提取的参数  year ->(\d{4})提取的参数
    return HttpResponse(f"re_test_1: {city} {year}")

正则路径有名分组:在Python正则表达式中,命名正则表达式组的语法(?P<name>pattern),其中name是组名, pattern是要匹配的模式

# In urls.py文件
from django.conf.urls import re_path
from . import views

# re_path(路径, 视图函数名)
urlpatterns = [
    # http://127.0.0.1:8000/re_test_2/guangzhou/2021/
    re_path(r'^re_test_2/(?P<city>[a-z]+)/(?P<year>\d{4})/$', views.re_test_2),
]

# In views.py文件
from django.http import HttpResponse
def re_test_2(request, city, year): # city ->(?P<city>[a-z]+)提取的参数 year ->(?P<year>\d{4})提取的参数
    return HttpResponse(f"re_test_2: {city} {year}")

嵌套参数: 正则表达式允许嵌套参数, Django 将处理它们并传递给视图; 当转换时, Django将试着填充给所有外部捕捉参数, 忽略任何嵌套捕捉参数

# In urls.py文件
from django.conf.urls import re_path
from . import views

urlpatterns = [
    # http://127.0.0.1:8000/re_test_1/city-shanghai/2019/
    re_path(r'^re_test_1/(city-([a-z]+))/(year-(\d{4}))/$', views.re_test_1),

    # http://127.0.0.1:8000/re_test_2/city-guangzhou/year-2021/
    re_path(r'^re_test_2/(?P<citys>city-(?P<city>[a-z]+))/(?P<years>year-(?P<year>\d{4}))/$',views.re_test_2)
]

# In views.py文件
from django.http import HttpResponse

# city  -> (city-[a-z]+)提取的参数        year ->(\d{4})提取的参数
# citys -> (city-([a-z]+))提取的参数      year ->(year-(\d{4}))提取的参数
def re_test_1(request, citys, city, years, year): 
    return HttpResponse(f"re_test_1: {citys}  {city}  {years}  {year}")


# city  ->(?P<city>[a-z]+)提取的参数                    year  ->(?P<year>\d{4})提取的参数
# citys ->(?P<citys>city-(?P<city>[a-z]+))提取的参数    years ->(?P<years>year-(?P<year>\d{4}))提取的参数
def re_test_2(request, city, citys, year, years): 
    return HttpResponse(f"re_test_2: {city} {citys} {year} {years}")

每个嵌套参数正则匹配每个捕捉到两个参数


路由分发(include)

Django项目里多个app目录共用一个 urls容易造成混淆, 后期维护也不方便, 使用路由分发(include), 让每个app目录都单独拥有自己的urls

1. 在每个app 目录里都创建一个urls.py

2. 在项目名称目录下的 urls 文件里,统一将路径分发给各个 app 目录。

# In urls.py
from django.contrib import admin
from django.urls import path,include # 从 django.urls 引入 include
urlpatterns = [
    path('admin/', admin.site.urls),
    path("users/", include("users.urls")),
    path("blog/", include("blog.urls")),
]

在各自 app 目录下,写自己的 urls.py 文件,进行路径跳转。

users目录:

# In users.urls.py
from django.urls import path, re_path 
from users import views # 从自己的 app 目录引入 views 
urlpatterns = [ 
    re_path(r'^login/(?P<m>[0-9]{2})/$', views.index),
] 

blog目录:

# In blog.urls.py
from django.urls import path, re_path
from blog import views   # 从自己的app目录引入views 
urlpatterns = [ 
    re_path("^xxx/(?P[0-9]{4})/$", views.xxx), 
]

当Django遇到 include()它会将匹配到该点的URLconf的任何部分切掉,并将剩余的字符串发送到包含的URLconf进行进一步处理。

通过使用 path() 实例的列表来包含其他 URL 模式

from django.urls import include, path

from users import views as blog_views
from apps.blog import views as users_views

extra_patterns = [
    path('login/', users_views.login),
    path('logout/', users_views.logout),
    path('user_info/', users_views.user_info),
]

urlpatterns = [
    path('users/', include(extra_patterns)),
    path('blog/', include('blog.urls')),
]

如上例子中,/users/login/URL将被users.views.login()这个Django视图处理

这种方法可以用来去除URLconf 中的冗余,其中某个模式前缀被重复使用

from django.urls import path
from . import views

urlpatterns = [
    path('<page_slug>-<page_id>/login/', views.login),
    path('<page_slug>-<page_id>/logout/', views.logout),
    path('<page_slug>-<page_id>/user_info/', views.user_info),
    path('<page_slug>-<page_id>/history/', views.history),
]

我们可以改进它,通过只声明共同的路径前缀一次并将后面的部分分组:

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

urlpatterns = [
    path(
        '<page_slug>-<page_id>/', 
        include(
            [
                path('login/', views.login),
                path('logout/', views.logout),
                path('user_info/', views.user_info),
                path('history/', views.history),
            ]
        )
    ),
]

捕获的参数

被包含的URLconf 会收到来自父URLconf 捕获的任何参数,所以下面的例子是合法的:

# In settings/urls/main.py
from django.urls import include, path

urlpatterns = [
    path('<username>/blog/', include('foo.urls.blog')),
]

# In foo/urls/blog.py
from django.urls import path
from . import views

urlpatterns = [
    path('', views.blog.index),
    path('archive/', views.blog.archive),
]

在上面的例子中,捕获的 "username" 变量将被如期传递给include()指向的URLconf


URL的反向解析

在 Django 项目中,一个常见需求是获取最终形式的 URL,比如用于嵌入生成的内容中(视图和资源网址,给用户展示网址等)或用户服务器端的导航处理(重定向等)。强烈建议不要硬编码 URL(这是一个费力、不能扩展、容易出错的主意)

# In urls.py
from django.conf.urls import url,include
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # url(路径, include((应用路径,应用名), namespace=路由命名空间)
    url(r'^users/', include(('users.urls', "Users"), namespace="users")),
]


# In users.urls.py
from django.conf.urls import url, re_path
from . import views

# re_path(路径, 视图函数名, name=给路由起的别名)
urlpatterns = [
    # http://127.0.0.1:8000/users/query_test/
    re_path(r'^get_query_params/$', views.query_test, name="query"),
    # http://127.0.0.1:8000/users/redirect_test/
    re_path(r'^redirect_test/$', views.redirect_test),
]


# In users.views.py
def query_test(request):
    return HttpResponse(f"query_test")

# 重定向
def redirect_test(request):
    # 通过应用的命名空间+函数别名反向解析重定向到query_test视图
    print("reverse:  ",  reverse("users:query"))
    return redirect("users:query")

如上代码,访问http://127.0.0.1:8000/users/redirect_test/将重定向到http://127.0.0.1:8000/users/query_test/

觉得不错,支持一下!

提交评论

您尚未登录,登录之后方可评论~ 登录 or 注册

评论列表

暂无评论
返回顶部

建议反馈

1. 可在博文底部留言评论

2. 发邮件到i_suichuan@163.com