Skip to content

Django - URL 映射

当用户从您的 Django 应用请求一个页面时,Django 需要一种方法来确定哪段 Python 代码(哪个视图/view)应该处理该请求。这个过程由 Django 的 URL 调度器 (URL dispatcher) 管理,通过主要在 urls.py 文件中定义的 URL 模式 (URL patterns) 进行配置。

URL 映射的核心是 urlpatterns 列表,它位于您项目的主 urls.py 文件中(例如 myproject/urls.py),也可能位于每个应用的 urls.py 文件中。

Django 处理请求时,会按照顺序检查请求的 URL 路径是否与 urlpatterns 中的每个模式匹配。第一个匹配成功的模式将被使用,Django 会调用关联的视图函数或基于类的视图。

一个典型的项目 urls.py 最初可能看起来像这样:

myproject/urls.py
from django.contrib import admin
from django.urls import path, include # 导入 include
urlpatterns = [
path('admin/', admin.site.urls),
# 在这里添加您的应用的路径
# 示例: path('blog/', include('blog.urls')),
]

Django 提供了两个主要函数用于在 urlpatterns 列表中定义 URL 模式:

  1. path(route, view, kwargs=None, name=None):
  • route:定义 URL 路径模式的字符串。它可以包含尖括号(<>)来捕获 URL 的一部分作为视图的参数。使用简单的路径转换器 (path converters)。
  • view:要调用的视图函数或基于类的视图(.as_view())。
  • kwargs:可选的字典,包含传递给视图的额外关键字参数。
  • name:此 URL 模式的可选名称,用于 URL 反向解析 (URL reversing)(强烈推荐使用)。
  1. re_path(route, view, kwargs=None, name=None):
  • route:一个包含 Python 正则表达式 的字符串,用于匹配 URL 路径。使用命名组 (?P<name>...) 来捕获 URL 的一部分。
  • 其他参数(view、kwargs、name)与 path() 相同。

当 path() 的转换器足够时,通常优先使用 path(),因为它更简单易读。re_path() 使用正则表达式提供了更大的能力和灵活性。

让我们创建一个简单的应用 myapp,其中包含一个视图,并将一个 URL 映射到它。

myapp/views.py
from django.http import HttpResponse
def hello_view(request):
return HttpResponse("Hello from myapp!")
# myapp/urls.py (创建此文件)
from django.urls import path
from . import views # 从当前目录导入 views
urlpatterns = [
path('hello/', views.hello_view, name='hello'), # 将 '/hello/' 映射到 hello_view
]

现在,在主项目的 urls.py 中包含 myapp 的 URL:

myproject/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('myapp/', include('myapp.urls')), # 包含来自 myapp 的 URL
]

通过此设置,对 /myapp/hello/ 的请求将首先匹配项目 urls.py 中的 'myapp/'。然后 Django 会剥离匹配的部分('myapp/'),并将剩余的字符串('hello/')传递给 myapp/urls.py 进行进一步匹配。在 myapp/urls.py 中,'hello/' 匹配模式,并调用 views.hello_view。

如上所示使用 include() 是组织 URL 的标准做法。每个应用在其 urls.py 中管理自己的 URL 命名空间 (URL namespace)。这促进了模块化和可重用性——您只需将其添加到 INSTALLED_APPS 并包含其 URL,就可以将 myapp 应用插入到另一个项目中。

通常,您需要 URL 的某些部分是动态的,例如产品 ID 或用户名。

使用 path() 和转换器 (Converters):

path() 使用尖括号 <converter:variable_name> 中指定的转换器。

  • <str:name>:匹配任何非空字符串(不包括 ’/’)。
  • <int:pk>:匹配零或任何正整数。捕获为 int 类型。
  • <slug:slug>:匹配任何 slug 字符串(ASCII 字母/数字、连字符、下划线)。
  • <uuid:id>:匹配格式化的 UUID。
  • <path:path>:匹配任何非空字符串,包括 ’/‘。用于捕获整个路径非常有用。
myapp/views.py
def view_article(request, article_id):
# article_id 将是一个整数,得益于 <int:> 转换器
text = f"Displaying article Number : {article_id} (Type: {type(article_id).__name__})"
return HttpResponse(text)
def view_articles_by_month(request, year, month):
# year 和 month 将是整数
text = f"Displaying articles for : {month:02d}/{year}"
return HttpResponse(text)
# myapp/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('article/<int:article_id>/', views.view_article, name='article_detail'),
# 示例: /myapp/article/123/
path('articles/<int:year>/<int:month>/', views.view_articles_by_month, name='articles_by_month'),
# 示例: /myapp/articles/2024/05/
]

使用 re_path() 和命名正则表达式组 (Named Regex Groups):

使用标准的 Python 正则表达式和命名组 (?P<variable_name>regex_pattern)。

myapp/views.py
# (视图通常可以保持与上面相同)
# myapp/urls.py
from django.urls import re_path
from . import views
urlpatterns = [
re_path(r'^article/(?P<article_id>\d+)/$', views.view_article, name='article_detail'),
# 示例: /myapp/article/123/
# \d+ 匹配一个或多个数字
re_path(r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', views.view_articles_by_month, name='articles_by_month'),
# 示例: /myapp/articles/2024/05/
# \d{4} 精确匹配 4 个数字,\d{2} 精确匹配 2 个数字
]

从 path() 和 re_path() 捕获的值都作为关键字参数传递给视图函数(匹配尖括号中的变量名或正则表达式组名)。

为您的 URL 模式分配一个 name(例如 name='article_detail')允许您在代码的其他部分(视图、模板、模型)中使用 reverse() 函数或 {% url %} 模板标签明确引用它们。这对于可维护性至关重要,因为您可以更改 urls.py 中实际的 URL 路径结构,而不会破坏其他地方的引用。

进一步阅读: