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()

 

posted @ 2020-06-08 10:56  人不知所  阅读(74)  评论(0)    收藏  举报