本文目录导读:
在 Django 中,路由配置主要通过 URLconf(URL Configuration)来实现,核心思想是将 URL 路径映射到对应的视图函数(或类视图)。
以下是 Django 路由配置的完整指南,从基础到进阶。
核心文件:urls.py
每个 Django 项目都有一个主 urls.py(通常在项目同名目录下),每个应用(App)也可以有自己的 urls.py。
基础路由配置(单应用)
假设项目名为 myproject,有一个应用 blog。
步骤 1:在应用的 urls.py 中定义路由
# blog/urls.py
from django.urls import path
from . import views
urlpatterns = [
# 空路径:http://127.0.0.1:8000/blog/
path('', views.index, name='blog-index'),
# 带路径:http://127.0.0.1:8000/blog/article/1/
path('article/<int:article_id>/', views.article_detail, name='article-detail'),
]
步骤 2:在项目主 urls.py 中包含应用路由
# myproject/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
# 将 blog 应用的路由挂载到 /blog/ 下
path('blog/', include('blog.urls')),
]
关键点:
include()函数会将blog/urls.py中的所有路由拼接到/blog/后面。
路由参数传递
Django 支持从 URL 中捕获参数并传递给视图。
常见路径转换器
| 转换器 | 匹配类型 | 示例 URL | 捕获的值 |
|---|---|---|---|
str |
任何非空字符串,但不包含 | hello/world/ |
world |
int |
正整数 | article/42/ |
42 |
slug |
字母、数字、横线、下划线组成的字符串 | article/hello-world/ |
hello-world |
uuid |
UUID 格式 | article/550e8400-e29b-... |
UUID 对象 |
path |
匹配任何字符串,包含 | page/2024/12/25/ |
2024/12/25 |
示例视图:
# blog/views.py
from django.http import HttpResponse
def article_detail(request, article_id):
return HttpResponse(f"文章 ID: {article_id}")
命名路由 & 反向解析
给路由起一个名字(name 参数),然后在模板或视图中通过名字获取 URL,而不是硬编码 URL 字符串。
配置
# blog/urls.py
urlpatterns = [
path('article/<int:article_id>/', views.article_detail, name='article-detail'),
]
在模板中使用
<!-- 使用 name 生成 URL -->
<a href="{% url 'article-detail' article_id=3 %}">查看文章 3</a>
在视图中使用
from django.urls import reverse
from django.http import HttpResponseRedirect
def redirect_to_article(request, article_id):
url = reverse('article-detail', args=[article_id])
return HttpResponseRedirect(url)
命名空间(Namespace)
当项目有多个应用时,不同应用的路由可能同名(比如都有 index),使用命名空间可以避免冲突。
配置方式
在应用 urls.py 中设置 app_name:
# blog/urls.py
app_name = 'blog' # 定义命名空间
urlpatterns = [
path('', views.index, name='index'),
]
在主路由中:
# myproject/urls.py
urlpatterns = [
path('blog/', include('blog.urls')), # 命名空间自动生效
]
使用时:
# 模板
{% url 'blog:index' %}
# 视图
reverse('blog:index')
高级路由技巧
1 使用 re_path() 正则匹配
当 URL 模式较复杂时,可以使用正则表达式。
from django.urls import re_path
urlpatterns = [
# 匹配以 article/ 开头,后面跟数字,再跟 /
re_path(r'^article/(?P<article_id>\d+)/$', views.article_detail),
]
2 使用 path() 的嵌套参数
path('page/<int:year>/<slug:slug>/', views.page_by_year_slug)
3 默认参数
可以在 path() 中给视图传递额外参数。
# urls.py
path('blog/', views.page_list, {'page': 1}, name='blog-list'),
# views.py
def page_list(request, page=1):
# ...
4 使用 reverse_lazy()
在类视图的属性中(如 success_url)需要 URL 反转时,使用 reverse_lazy 避免加载顺序问题。
from django.urls import reverse_lazy
class MyView(CreateView):
success_url = reverse_lazy('blog:index')
常见错误与调试
| 错误信息 | 原因 | 解决办法 |
|---|---|---|
NoReverseMatch |
路由名称不存在或参数不匹配 | 检查 name 和 args/kwargs 是否正确 |
Page not found (404) |
URL 未匹配到任何路由 | 检查 urlpatterns 是否包含该路径,注意斜杠结尾 |
Reverse for '...' not found. '...' is not a valid view function or pattern name. |
命名空间拼写错误或未定义 app_name |
在应用 urls.py 中添加 app_name = 'your_app_name' |
完整工作示例
# myproject/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('home.urls')), # 首页
path('accounts/', include('accounts.urls')), # 用户系统
path('blog/', include('blog.urls')), # 博客系统
]
# blog/urls.py
from django.urls import path
from . import views
app_name = 'blog'
urlpatterns = [
path('', views.post_list, name='post-list'),
path('post/<int:post_id>/', views.post_detail, name='post-detail'),
path('category/<slug:category_slug>/', views.category_list, name='category-list'),
]
# blog/views.py
from django.shortcuts import render, get_object_or_404
from .models import Post
def post_list(request):
posts = Post.objects.all()
return render(request, 'blog/post_list.html', {'posts': posts})
def post_detail(request, post_id):
post = get_object_or_404(Post, pk=post_id)
return render(request, 'blog/post_detail.html', {'post': post})
Django 路由配置的核心步骤:
- 在应用的
urls.py中定义urlpatterns列表,使用path()或re_path()。 - 在应用
urls.py中设置app_name避免冲突。 - 在主
urls.py中使用include()将应用路由挂载到指定前缀。 - 使用路由名称进行反向解析(模板中
{% url %},视图中reverse())。
这样配置后,你的 Django 项目就拥有了清晰、可维护的 URL 结构。