Djnago 视图层
Django提供了一套简洁优美的URL传递机制
1. Django处理HTTP请求过程
- Django会用使用配置文件settings中的ROOT_URLCONF指定的url配置文件,但是如果request中有一个urlconf属性,就会优先使用这个值
- Django加载这个url配置文件,寻找urlpatterns变量,这个变量必须是一个列表或元组,元素是django.urls.path或django.urls.re_path的对象
- Django会按顺序匹配urlpatterns中定义的URL匹配模式,一旦匹配成功就立刻结束
- 匹配成功后Django会调用对应的视图函数处理,并给视图函数传递HttpRequest对象,并把匹配的位置参数或关键字参数传给视图
- 如果没有对应的URL匹配,或者在这个过程中引发了异常,就会调用一个适当的错误处理视图,比如404
1.1 django.urls.path
比如下面这个URL配置文件
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参数,就使用尖括号包住,如<int:year>
- 可以让捕获的URL参数转换成对应的类型,如<int:year>,会把捕获的year由字符串转成整数
- 匹配时不需要以 /开头,因为每一个URL都会以/结尾
- 如果一个请求是
/articles/2005/03/,就会匹配urlpatterns列表中的第三个,Django会调用第三个视图函数views.month_archive(request, year=2005, month=3) - /articles/2003/会匹配列表中的第一个, 调用views.special_case_2003(request)
- /articles/2003 匹配不到任何一个,因为每一个URL需要以一个/结尾
- /articles/2003/03/building-a-django-site/会匹配最后一个, Django会调用views.article_detail(request, year=2003, month=3, slug="building-a-django-site")
路径参数类型转换
- str - 匹配任意非空字符串,不包括 / ,这是默认的默认的转换方式
- int - 匹配0或任意正整数,返回一个整数
- slug - 匹配由ASCII字母或数字,连字符,下划线字符组成的字符串
- uuid - 匹配并返回一个uuid对象
- path - 匹配任意非空字符串,包括 /, 可以用来匹配一个完整的URL路径
1.2 django.urls.re_path
使用re_path,捕获URL参数用圆括号包住,如果想捕获关键字参数,使用(?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), ]
1.3 错误处理
Django默认提供了4个错误处理,如果觉得不够可以自己添加,也可以修改这四个错误处理变量
四个错误处理变量必须在URL根配置文件中配,在其它的URL配置文件中配置不会生效
四个错误处理变量必须是可以调用的对象,或者是可以导入的视图的完整路径,然后视图中处理错误
这些四个错误处理变量是
handler400 – See django.conf.urls.handler400.
handler403 – See django.conf.urls.handler403.
handler404 – See django.conf.urls.handler404.
handler500 – See django.conf.urls.
下面是一个自定义处理403错误的例子
from django.core.exceptions import PermissionDenied from django.http import HttpResponse from django.test import SimpleTestCase, override_settings from django.urls import path def response_error_handler(request, exception=None): return HttpResponse('Error handler content', status=403) def permission_denied_view(request): raise PermissionDenied urlpatterns = [ path('403/', permission_denied_view), ] handler403 = response_error_handler # ROOT_URLCONF must specify the module that contains handler403 = ...
# 这里用装饰器临时覆盖配置文件设置的URL根配置文件为当前文件,主要用来测试
@override_settings(ROOT_URLCONF=__name__) class CustomErrorHandlerTests(SimpleTestCase): def test_handler_renders_template_response(self): response = self.client.get('/403/') # Make assertions on the response here. For example: self.assertContains(response, 'Error handler content', status_code=403)
1.4 包含其它的URL配置文件
一个大点的网站,可能需要不止一个URL配置文件,实际上Django中每一个APP都应该有一个URL配置文件
在settings中配置的ROOT_URLCONF指定的URL配置文件是根配置,从这里可以引入其它APP的URL配置文件
比如可以这样引入一个article的app目录下的名为urls.py的URL配置文件
from django.urls import path, include urlpatterns = [ path('articles/', include('article.urls')), ]
article/urls.py中这样继续定义
from django.urls import path from . import views urlpatterns = [ path('2003/', views.special_case_2003), path('<int:year>/', views.year_archive), path('<int:year>/<int:month>/', views.month_archive), path('<int:year>/<int:month>/<slug:slug>/', views.article_detail), ]
这时如果浏览器请求articles/2003/,就先匹配URL根配置文件,匹配到articles/之后 ,就截断已匹配的
继续把剩余的传递给article.urls中匹配,匹配到列表中的第一个,调用views.special_case_2003(request)
这个也可以用来把大量有相同前缀的URL匹配简化,
如
from django.urls import path from . import views urlpatterns = [ path('<page_slug>-<page_id>/history/', views.history), path('<page_slug>-<page_id>/edit/', views.edit), path('<page_slug>-<page_id>/discuss/', views.discuss), path('<page_slug>-<page_id>/permissions/', views.permissions), ]
可以这样简化
from django.urls import include, path from . import views urlpatterns = [ path('<page_slug>-<page_id>/', include([ path('history/', views.history), path('edit/', views.edit), path('discuss/', views.discuss), path('permissions/', views.permissions), ])), ]
1.5 URL反向解析
我们可以在URL配置项中,给一个匹配项起一个名字,如下面的
from django.urls import path from . import views urlpatterns = [ #... path('articles/<int:year>/', views.year_archive, name='news-year-archive'), #... ]
然后在模板中使用url标签进行反向解析
<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a> {# Or with the year in a template context variable: #} <ul> {% for yearvar in year_list %} <li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li> {% endfor %} </ul>
在视图函数中反向解析,需要使用reverse方法
from django.http import HttpResponseRedirect from django.urls import reverse def redirect_to_year(request): # ... year = 2006 # ... return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))
2. 视图函数
2.1 基本视图
视图函数一般是一个python定义的函数,需要接收HTTP request请求对象,返回HTTP响应对象,
返回的内容可以是HTML内容,或者是一个重定向,或者是一个404错误,或者是一个图片,一个XML文档,或者任何东西,
视图函数的处理可以是任意的逻辑,只要返回HTTP响应对象就可以
一般视图函数放在APP或项目目录下面的view.py文件中
比如一个简单的视图函数,返回一个显示当前时间的HTML内容
from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html)
其中,视图函数的名字可以是任意的。
视图函数中,可以直接引发http异常报错,然后Django就会自动调用1.3错误处理中的视图来处理错误
from django.http import Http404 from django.shortcuts import render from polls.models import Poll def detail(request, poll_id): try: p = Poll.objects.get(pk=poll_id) except Poll.DoesNotExist: raise Http404("Poll does not exist") return render(request, 'polls/detail.html', {'poll': p})
2.2 视图装饰器
Django提供了一些装饰器来装饰视图函数
require_http_methods(request_method_list) 限制HTTP请求方法为request_method_list中设置的
from django.views.decorators.http import require_http_methods @require_http_methods(["GET", "POST"]) def my_view(request): # I can assume now that only GET or POST requests make it this far # ... pass
注意,请求方法必须是大写的
require_GET
限制HTTP请求为GET方法
require_POST
限制HTTP请求为POST方法
require_safe
限制HTTP请求为GET和HEAD方法,这两个方法只是请求资源,所以叫安全的
3. 快捷函数
3.1 render()
render(request, template_name, context=None, content_type=None, status=None, using=None)
用http请求,模板和上下文字典,渲染之后返回http响应对象
3.2 redirect()
重定向
3.3 get_object_or_404()
3.4 get_list_or_404()

浙公网安备 33010602011771号