Django如何处理一个请求

当用户请求Django站点的一个页面,Django会以下面的逻辑执行操作:

  1. 决定要使用的根URLconf模块。通常,这是ROOT_URLCONF设置的值,但是如果传入的HttpRequest对象具有urlconf属性(由中间件设置),则其值将被用于代替ROOT_URLCONF设置。通俗的将,就是你可以自定义项目入口url是哪个文件。
  2. 加载该模块并寻找可用的urlpatterns。它是django.urls.path()或者django.urls.re_path()实例的一个列表。
  3. 依次匹配每个URL模式,在与请求的URL相匹配的第一个模式停止。
  4. 导入并调用匹配行中给定的视图,该视图是一个简单的Python函数(被称为视图函数),或基于类的视图。视图将会获得如下参数:
    • 一个HttpRequest实例。
    • 如果匹配的URL模式未返回任何命名组,则正则表达式中的匹配将作为位置参数提供。
    • 关键字参数由路径表达式匹配的任何命名部分组成,但是可以被django.urls.path()的可选参数kwargs覆盖。
  5. 如果没有匹配到任何表达式,或者过程中抛出异常,将调用一个合适的错误处理视图。

示例

from django.urls import path
from . import views


urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    path('articles/<int:year>/', views.year_archive),
    path('articles/<int:year>/<int:month>/', views.month_archive),
    path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
]

注意:

  • 需要从url获取的值,需要使用尖括号包裹(“<>”)。
  • 捕获的值可以选择性地包含转换器类型。

路径转换器

  • str:匹配任何非空字符串,但不包含”/“。如果没有指定转换器类型,它将会是默认转换器类型。
  • int:匹配任何0或正整数,返回一个int类型。
  • slug:匹配由ASCII字母或数字组成的任何slug字符串,以及连字符和下划线。
  • uuid:匹配格式化的UUID,为了防止多个URL映射到同一页面,必须包含连字符,并且字母必须为小写。例如,ca6342ef-3c98-402c-9418-b39a13f72028。返回一个UUID实例。
  • path:匹配任何非空字符安穿,重点是可以包含路径分隔符”/“,这个转换器可以匹配整个url而不是一段段的url字符串。

自定义path转换器

对于复杂的匹配要求,也可以自定义路径转换器。
转换器是一个包含一下内容的类:

  • regex类属性:字符串形式的正则表达式。
  • to_python(self, value):将匹配到的字符串转换为想要的数据类型,并传递给视图函数。如果转换失败,必须抛出ValueError异常。
  • to_url(self, value):将python数据类型转化为一段url的方法。

示例:

# converters.py
class FourDigitYearConverter:
    regex = "[0-9]{4}"

    def to_python(self, value):
        return int(value)

    def to_url(self, value):
        return "%04d" % value

定义好的自定义转换器类,使用时还需要在URLconf中使用register_converter()注册后才能正常是用。

from django.urls import path, register_converter
from . import converters, views

register.converter(converters.FourDigitYearConverter, "yyyy")

urlpatters = [
    path('articles/2003/', views.special_case_2003),
    path('articles/<yyyy:year>/', views.year_archive),
    ...
]

正则表达式匹配

django2.0以上版本使用path()代替了之前版本使用url()进行正则匹配的方式,但是同样可以使用re_path()进行正则匹配。Python正则表达式中,命名正则表达式组的语法是(?P<name>pattern),name是组名,pattern是需要匹配的模式。

from django.urls import path, re_path
from . import views


urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[\w-]+)/$', views.article_detail),
]

URLconf如何进行查找

请求的URL将被看做是一个普通的Python字符串,同过URLconf进行查找和匹配。进行匹配时,将不包括GET或POST请求方式的参数以及域名。URLconf不检查使用了那种请求方法。所有的请求方法对同一个URL的访问,都将被路由到相同的函数。

错误处理

当Django找不到与请求匹配的URL或抛出异常时,将调用一个错误处理视图。Django默认自带的错误处理视图包括400、403、404和500,分别表示请求错误、拒绝服务、页面不存在和服务器错误。这些只必须设置在根URLconf中,在其他URLconf中设置将不会产生效果。这些值分别为:

  • handler400
  • handler403
  • handler404
  • handler500

自定义错误页面

示例

# views.py 配置
def page_not_found(request, exception):
    response = render_to_response("404.html")
    response.status_code = 404
    return response

# 根URLconf配置
from django.urls import path
from . import views

urlpatterns = [
    ...
]

handler404 = views.page_not_found

URL转发

在任何时候,URLconf中都可以使用”include”包含其他URLconf模块。

from django.urls import include, path

urlpatterns = [
    path("blog/", include("blog.urls")),
    path("article/", include("article.urls")),
    ...
]

每当Django遇到include(),它都会删除与该点匹配的URL的任何部分,并将剩余的字符串发送到包含的URLconf以进行进一步的匹配。

传递额外选项

URLconfs有一个钩子,允许将额外的参数作为Python字典传递给视图函数。path()函数可以采用可选的第三个参数,该参数应该是传递给视图函数的额外关键字参数的字典。

from django.urls import path
from . import views

urlpatterns = [
    path("blog/<int:year>/", views.year_archive, {"foo": "bar"}),
]

上面的示例,Django将调用views.year_archive(request, year, foo="bar")

将额外参数传递给include()

# 方法一
# main.py
from django.urls import include, path

urlpatterns = [
    path('blog/', include('inner'), {'blog_id': 3}),
]

# inner.py
from django.urls import path
from mysite import views

urlpatterns = [
    path('archive/', views.archive),
    path('about/', views.about),


# 方法二
# main.py
from django.urls import include, path
from mysite import views

urlpatterns = [
    path('blog/', include('inner')),
]

# inner.py
from django.urls import path

urlpatterns = [
    path('archive/', views.archive, {'blog_id': 3}),
    path('about/', views.about, {'blog_id': 3}),
]

注意,额外的选项总是被传递到包含的URLconf中的每一行,而不管行视图是否接受这些选项为有效的。由于这个原因,只有在确定包含的URLconf中的每个视图都接受传递的额外选项时,这种技术才有用。

0条评论

相关推荐

django教程

r

Django 2019-05-20 10:53:53

Celery

celery学习资料

Django 2019-05-25 18:41:55

Django-rest-framework教程

django-rest-framework教程。

Django 2019-07-18 16:33:26

django实用资料

django项目从0到1自己总结的实用的资料,大部分常用的功能这里都有

Django 2019-05-08 18:21:34