Django 路由层
1. 路由基础概念
- URLconf (URL 配置):Django 的路由系统是基于
urls.py
文件定义的。 - 路径匹配:通过模式匹配 URL,并将请求传递给对应的视图处理函数。
- 命名路由:每个路由可以定义一个名称,用于反向解析。
2. 基本路由配置
示例 urls.py
文件
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name='home'), # 根路径
path('about/', views.about, name='about'), # 静态路径
path('article/<int:id>/', views.article_detail, name='article-detail'), # 动态参数
]
# views.py
from django.http import HttpResponse
def home(request):
return HttpResponse("Welcome to the Home page!")
def about(request):
return HttpResponse("This is the About page.")
def article_detail(request, id):
return HttpResponse(f"Article Detail for Article {id}")
path()
函数:- 第一个参数:URL 模式。
- 第二个参数:对应的视图函数。
- 第三个参数(可选):
name
用于反向解析。
3. 动态路由
动态路由允许在 URL 中传递参数。
示例
urlpatterns = [
path('user/<int:user_id>/', views.user_profile, name='user-profile'), # 整数参数
path('post/<slug:slug>/', views.post_detail, name='post-detail'), # 字符串参数
path('date/<int:year>/<int:month>/', views.archive, name='archive'), # 多参数
]
# views.py
from django.http import HttpResponse
def user_profile(request, user_id):
return HttpResponse(f"User Profile for user {user_id}")
def post_detail(request, slug):
return HttpResponse(f"Post Detail for post {slug}")
def archive(request, year, month):
return HttpResponse(f"Archive for {year}-{month}")
支持的路径转换器:
转换器 | 描述 | 示例 |
---|---|---|
str | 匹配任意非空字符串(默认类型) | 'hello/' |
int | 匹配正整数 | '123/' |
slug | 匹配字母、数字、- 和 _ | 'my-post-slug/' |
uuid | 匹配 UUID 格式 | '550e8400-e29b-...' |
path | 匹配包含 / 的字符串 | 'some/path/' |
4. 子路由与 include
Django 推荐在大型项目中将路由分模块管理。
示例:主路由
from django.urls import path, include
urlpatterns = [
path('blog/', include('blog.urls')), # 引入子路由
path('shop/', include('shop.urls')), # 引入另一个应用的路由
]
示例:子路由(blog/urls.py
)
from django.urls import path
from . import views
urlpatterns = [
path('', views.blog_home, name='blog-home'),
path('<int:post_id>/', views.blog_post, name='blog-post'),
]
# blog/views.py
from django.http import HttpResponse
def blog_home(request):
return HttpResponse("Welcome to the blog home page.")
def blog_post(request, post_id):
return HttpResponse(f"Blog Post with ID {post_id}")
URL /blog/
和 /blog/123/
将分别被子路由处理。
5. 命名空间
在大型项目中,为不同应用的路由定义命名空间,避免路由名称冲突。
主路由配置
from django.urls import path, include
urlpatterns = [
path('blog/', include(('blog.urls', 'blog'), namespace='blog')), # 定义命名空间
]
子路由配置(blog/urls.py
)
from django.urls import path
from . import views
app_name = 'blog' # 命名空间
urlpatterns = [
path('', views.home, name='home'),
path('<int:post_id>/', views.post_detail, name='post-detail'),
]
使用反向解析
from django.urls import reverse
# 使用命名空间解析路由
url = reverse('blog:post-detail', kwargs={'post_id': 1}) # 返回 /blog/1/
6. 正则表达式路由
如果路径匹配需要更复杂的规则,可以使用 re_path
,支持正则表达式。
* 示例: 在2.x以上版本 无名分组 有名分组 可以用 re_path 实现
# urls.py
from django.urls import re_path
from . import views
urlpatterns = [
# 无名分组
re_path(r'^page/(\d+)/$', views.page_view, name='page-view'),
# 有名分组
re_path(r'^page/(?P<page_number>\d+)/$', views.page_view, name='page-view'),
]
路径 /page/123/
会被捕获为 page_number=123
。
# views.py
from django.http import HttpResponse
def page_view(request, page_number):
return HttpResponse(f"Page number: {page_number}")
7. 路由中的默认值
可以为动态路由提供默认值,以减少 URL 的复杂度。
示例
from django.urls import path
from . import views
urlpatterns = [
path('profile/<str:username>/', views.profile, name='profile'),
path('profile/', views.profile, {'username': 'default_user'}, name='default-profile'),
]
请求 /profile/
将自动解析为 username='default_user'
。
# views.py
from django.http import HttpResponse
def profile(request, username='default_user'):
return HttpResponse(f"User profile: {username}")
8. 类视图的路由
在路由中,可以直接绑定类视图。
示例
# urls.py
from django.urls import path
from .views import HomeView, ArticleView
urlpatterns = [
path('', HomeView.as_view(), name='home'),
path('article/<int:pk>/', ArticleView.as_view(), name='article-detail'),
]
类视图必须使用 .as_view()
方法绑定。
# views.py
from django.views import View
from django.http import HttpResponse
class HomeView(View):
def get(self, request):
return HttpResponse("Welcome to the Home page!")
class ArticleView(View):
def get(self, request, pk):
return HttpResponse(f"Article Detail for Article {pk}")
9. 自定义路由转换器
Django 支持自定义路径转换器,用于处理特定格式的路径。
定义自定义转换器
在 converters.py
中:
class FourDigitYearConverter:
regex = r'\d{4}'
def to_python(self, value):
return int(value)
def to_url(self, value):
return f'{value}'
局部注册转换器
在 urls.py
中:
from django.urls import path, register_converter
from .converters import FourDigitYearConverter
register_converter(FourDigitYearConverter, 'yyyy')
urlpatterns = [
path('year/<yyyy:year>/', views.year_archive, name='year-archive'),
]
请求 /year/2024/
将解析为 year=2024
。
* 也可以用继承
导包
from django.urls.converters import StringConverter class FourDigitYearConverter(StringConverter): regex = r'\d{4}' def to_python(self, value): return int(value) def to_url(self, value): return f'{value}'
* 全局注册
from django.urls.converters import StringConverter, DEFAULT_CONVERTERS DEFAULT_CONVERTERS['yyyy'] = FourDigitYearConverter
# views.py
from django.http import HttpResponse
def year_archive(request, year):
return HttpResponse(f"Year Archive for {year}")
10. 静态文件与媒体文件路由
Django 开发模式下可以通过路由处理静态文件和媒体文件。
配置 settings.py
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
STATIC_URL = '/static/'
MEDIA_URL = '/media/'
STATICFILES_DIRS = [BASE_DIR / "static"]
MEDIA_ROOT = BASE_DIR / "media"
配置 urls.py
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
# 其他路由
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
总结
Django 路由是通过 urls.py
文件进行管理的,支持以下特性:
- 静态和动态路由:支持静态路径和动态参数传递。
- 子路由与命名空间:方便模块化管理,避免路由名称冲突。
- 反向解析:通过路由名称动态生成 URL。
- 自定义转换器:处理自定义路径格式。
- 正则表达式路由:支持复杂路径匹配。
路由系统是 Django 项目请求处理的起点,合理设计路由结构能显著提高项目的可维护性
* 11. 前后端反向解析
解析方式 | 方法 | 示例代码 | 解析结果 |
---|---|---|---|
前端解析 | {% url 'route-name' %} | <a href="{% url 'about' %}">About</a> | /about/ |
后端解析 | reverse('route-name') | reverse('about') | /about/ |
动态参数 | reverse /{% url %} | reverse('article-detail', kwargs={'id': 42}) | /article/42/ |
命名空间 | reverse /{% url %} | {% url 'blog:post-detail' post_id=5 %} | /blog/5/ |
延迟解析 | reverse_lazy | reverse_lazy('profile', kwargs={...}) | /profile/... |