Python开发-Django视图层

在这里插入图片描述

视图层

Django 具有 “视图” 的概念,负责处理用户的请求并返回响应。

一、基础:

1.URL 配置

URL调度器

对于高质量的 Web 应用来说,使用简洁、优雅的 URL 模式是一个非常值得重视的细节。Django 允许你自由地设计你的 URL,不受框架束缚。

概况

为了给一个应用设计 URL,你需要创建一个 Python 模块,通常被称为 URLconf (URL configuration)。这个模块是纯粹的 Python 代码,包含 URL 模式(简单的正则表达式)到 Python 函数(你的视图)的简单映射。

映射可短可长,随便你。它可以引用其它的映射。而且,因为它是纯粹的 Python 代码,它可以动态构造。

Django 如何处理一个请求

当一个用户请求 Django 站点的一个页面,下面是 Django 系统决定执行哪个 Python 代码使用的算法:

Django 确定使用根 URLconf 模块。通常,这是 ROOT_URLCONF 设置的值,但如果传入 HttpRequest 对象拥有 urlconf 属性(通过中间件设置),它的值将被用来代替 ROOT_URLCONF 设置。

Django 加载该 Python 模块并寻找可用的 urlpatterns 。它是 django.urls.path() 和(或) django.urls.re_path() 实例的序列(sequence)。
Django 会按顺序遍历每个 URL 模式,然后会在所请求的URL匹配到第一个模式后停止,并与 path_info 匹配。

一旦有 URL 匹配成功,Djagno 导入并调用相关的视图,这个视图是一个Python 函数(或基于类的视图 class-based view )。

视图会获得如下参数:

一个 HttpRequest 实例。
如果匹配的 URL 包含未命名组,那么来自正则表达式中的匹配项将作为位置参数提供。
关键字参数由路径表达式匹配的任何命名部分组成,并由 django.urls.path() 或 django.urls.re_path() 的可选 kwargs 参数中指定的任何参数覆盖。
如果没有 URL 被匹配,或者匹配过程中出现了异常,Django 会调用一个适当的错误处理视图。参加下面的错误处理( Error handling )。

比如下面的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),
]

路径转换器
下面的路径转换器在默认情况下是有效的:

str - 匹配除了 ‘/’ 之外的非空字符串。如果表达式内不包含转换器,则会默认匹配字符串。
int - 匹配 0 或任何正整数。返回一个 int 。
slug - 匹配任意由 ASCII 字母或数字以及连字符和下划线组成的短标签。比如,building-your-1st-django-site 。
uuid - 匹配一个格式化的 UUID 。为了防止多个 URL 映射到同一个页面,必须包含破折号并且字符都为小写。比如,075194d3-6885-417e-a8a8-6c931e272f00。返回一个 UUID 实例。
path - 匹配非空字段,包括路径分隔符 ‘/’ 。它允许你匹配完整的 URL 路径而不是像 str 那样匹配 URL 的一部分。

注册自定义的路径转换器

对于更复杂的匹配需求,你能定义你自己的路径转换器。

转换器是一个类,包含如下内容:

字符串形式的 regex 类属性。

to_python(self, value) 方法,用来处理匹配的字符串转换为传递到函数的类型。如果没有转换为给定的值,它应该会引发 ValueError 。ValueError 说明没有匹配成功,因此除非另一个 URL 模式匹配成功,否则会向用户发送404响应。

一个 to_url(self, value) 方法,它将处理 Python 类型转换为字符串以用于 URL 中。如果不能转换给定的值,它应该引发 ValueError。ValueError 被解释为无匹配项,因此 reverse() 将引发 NoReverseMatch,除非有其他 URL 模式匹配。

比如:

class FourDigitYearConverter:
    regex = '[0-9]{4}'

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

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

自定义转换器:

from django.urls import path, register_converter

from . import converters, views

register_converter(converters.FourDigitYearConverter, 'yyyy')

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

使用正则表达式

如果路径和转化器语法不能很好的定义你的 URL 模式,你可以可以使用正则表达式。如果要这样做,请使用 re_path() 而不是 path() 。

在 Python 正则表达式中,命名正则表达式组的语法是 (?Ppattern) ,其中 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),
]

2.视图函数

一个视图函数(或简称为视图)是一个 Python 函数,它接受 Web 请求并返回一个 Web 响应。这个响应可以是 Web 页面的 HTML 内容,或者重定向,或者404错误,或者 XML 文档,或一个图片…或是任何内容。视图本身包含返回响应所需的任何逻辑。这个代码可以存在任何地方,只要它在你的 Python 路径上就行。可以说,不需要其他东西,这里并没有魔法。为了将代码放置在某处,约定将视图放在名为 views.py 的文件里,这个文件放置在项目或应用目录里。

下面是一个视图例子:

import datetime

def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)

上面的代码中,我们从 django.http 模块导入类 HttpResponse ,以及 Python 的 datetime 库。
然后,我们定义一个名为 current_datetime 的函数。这是一个视图函数。每个视图函数都将 HttpRequest 对象作为第一个参数,通常名为 request 。

注意视图函数名称无关紧要;它不需要以特定的名称来让 Django 识别它。我们在这里命名 current_datetime ,因为这个名字可以清楚的表示它的用途。

视图返回一个包含生成的响应的 HttpResponse 对象。每个视图函数都要返回 HttpResponse 对象。

将 URL 映射到视图

视图函数返回包含当前日期时间的HTML页面。如果在特定的 URL 使用这个视图,你需要创建 URLconf
返回错误信息

from django.http import HttpResponse, HttpResponseNotFound

def my_view(request):
    # ...
    if foo:
        return HttpResponseNotFound('<h1>Page not found</h1>')
    else:
        return HttpResponse('<h1>Page was found</h1>')

Http404 异常
class django.http.Http404
当你返回错误,例如 HttpResponseNotFound ,你需要定义错误页面的 HTML 。

return HttpResponseNotFound('<h1>Page not found</h1>')

自定义报错视图

handler404 = 'mysite.views.my_custom_page_not_found_view'

异步视图

除了同步函数,视图也可以是异步(“async”)函数,通常使用 Python 的 async def 语法定义。Django 会自动检测这些函数,并在异步上下文中运行它们。但是,你需要使用基于 ASGI 的异步服务器来获得它们的性能优势。

比如我们定义一个异步视图:

import datetime
from django.http import HttpResponse

async def current_datetime(request):
    now = datetime.datetime.now()
    html = '<html><body>It is now %s.</body></html>' % now
    return HttpResponse(html)

3.便捷工具

便捷函数

包 django.shortcuts 收集助手函数和“跨”多级mvc的类,换句话说,为了方便起见,这些函数/类引入受控耦合。

比如可用MIME类型显现模板:

from django.shortcuts import render

def my_view(request):
    # View code here...
    return render(request, 'myapp/index.html', {
        'foo': 'bar',
    }, content_type='application/xhtml+xml')

4.装饰器

视图装饰器

Django 提供很多装饰器,它们可以为视图支持多种 HTTP 特性。

允许的 HTTP 方法
装饰器可以要求视图只接受特定的请求方法

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

条件视图处理
下面 django.views.decorators.http 的装饰器被用来控制特殊视图中的缓存行为。

condition(etag_func=None, last_modified_func=None)
etag(etag_func)
last_modified(last_modified_func)
这些装饰器被用来生成 ETag 和 Last-Modified 头部;查看 conditional view processing 。

GZip 压缩

django.views.decorators.gzip 里的装饰器控制基于每个视图的内容压缩。

gzip_page()

如果浏览器允许 gzip 压缩,那么这个装饰器将压缩内容。它相应的设置了 Vary 头部,这样缓存将基于 Accept-Encoding 头进行存储。

Vary 头

django.views.decorators.vary 里的装饰器被用来根据特殊请求头的缓存控制。

vary_on_cookie(func)

vary_on_headers(*headers)
Vary 头定义了缓存机制在构建其缓存密钥时应该考虑哪些请求报头。

缓存

django.views.decorators.cache 中的装饰器控制服务器及客户端的缓存。

**cache_control(kwargs)

这个装饰器通过添加所有关键字参数来修补响应的 Cache-Control 头。查看 patch_cache_control() 来了解转换的详情。

never_cache(view_func)

这个装饰器添加 Cache-Control: max-age=0, no-cache, no-store, must-revalidate 头到一个响应来标识禁止缓存该页面。

Common

The decorators in django.views.decorators.common allow per-view customization of CommonMiddleware behavior.

no_append_slash()
This decorator allows individual views to be excluded from APPEND_SLASH URL normalization.

5.异步支持

异步支持

Django 支持编写异步(“async”)视图,如果在 ASGI 下运行,还支持完全异步的请求堆栈。异步视图仍然可以在 WSGI 下运行,但会有性能损失,并且不能有高效的长时间运行的请求。

用 sync_to_async() 调用来包装:

from asgiref.sync import sync_to_async

results = await sync_to_async(Blog.objects.get, thread_sensitive=True)(pk=123)

二、请求响应对象:

1.内置视图

为开发中的文件提供服务
static.serve(request, path, document_root, show_indexes=False)

除了你的项目的静态资源外,可能还有一些其他的文件,为了方便,你想让 Django 在本地开发中为你提供服务。serve() 视图可以用来为你给它的任何目录提供服务。(这个视图并 没有 强到用于生产,只应该作为开发辅助工具,你应该在生产中使用真正的前端 Web 服务器来服务这些文件)。

最有可能的例子是用户在 MEDIA_ROOT 中上传的内容。django.contrib.staticfiles 是为静态资源设计的,并没有内置处理用户上传文件的功能,但是你可以通过在 URLconf 中添加这样的内容,让 Django 为你的 MEDIA_ROOT 服务:

from django.conf import settings
from django.urls import re_path
from django.views.static import serve

# ... the rest of your URLconf goes here ...

if settings.DEBUG:
    urlpatterns += [
        re_path(r'^media/(?P<path>.*)$', serve, {
            'document_root': settings.MEDIA_ROOT,
        }),
    ]

2.请求/响应对象

快速概述
Django 使用请求和响应对象在系统中传递状态。

当一个页面被请求时,Django 会创建一个 HttpRequest 对象,这个对象包含了请求的元数据。然后,Django 加载相应的视图,将 HttpRequest 作为视图函数的第一个参数。每个视图负责返回一个 HttpResponse 对象。

HttpRequest 对象
class HttpRequest
属性
除非另有说明,否则所有属性都应视为只读。

HttpRequest.scheme
代表请求协议的字符串(通常是 http 或 https)。

HttpRequest.body

原始的 HTTP 请求体作为一个字节字符串。这对于以不同方式处理非常规 HTML 表单的数据很有用:二进制图像,XML 有效负载等。对于处理传统的表单数据,使用 HttpRequest.POST。

你也可以使用类似文件的接口 HttpRequest.read() 或 HttpRequest.readline() 从 HttpRequest 中读取。在使用这些 I/O 流方法中的任何一种方法读取请求后,访问 body 属性会产生 RawPostDataException。

HttpRequest.path

A string representing the full path to the requested page, not including the scheme, domain, or query string.

例如:"/music/bands/the_beatles/"

HttpRequest.path_info

在某些 Web 服务器的配置下,主机名之后的 URL 部分被分割成脚本前缀部分和路径信息部分。path_info 属性总是包含路径的路径信息部分,无论使用的是什么 Web 服务器。使用它代替 path 可以使你的代码更容易在测试服务器和部署服务器之间移动。

例如,如果你的应用程序的 WSGIScriptAlias 设置为 “/minfo”,那么 path 可能是 “/minfo/music/bands/the_beatles/” 和 path_info 将是 “/music/bands/the_beatles/”。

HttpRequest.method

if request.method == 'GET':
    do_something()
elif request.method == 'POST':
    do_something_else()

3.TemplateResponse 对象

TemplateResponse 和 SimpleTemplateResponse

标准 HttpResponse 对象是静态结构。它们在构建时提供了一个预渲染的内容块,虽然这些内容可以修改,但它的形式并不便于进行修改。

然而,有时允许装饰者或中间件在视图构建响应后修改响应可能是有益的。例如,你可能想改变所使用的模板,或者在上下文中放入额外的数据。

TemplateResponse 提供了一种方法来实现这一点。与基本的 HttpResponse 对象不同,TemplateResponse 对象保留了模板和上下文的细节,这些细节是由视图提供的,用于计算响应。响应的最终输出直到需要时才会计算,在响应过程的后面。

三、文件上传:

1.概览

当 Django 处理文件上传时,文件数据最终会被放置在 request.FILES
比如简单文件上传:

from django import forms

class UploadFileForm(forms.Form):
    title = forms.CharField(max_length=50)
    file = forms.FileField()

2.文件对象

File 对象

django.core.files 模块及其子模块包含了 Django 中基本的文件处理的内置类。

ContentFile 类

class ContentFile(content, name=None)

ImageFile 类

class ImageFile(file_object, name=None)

3.存储 API

获取当前存储类
Django 提供了两种方便的方式来访问当前的存储类。

class DefaultStorage

DefaultStorage 在内部使用 get_storage_class(),提供对当前默认存储系统的惰性访问,该系统由 DEFAULT_FILE_STORAGE 定义。

get_storage_class(import_path=None)

返回一个实现存储 API 的类或模块。

4.管理文件

在模型中使用文件

当你使用 FileField 或 ImageField 时,Django 提供了一组处理文件的API。

考虑下面的模型,使用 ImageField 来存储照片:

from django.db import models

class Car(models.Model):
    name = models.CharField(max_length=255)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    photo = models.ImageField(upload_to='cars')

5.自定义存储

编写一个自定义存储系统

如果你需要提供自定义文件储存功能——一个普通的例子是,把文件储存在远程系统中——自定义一个存储类可以完成这一任务来完成。下面是需要完成的具体步骤:

1.你自定义的存储系统必须为 Django.core.files.storage.Storage 的一个子类:

from django.core.files.storage import Storage

class MyStorage(Storage):
    ...

2.Django 必须能以无参数实例化你的存储系统。意味着所有配置都应从 django.conf.settings 配置中获取:

from django.core.files.storage import Storage

class MyStorage(Storage):
    def __init__(self, option=None):
        if not option:
            option = settings.CUSTOM_STORAGE_OPTIONS
        ...

3.在你的存储类中,除了其他自定义的方法外,还必须实现 _open() 以及 _save() 等其他适合你的存储类的方法。
4.您的存储类必须是 deconstructible,以便在迁移中的字段上使用它时可以序列化。 只要你的字段有自己的参数 serializable,你可以使用 django.utils.deconstruct.deconstructible 类装饰器(这是 Django 在 FileSystemStorage 上使用的)。

四、基于类的视图:

1.概览

基于类的视图¶
视图是可调用的,能接受用户的请求并返回响应。视图远不只是个函数,Django提供了一些可用作视图的类的示例,允许你通过继承和复用构建自己的视图并且复用这些代码。虽然接下来还会介绍一些用于任务的通用视图,但你可能想自己设计可复用的视图结构,以便针对某些特殊场景 。

基于类的视图
内置的基于类的通用视图
使用基于类的视图处理表单
在基于类的视图中使用混入

2.内置显示视图

编写 web 应用会很单调,因为我们一遍一遍地重复一些模式。Django 试图在模型和模板层面消除一些单调,但 web 开发者们仍然会在视图层感受到这种无聊。

Django 通用视图是为了缓解这种情况而被开发的。他们采用在视图开发时发现的某些通用的风格和模式,并把它们抽象化,因此你可能更快的编写公共的数据视图,而不是编写更多的代码。

我们可以识别出某些通用任务,比如显示对象列表,编写显示任何对象列表的代码。然后有问题的模型将被当做附加的参数传递给 URLconf。

Django 附带通用视图来执行以下操作:

为单个对象显示列表和详情页。如果我们创建一个管理会议的应用,那么 TalkListView 和 RegisteredUserListView 就是列表视图的例子。单个"话题页"将作为例子中的"详情页"。
在年/月/日的归档页面,相关的详情和最新页面将显示基于日期的对象。
运行用户创建、更新和删除对象——无论是否授权。
总之,这些视图提供的接口来执行开发者们遇到的最常见的通用任务。

# views.py
from django.views.generic import ListView
from books.models import Publisher

class PublisherListView(ListView):
    model = Publisher

视图挂钩:

# urls.py
from django.urls import path
from books.views import PublisherListView

urlpatterns = [
    path('publishers/', PublisherListView.as_view()),
]

3.内置编辑视图

使用基于类的视图处理表单
表单处理通常有3个途径:

初始 GET (空白或预填充表单)
带有合法数据的POST(通常是带有错误的重新显示的表单)
带有合法数据的POST(处理数据和通常重定向)
自己实现这个会导致很多重复的样板代码(查看 Using a form in a view )。为了避免这个问题,Django 提供了一组通用基于类的视图来处理表单。

基础表单

from django import forms

class ContactForm(forms.Form):
    name = forms.CharField()
    message = forms.CharField(widget=forms.Textarea)

    def send_email(self):
        # send email using the self.cleaned_data dictionary
        pass

模型表单

from django.urls import reverse_lazy
from django.views.generic.edit import CreateView, DeleteView, UpdateView
from myapp.models import Author

class AuthorCreateView(CreateView):
    model = Author
    fields = ['name']

class AuthorUpdateView(UpdateView):
    model = Author
    fields = ['name']

class AuthorDeleteView(DeleteView):
    model = Author
    success_url = reverse_lazy('author-list')

4.使用混入

在基于类的视图中使用混入

Django 内置的基于类的视图提供了很多功能,但你可能想单独使用有些功能。例如,你可能想写一个渲染一个模板来生成 HTTP 响应的视图,但你不能使用 TemplateView ;也许你只需要在 POST 时渲染一个模板,用 GET 来处理其他所有事。虽然你可以直接使用 TemplateResponse,但这很可能会导致重复代码。

因此 Django 也提供了很多混入,它们提供了更多的离散功能。比如模板渲染,被封装在 TemplateResponseMixin 中。

from django.urls import path
from books.views import RecordInterestView

urlpatterns = [
    #...
    path('author/<int:pk>/interest/', RecordInterestView.as_view(), name='author-interest'),
]

5.API 参考

基础视图

View
TemplateView
RedirectView

通用显示视图

DetailView
ListView

通用编辑视图

FormView
CreateView
UpdateView
DeleteView

通用日期视图

ArchiveIndexView
YearArchiveView
MonthArchiveView
WeekArchiveView
DayArchiveView
TodayArchiveView
DateDetailView

基于类的视图混入

ContextMixin
TemplateResponseMixin

单对象混入

SingleObjectMixin
SingleObjectTemplateResponseMixin

多对象混入

MultipleObjectMixin
MultipleObjectTemplateResponseMixin

编辑混入

FormMixin
ModelFormMixin
ProcessFormView
DeletionMixin

基于日期的混入

YearMixin
MonthMixin
DayMixin
WeekMixin
DateMixin
BaseDateListView

简单的通用视图

View
TemplateView
RedirectView

详情视图

DetailView

列表视图

ListView

编辑视图

FormView
CreateView
UpdateView
DeleteView

基于日期的视图

ArchiveIndexView
YearArchiveView
MonthArchiveView
WeekArchiveView
DayArchiveView
TodayArchiveView
DateDetailView

6.扁平化索引

基于类的通用视图——扁平化索引

该索引提供了基于类的视图的参考文档的另一种组织形式。对于每个视图,类树中的有效属性和方法都在该视图下表示。

五、高级:

1.生成 CSV

利用 Django 输出 CSV

本文介绍如何用 Django 的视图动态输出 CSV (Comma Separated Values)。要达到目的,你可以使用 Python 的 CSV 库或 Django 的模板系统。

使用 Python 的 CSV 库

Python 有用一个 CSV 库 csv。它配合 Django 使用的关键是 csv 模块的 CSV 创建行为作用于类文件对象,而 Django 的 HttpResponse 对象也是类文件对象。

import csv
from django.http import HttpResponse

def some_view(request):
    # Create the HttpResponse object with the appropriate CSV header.
    response = HttpResponse(
        content_type='text/csv',
        headers={'Content-Disposition': 'attachment; filename="somefilename.csv"'},
    )

    writer = csv.writer(response)
    writer.writerow(['First row', 'Foo', 'Bar', 'Baz'])
    writer.writerow(['Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"])

    return response

2.生成 PDF

利用 Django 输出 PDF

动态生成 PDF 文件的优点是你可以为不同的目的创建不同的自定义 PDF——例如,为不同的用户或内容的不同片段生成 PDF。

安装 ReportLab
ReportLab 库可从 PyPI 获取。也可以下载 用户指南 (一份 PDF 文件,这不是巧合)。你可以用 pip 安装 ReportLab:

$ python -m pip install reportlab

在 Python 交互解释器中导入它,测试你的安装是否成功:

>>> import reportlab

六、中间件:

1.概览

中间件是 Django 请求/响应处理的钩子框架。它是一个轻量级的、低级的“插件”系统,用于全局改变 Django 的输入或输出。

每个中间件组件负责做一些特定的功能。例如,Django 包含一个中间件组件 AuthenticationMiddleware,它使用会话将用户与请求关联起来。

编写自己的中间件

def simple_middleware(get_response):
    # One-time configuration and initialization.

    def middleware(request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.

        response = get_response(request)

        # Code to be executed for each request/response after
        # the view is called.

        return response

    return middleware

2.内建的中间件类

缓存中间件

class UpdateCacheMiddleware
class FetchFromCacheMiddleware

启用全站缓存。如果启用了这些功能,那么每一个 Django 驱动的页面都会在 CACHE_MIDDLEWARE_SECONDS 配置定义的时间内被缓存。

“通用”中间件

class CommonMiddleware

为完美主义者增加了一些便利:

禁止 DISALLOWED_USER_AGENTS 配置中的用户代理访问,它应该是一个编译的正则表达式对象列表。

根据 APPEND_SLASH 和 PREPEND_WWW 的配置进行 URL 重写。

GZip 中间件

class GZipMiddleware

django.middleware.gzip.GZipMiddleware 为能理解 GZip 压缩的浏览器(所有现代浏览器)压缩内容。

这个中间件应该放在任何其他需要读取或写入响应体的中间件之前,这样压缩就会在之后发生。

如果以下任何一项为真,它将不会压缩内容:

内容主体长度小于 200 字节。
响应已经设置了 Content-Encoding 头。
请求(浏览器)没有发送包含 gzip 的 Accept-Encoding 头。

评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

huidaoli

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值