Django 路由
以下是用中文详细讲解 Django 路由(URL Routing)的指南,涵盖路由的作用、定义方法、URL 模式、参数传递、命名空间以及最佳实践。我会保持简洁清晰,适合初学者和进阶用户,并提供实用示例,关键代码将包裹在 ““` 标签中以生成 artifact。如果你有特定问题或需要更深入的内容,请随时告知!
什么是 Django 路由?
Django 路由是通过 URL 模式将用户请求映射到对应视图的机制。路由定义在项目的 urls.py
文件和应用的 urls.py
文件中,决定了哪个视图处理特定的 URL 请求。
- 作用:
- 将 URL 路径与视图函数或类视图关联。
- 支持动态 URL(如包含参数的路径)。
- 提供反向解析 URL(通过名称生成 URL)。
- 特点:
- 使用正则表达式或路径转换器定义 URL 模式。
- 支持模块化(应用级路由通过
include()
分发)。 - 内置命名空间,防止 URL 冲突。
1. 路由配置
Django 的路由主要在 urls.py
文件中定义,分为项目级路由(project/urls.py
)和应用级路由(app/urls.py
)。
1.1 项目级路由
项目级 urls.py
是路由的入口,通常将请求分发到应用的 urls.py
。
示例:myproject/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('myapp.urls')), # 分发到应用路由
]
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path(‘admin/’, admin.site.urls),
path(”, include(‘myapp.urls’)), # 分发到应用路由
]
“`python
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path(‘admin/’, admin.site.urls),
path(”, include(‘myapp.urls’)), # 分发到应用路由
]
- **说明**:
- `path('admin/', admin.site.urls)`:映射 Django 管理后台。
- `include('myapp.urls')`:将根路径请求分发到 `myapp` 应用的 `urls.py`。
- `path('', ...)`:空路径表示根 URL(`http://example.com/`)。
#### 1.2 应用级路由
应用级 `urls.py` 定义具体路径与视图的映射。
##### 示例:`myapp/urls.py`
python
from django.urls import path
from . import views
urlpatterns = [
path(”, views.item_list, name=’item_list’), # 商品列表
path(‘items//’, views.item_detail, name=’item_detail’), # 商品详情
path(‘items/create/’, views.item_create, name=’item_create’), # 创建商品
]
- **说明**:
- `path('', views.item_list)`:根路径映射到 `item_list` 视图。
- `path('items/<int:pk>/', views.item_detail)`:动态路径,捕获整数参数 `pk`。
- `name='item_list'`:为 URL 命名,用于反向解析。
---
### 2. URL 模式
Django 使用 `path()` 和 `re_path()` 定义 URL 模式。
#### 2.1 `path()` 语法
- **格式**:`path(route, view, kwargs=None, name=None)`
- `route`:URL 模式字符串。
- `view`:视图函数或类视图的 `as_view()`。
- `kwargs`:传递给视图的额外参数。
- `name`:URL 名称。
- **示例**:
python
path(‘about/’, views.about, name=’about’)
#### 2.2 路径转换器
`path()` 支持内置转换器,捕获动态参数。
- **常用转换器**:
- `str`:匹配非空字符串(默认,不含 `/`)。
- `int`:匹配整数。
- `slug`:匹配字母、数字、下划线或连字符。
- `uuid`:匹配 UUID。
- `path`:匹配任意非空字符串(含 `/`)。
- **示例**:
python
path(‘items//’, views.item_detail, name=’item_detail’) # 捕获整数 pk
path(‘items//’, views.item_by_slug, name=’item_by_slug’) # 捕获 slug
#### 2.3 `re_path()` 语法
- **作用**:使用正则表达式定义复杂 URL 模式。
- **示例**:
python
from django.urls import re_path
re_path(r’^items/(?P\d{4})/(?P\d{2})/$’, views.items_by_date, name=’items_by_date’)
- **说明**:
- `(?P<year>\d{4})`:捕获 4 位数字作为 `year` 参数。
- 适合需要高度定制的 URL 模式。
---
### 3. 参数传递
URL 参数通过路径转换器或正则表达式传递到视图。
#### 示例:视图处理参数
python
from django.shortcuts import render, get_object_or_404
from .models import Item
def item_detail(request, pk):
item = get_object_or_404(Item, pk=pk)
return render(request, ‘myapp/item_detail.html’, {‘item’: item})
def items_by_date(request, year, month):
items = Item.objects.filter(created_at__year=year, created_at__month=month)
return render(request, ‘myapp/item_list.html’, {‘items’: items})
- **说明**:
- `pk`:从 `items/<int:pk>/` 捕获,传递给视图。
- `year` 和 `month`:从正则表达式捕获,过滤数据。
---
### 4. 反向解析 URL
通过 URL 名称生成 URL,避免硬编码路径。
#### 4.1 在视图中使用
使用 `reverse()`:
python
from django.urls import reverse
def item_create(request):
if request.method == ‘POST’:
form = ItemForm(request.POST)
if form.is_valid():
form.save()
return redirect(reverse(‘item_list’)) # 反向解析到 /items/
…
#### 4.2 在模板中使用
使用 `{% url %}`:
html
{{ item.name }}
- **说明**:
- `{% url 'item_detail' pk=item.pk %}`:生成 `/items/1/`(假设 `pk=1`)。
- 提高代码可维护性,URL 改变时无需修改模板或视图。
---
### 5. 命名空间
为应用添加命名空间,防止多个应用间的 URL 名称冲突。
#### 示例:项目 `urls.py`
python
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path(‘admin/’, admin.site.urls),
path(”, include(‘myapp.urls’, namespace=’myapp’)),
]
#### 示例:应用 `urls.py`
python
from django.urls import path
from . import views
app_name = ‘myapp’ # 定义命名空间
urlpatterns = [
path(”, views.item_list, name=’item_list’),
path(‘items//’, views.item_detail, name=’item_detail’),
]
#### 使用命名空间
- 模板:
html
{{ item.name }}
- 视图:
python
redirect(‘myapp:item_list’)
- **说明**:
- `app_name = 'myapp'`:定义应用命名空间。
- `namespace='myapp'`:在 `include()` 中指定。
- 使用 `namespace:name` 格式访问 URL。
---
### 6. 模板和视图(参考)
以下是路由使用的视图和模板。
#### 视图:`myapp/views.py`
python
from django.shortcuts import render, get_object_or_404, redirect
from .models import Item
from .forms import ItemForm
def item_list(request):
items = Item.objects.select_related(‘category’).all()
return render(request, ‘myapp/item_list.html’, {‘items’: items})
def item_detail(request, pk):
item = get_object_or_404(Item, pk=pk)
return render(request, ‘myapp/item_detail.html’, {‘item’: item})
def item_create(request):
if request.method == ‘POST’:
form = ItemForm(request.POST)
if form.is_valid():
form.save()
return redirect(‘myapp:item_list’)
else:
form = ItemForm()
return render(request, ‘myapp/item_form.html’, {‘form’: form})
#### 模板:`myapp/templates/myapp/item_list.html`
html
{% extends ‘base.html’ %}
{% block content %}
商品列表
- {{ item.name }} – ¥{{ item.price }}
- 暂无商品
{% endblock %}
#### 模板:`myapp/templates/myapp/item_detail.html`
html
{% extends ‘base.html’ %}
{% block content %}
{{ item.name }}
价格:¥{{ item.price }}
分类:{{ item.category.name }}
描述:{{ item.description|default:”无描述” }}
返回列表
{% endblock %}
#### 模板:`myapp/templates/myapp/item_form.html`
html
{% extends ‘base.html’ %}
{% block content %}
添加商品
{% csrf_token %} {{ form.as_p }} 保存
取消
{% endblock %}
---
### 7. 最佳实践
1. **模块化路由**:
- 每个应用维护自己的 `urls.py`,通过 `include()` 分发。
- 使用命名空间避免冲突。
2. **清晰命名**:
- URL 名称(`name`)应直观(如 `item_list`、`item_detail`)。
- 路径应简洁,反映资源层级(如 `items/<int:pk>/`)。
3. **反向解析**:
- 始终使用 `{% url %}` 或 `reverse()`,避免硬编码 URL。
- 提高代码可维护性。
4. **安全性**:
- 限制动态参数类型(如使用 `int` 转换器)。
- 处理 404 错误(通过 `get_object_or_404`)。
5. **性能优化**:
- 避免复杂正则表达式,使用 `path()` 优先。
- 合理组织路由,减少匹配开销。
---
### 8. 常见问题
1. **URL 未匹配**:
- 检查 `urls.py` 的路径顺序(从具体到通用)。
- 确保 `include()` 正确指向应用。
2. **参数未传递**:
- 确认视图函数参数与 URL 模式一致。
- 检查转换器类型(如 `int` vs `str`)。
3. **名称冲突**:
- 使用 `app_name` 和 `namespace` 分隔不同应用的 URL。
- 检查 `name` 是否重复。
4. **404 错误**:
- 确认 URL 路径和视图是否存在。
- 检查动态参数是否正确传递。
---
### 9. 运行项目
1. 确保模型迁移:
bash
python manage.py makemigrations
python manage.py migrate
2. 启动服务器:
bash
python manage.py runserver
“`
- 访问:
- 商品列表:
http://127.0.0.1:8000/
- 商品详情:
http://127.0.0.1:8000/items/1/
- 添加商品:
http://127.0.0.1:8000/items/create/
总结
Django 路由通过 path()
和 re_path()
定义 URL 模式,将请求映射到视图,支持动态参数和反向解析。模块化路由(项目级和应用级)、命名空间和转换器提高了代码的灵活性和可维护性。遵循最佳实践(如清晰命名、避免硬编码)可以构建高效的 Web 应用。
如果你需要更复杂的路由示例(如 REST API 路由、动态子域名)、特定功能的深入讲解,或调试路由问题的方法,请告诉我!