Djangoroutingsystemoverview
Django routingsystem用于将URLpathmap to 相应 视graphfunction or class视graph. It supports many 种routing模式, including静态routing, 动态routing, 嵌套routingetc..
Djangoroutingsystem corecomponent:
- URLconf: URLconfigurationmodule, 定义URLpath and 视graph maprelationships.
- Path converters: path转换器, 用于将URLpathin parameter转换 for Pythonobject.
- View: 视graphfunction or class视graph, processingHTTPrequest并返回HTTPresponse.
- Reverse URL resolution: 反向URL解析, through视graph名称生成URLpath.
提示
Django 2.0及以 on version推荐usingpath()function定义routing, 它providing了更简洁 语法 and 更 good readable 性. for 于需要正则表达式 complex routing, 可以usingre_path()function.
嵌套routing
嵌套routing is 指 in application URLconfigurationinpackage含otherapplication URLconfiguration, implementationrouting module化management.
basic嵌套routing
# mysite/urls.py
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
# package含blogapplication URLconfiguration
path('blog/', include('blog.urls')),
# package含shopapplication URLconfiguration
path('shop/', include('shop.urls')),
]
然 after in application urls.pyin定义具体 routing:
# blog/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.post_list, name='post_list'),
path('post//', views.post_detail, name='post_detail'),
path('post/new/', views.post_create, name='post_create'),
path('post//edit/', views.post_update, name='post_update'),
path('post//delete/', views.post_delete, name='post_delete'),
]
嵌套routing and namespace
当 many 个applicationusing相同 视graph名称时, 可以usingnamespace来避免conflict:
# mysite/urls.py
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
# for blogapplication添加namespace
path('blog/', include(('blog.urls', 'blog'), namespace='blog')),
# for shopapplication添加namespace
path('shop/', include(('shop.urls', 'shop'), namespace='shop')),
]
in 模板inusingnamespace:
<a href="{% url 'blog:post_list' %}">博客list</a>
<a href="{% url 'shop:product_list' %}">商品list</a>
动态routing
动态routing允许 in URLpathinpackage含parameter, 这些parameter会被传递给视graphfunction or class视graph.
path转换器
Djangoproviding了 many 种 in 置 path转换器:
- str: 匹配除斜杠 out 任何非空string, 默认转换器.
- int: 匹配正整数.
- slug: 匹配由ASCII字母, number, 连字符 and under 划线组成 string.
- uuid: 匹配UUID格式 string.
- path: 匹配including斜杠 in in 任何非空string.
usingpath转换器
# blog/urls.py
from django.urls import path
from . import views
urlpatterns = [
# 匹配整数主键
path('post//', views.post_detail, name='post_detail'),
# 匹配slug
path('post//', views.post_detail_by_slug, name='post_detail_by_slug'),
# 匹配UUID
path('article//', views.article_detail, name='article_detail'),
# 匹配path
path('files//', views.file_view, name='file_view'),
]
in 视graphfunctionin接收parameter:
# blog/views.py
def post_detail(request, pk):
# pk is from URLin提取 整数parameter
post = get_object_or_404(BlogPost, pk=pk)
return render(request, 'blog/post_detail.html', {'post': post})
def post_detail_by_slug(request, slug):
# slug is from URLin提取 slugparameter
post = get_object_or_404(BlogPost, slug=slug)
return render(request, 'blog/post_detail.html', {'post': post})
自定义path转换器
可以creation自定义path转换器, processing特殊 URLparameter格式.
步骤1: creation转换器class
# blog/converters.py
class YearConverter:
regex = r'\d{4}' # 匹配4位number
def to_python(self, value):
# 将URLpathin string转换 for Pythonobject
return int(value)
def to_url(self, value):
# 将Pythonobject转换 for URLpathin string
return str(value)
class MonthConverter(YearConverter):
regex = r'\d{2}' # 匹配2位number
步骤2: register转换器
# blog/urls.py
from django.urls import path, register_converter
from . import views
from .converters import YearConverter, MonthConverter
# register自定义转换器
register_converter(YearConverter, 'year')
register_converter(MonthConverter, 'month')
urlpatterns = [
# using自定义转换器
path('archive//', views.archive_by_year, name='archive_by_year'),
path('archive///', views.archive_by_month, name='archive_by_month'),
]
in 视graphfunctioninusing自定义转换器:
# blog/views.py
def archive_by_year(request, year):
# year is intclass型 parameter
posts = BlogPost.objects.filter(pub_date__year=year)
return render(request, 'blog/archive.html', {'posts': posts, 'year': year})
def archive_by_month(request, year, month):
# year and month都 is intclass型 parameter
posts = BlogPost.objects.filter(pub_date__year=year, pub_date__month=month)
return render(request, 'blog/archive.html', {'posts': posts, 'year': year, 'month': month})
正则表达式routing
for 于 complex routing模式, 可以using正则表达式routing.
# blog/urls.py
from django.urls import path, re_path
from . import views
urlpatterns = [
# using正则表达式匹配日期格式 YYYY/MM/DD
re_path(r'^archive/(?P\d{4})/(?P\d{2})/(?P\d{2})/$',
views.archive_by_day, name='archive_by_day'),
# using正则表达式匹配 many 个ID, 例such as /posts/1,2,3/
re_path(r'^posts/(?P[\d,]+)/$', views.posts_by_ids, name='posts_by_ids'),
]
in 视graphfunctioninusing正则表达式parameter:
# blog/views.py
def archive_by_day(request, year, month, day):
posts = BlogPost.objects.filter(
pub_date__year=year,
pub_date__month=month,
pub_date__day=day
)
return render(request, 'blog/archive.html', {
'posts': posts,
'year': year,
'month': month,
'day': day
})
def posts_by_ids(request, ids):
# 将stringID转换 for 整数list
id_list = [int(id) for id in ids.split(',')]
posts = BlogPost.objects.filter(id__in=id_list)
return render(request, 'blog/post_list.html', {'posts': posts})
routing视graph
Djangoproviding了 many 种 in 置 routing视graph, 可以直接用于processingcommon HTTPrequest.
重定向视graph
# blog/urls.py
from django.urls import path
from django.views.generic import RedirectView
urlpatterns = [
# 永久重定向
path('old-url/', RedirectView.as_view(url='/new-url/', permanent=True), name='old_url_redirect'),
# using反向URL解析
path('legacy-post//', RedirectView.as_view(pattern_name='post_detail', permanent=True)),
# 动态重定向
path('go-to-post//', RedirectView.as_view(url='/post/%(pk)s/'), name='go_to_post'),
]
模板视graph
# blog/urls.py
from django.urls import path
from django.views.generic import TemplateView
urlpatterns = [
# simple 模板视graph
path('about/', TemplateView.as_view(template_name='blog/about.html'), name='about'),
# 带额 out on under 文 模板视graph
path('contact/', TemplateView.as_view(
template_name='blog/contact.html',
extra_context={'phone': '123-456-7890', 'email': 'contact@example.com'}
), name='contact'),
]
routingin间件
routingin间件 is 指 in processingrequest 过程in, in 视graph执行 before after 执行 code. 可以用于身份verification, log记录, cacheetc..
自定义in间件
# blog/middleware.py
class LoggingMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# request to 达视graph之 before 执行
print(f"Request: {request.method} {request.path}")
# 调用视graph
response = self.get_response(request)
# 视graph返回response之 after 执行
print(f"Response: {response.status_code}")
return response
# processing视graph抛出 exception
def process_exception(self, request, exception):
print(f"Exception: {exception}")
return None
然 after in settings.pyinregisterin间件:
# settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'blog.middleware.LoggingMiddleware', # register自定义in间件
]
基于class in间件
可以using基于class in间件, implementation更 complex functions:
# blog/middleware.py
from django.utils.deprecation import MiddlewareMixin
class AuthenticationMiddleware(MiddlewareMixin):
def process_request(self, request):
# request to 达视graph之 before 执行
if not request.user.is_authenticated and request.path not in ['/login/', '/register/']:
return redirect('/login/')
def process_response(self, request, response):
# 视graph返回response之 after 执行
return response
routingpermission控制
可以using装饰器 or in间件来控制routing 访问permission.
using装饰器控制permission
# blog/views.py
from django.contrib.auth.decorators import login_required, permission_required
@login_required
def profile(request):
return render(request, 'blog/profile.html')
@permission_required('blog.change_blogpost')
def post_edit(request, pk):
# 视graph逻辑...
usingin间件控制permission
# blog/middleware.py
class PermissionMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# 定义需要specificpermission URLpath
permission_required = {
'/admin/': 'is_staff',
'/post/create/': 'blog.add_blogpost',
'/post//edit/': 'blog.change_blogpost',
}
# checkuserpermission
for path, permission in permission_required.items():
if request.path.startswith(path):
if permission.startswith('is_'):
# checkuserproperty
if not getattr(request.user, permission, False):
return HttpResponseForbidden()
else:
# checkuserpermission
if not request.user.has_perm(permission):
return HttpResponseForbidden()
response = self.get_response(request)
return response
routingcache
可以usingDjango cachesystem来cacheroutingresponse, improvingperformance.
cache整个站点
# settings.py
MIDDLEWARE = [
'django.middleware.cache.UpdateCacheMiddleware', # 必须放 in 第一个
# otherin间件...
'django.middleware.cache.FetchFromCacheMiddleware', # 必须放 in 最 after 一个
]
# cacheconfiguration
CACHE_MIDDLEWARE_ALIAS = 'default'
CACHE_MIDDLEWARE_SECONDS = 600 # cache时间, 单位秒
CACHE_MIDDLEWARE_KEY_PREFIX = ''
cachespecific视graph
# blog/views.py
from django.views.decorators.cache import cache_page
@cache_page(60 * 15) # cache15分钟
def post_list(request):
posts = BlogPost.objects.all()
return render(request, 'blog/post_list.html', {'posts': posts})
cachespecificURL
# blog/urls.py
from django.urls import path
from django.views.decorators.cache import cache_page
from . import views
urlpatterns = [
# cachepost_list视graph15分钟
path('', cache_page(60 * 15)(views.post_list), name='post_list'),
# otherURLconfiguration...
]
routingperformanceoptimization
routing performance for 整个application performance has important 影响. 以 under is 一些optimizationroutingperformance 建议:
- 保持URLconf简洁: 避免 in URLconfin执行 complex 逻辑 or querydatalibrary.
- using命名routing: using命名routing可以improvingcode readable 性 and 可maintenance性.
- 避免using正则表达式routing: 正则表达式routing比普通routing slow , 尽量usingpath()function.
- usinginclude()function: usinginclude()function可以将URLconf拆分 for many 个module, improvingperformance.
- cacheroutingresponse: for 于频繁访问 视graph, 可以usingcache来improvingperformance.
练习 1: creation嵌套routing
- creation一个名 for "shop" Djangoapplication.
- in project urls.pyinpackage含shopapplication URLconfiguration, 并添加namespace.
- in shopapplication urls.pyin定义商品list, 商品详情, 商品creationetc.routing.
- creation相应 视graphfunction and 模板.
- testrouting is 否正常工作.
练习 2: creation自定义path转换器
- creation一个自定义path转换器, 用于匹配IPv4地址.
- register自定义转换器.
- using自定义转换器creationrouting, 用于显示specificIP地址 访问log.
- creation相应 视graphfunction and 模板.
- testrouting is 否正常工作.
练习 3: creationroutingin间件
- creation一个in间件, 用于记录所 has request URL, method and responsestatus码.
- in settings.pyinregisterin间件.
- testin间件 is 否正常工作.