内置的基于类的通用视图

  • 1. 扩展通用视图
  • 2. 对象的通用视图
  • 3. 制作“友好”的模板上下文
  • 4. 添加额外的上下文
  • 5. 查看对象的子集
  • 6. 动态过滤
  • 7. 执行额外的工作

CBV | 总目录 | 内置编辑视图


编写Web应用程序可能是单调的,因为我们一次又一次地重复某些模式。Django试图在模型和模板层中消除一些单调,但Web开发人员也在视图级别遇到这种无聊。

Django的通用视图(generic views)是为缓解这种痛苦而开发的。它们采用视图开发中的某些常用习语和模式并对其进行抽象,以便您可以快速编写数据的公共视图,而无需编写太多代码。

我们可以识别某些常见任务,例如显示对象列表,以及编写显示任何对象列表的代码。然后,可以将相关模型作为额外参数传递给URLconf。

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

  • 显示单个对象的列表和详细信息页面。如果我们要创建一个管理会议的应用程序,那么 TalkListView 和 RegisteredUserListView 将是列表视图的示例。单个谈话页面就是我们称之为“详情”视图的一个例子。
  • 年/月/日归档页面,相关详细信息和“最新”页面中显示基于日期的对象。
  • 允许用户创建,更新和删除对象 - 无论是否经过授权。

总之,这些视图提供了简单的界面来执行开发人员遇到的最常见任务。

1. 扩展通用视图

毫无疑问,使用通用视图可以大大加快开发速度。然而,在大多数项目中,通用视图不再足够。实际上,新Django开发人员提出的最常见的问题是如何使通用视图处理更广泛的情况。

这是为1.3版本重新设计通用视图的原因之一 - 之前,它们只是具有令人眼花缭乱的选项数组的视图函数; 现在,扩展通用视图的推荐方法不是在URLconf中传递大量配置,而是将它们子类化,并覆盖它们的属性或方法。

也就是说,通用视图将有一个限制。如果您发现自己难以将视图实现为通用视图的子类,那么您可能会发现使用您自己的基于类或功能的视图编写所需的代码会更有效。

某些第三方应用程序中提供了更多通用视图示例,您也可以根据需要编写自己的视图。

2. 对象的通用视图

TemplateView 当然是有用的,但Django的通用视图在呈现数据库内容的视图时确实很有用。因为它是如此常见的任务,Django附带了一些内置的通用视图,使得生成对象的列表和详情视图非常容易。

让我们首先看一些显示对象列表或单个对象的示例。

我们将使用这些模型:

# models.py
from django.db import modelsclass Publisher(models.Model):name = models.CharField(max_length=30)address = models.CharField(max_length=50)city = models.CharField(max_length=60)state_province = models.CharField(max_length=30)country = models.CharField(max_length=50)website = models.URLField()class Meta:ordering = ["-name"]def __str__(self):return self.nameclass Author(models.Model):salutation = models.CharField(max_length=10)name = models.CharField(max_length=200)email = models.EmailField()headshot = models.ImageField(upload_to='author_headshots')def __str__(self):return self.nameclass Book(models.Model):title = models.CharField(max_length=100)authors = models.ManyToManyField('Author')publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)publication_date = models.DateField()

现在我们需要定义一个视图:

# views.py
from django.views.generic import ListView
from books.models import Publisherclass PublisherList(ListView):model = Publisher

最后将该视图与你的URL关联:

# urls.py
from django.urls import path
from books.views import PublisherListurlpatterns = [path('publishers/', PublisherList.as_view()),
]

这就是我们需要编写的所有Python代码。但是,我们仍然需要编写模板。我们可以通过向视图添加template_name属性来明确告诉视图使用哪个模板 ,但是如果没有显式模板,Django将从对象的名称推断出一个。在这种情况下,推断的模板将是"books/publisher_list.html"- “books”部分来自定义模型的应用程序的名称,而“publisher”只是模型名称的小写版本。

注意
当(例如) 后端TEMPLATES是DjangoTemplates并且APP_DIRS选项设置为True时,模板位置可以是:/path/to/project/books/templates/books/publisher_list.html

模板将渲染包含所有出版社的object_list变量 。一个非常简单的模板可能如下所示:

{% extends "base.html" %}{% block content %}<h2>Publishers</h2><ul>{% for publisher in object_list %}<li>{{ publisher.name }}</li>{% endfor %}</ul>
{% endblock %}

效果图:

这就是它的全部内容。通用视图的所有很酷的功能都来自更改通用视图上设置的属性。该 通用视图参考文献详细描述所有通用视图的选项; 本文档的其余部分将考虑一些可以自定义和扩展通用视图的常用方法。

3. 制作“友好”的模板上下文

您可能已经注意到,我们的示例 publisher 列表模板将所有发布者存储在名为的变量中object_list。虽然这很好用,但对模板作者来说并不是那么“友好”:他们必须“只知道”他们在这里与publisher打交道。

好吧,如果你正在处理一个模型对象,这已经为你完成了。当您处理对象或查询集时,Django能够使用模型类名称的小写版本来填充上下文。除默认object_list含完全相同的数据的xxx_list (这里是 publisher_list)。

如果这仍然不是你想要的,您可以在通用视图上设置context_object_name属性:

# views.py
from django.views.generic import ListView
from books.models import Publisherclass PublisherList(ListView):model = Publishercontext_object_name = 'publisherList'

提供有用context_object_name的总是一个好主意。你设计模板的同事会感谢你。

4. 添加额外的上下文

通常,您需要提供除通用视图的信息之外的一些额外信息。例如,考虑在每个publisher详细信息页面上显示所有书籍的列表。通用视图 DetailView 在上下文中提供了publisher ,但我们如何在模板中获取更多的信息?

答案是创建DetailView 子类并提供您自己的get_context_data方法实现。默认实现只是将显示的对象添加到模板中,但您可以覆盖它以发送更多:

from django.views.generic import DetailView
from books.models import Book, Publisherclass PublisherDetail(DetailView):model = Publisherdef get_context_data(self, **kwargs):# Call the base implementation first to get a contextcontext = super().get_context_data(**kwargs)# Add in a QuerySet of all the bookscontext['book_list'] = Book.objects.all()return context

注意
通常,get_context_data将所有父类的上下文数据与当前类的上下文数据合并。要在您想要更改上下文的类中保留此行为,您应该确保调用超类的 get_context_data。当没有两个类尝试定义相同的键时,这将给出预期的结果。但是,如果任何类在父类设置它之后尝试覆盖键(在调用super之后),那么该类的任何子类还需要在super之后显式设置它,如果他们想要确保覆盖所有父项。如果遇到问题,请查看视图的方法解析顺序。

另一个考虑因素是来自基于类的通用视图的上下文数据将覆盖上下文处理器提供的数据; 看 get_context_data()。

译者注
DetailView是显示每条数据的,所以,url里应该这么配置

path('views4/<int:pk>/',PublisherDetailView.as_view(),name='cbv_detail_view'),

在html中可以使用添加的额外数据:

<ul>{% for b in book_list %}<li>{{ b.title }} - {{ b.price }}</li>{% endfor %}</ul>

5. 查看对象的子集

现在让我们仔细看看model参数。该model参数指定了视图将对其进行操作的数据库模型,该参数可用于对单个对象或对象集合进行操作的所有通用视图。但是,model参数不是指定视图将操作的对象的唯一方法 - 您还可以使用queryset参数指定对象列表:

from django.views.generic import DetailView
from books.models import Publisherclass PublisherDetail(DetailView):context_object_name = 'publisher'queryset = Publisher.objects.all()

实际上指定model = Publisher只是queryset = Publisher.objects.all()的简写。但是,通过使用queryset定义过滤的对象列表,您可以更加具体地了解在视图中可见的对象(请参阅 执行查询 以获取有关QuerySet对象的更多信息,并查看基于类的视图参考 以获取完整的详细信息)。

要选择一个简单的示例,我们可能希望按发布日期订购图书列表,最新的第一个:

from django.views.generic import ListView
from books.models import Bookclass BookList(ListView):queryset = Book.objects.order_by('-publication_date')context_object_name = 'book_list'

这是一个非常简单的例子,但它很好地说明了这个想法。当然,您通常希望做的不仅仅是重新排序对象。如果要显示特定发布者的书籍列表,可以使用相同的技巧:

from django.views.generic import ListView
from books.models import Bookclass AcmeBookList(ListView):context_object_name = 'book_list'queryset = Book.objects.filter(publisher__name='ACME Publishing')template_name = 'books/acme_list.html'

请注意,除了过滤queryset之外,我们还使用了自定义模板名称。

另请注意,这不是一种非常优雅的显示出版商特定书籍的方式。如果我们想要添加另一个发布者页面,我们在URLconf中需要另外一些行,并且不止一些发布者会变得不合理。我们将在下一节讨论这个问题。

注意
如果您在请求/books/acme/时获得404,请检查以确保您确实拥有名为“ACME Publishing”的发布者。对于此种情况,通用视图提供了allow_empty参数。有关更多详细信息,请参阅 基于类的视图参考。

6. 动态过滤

另一个常见的需求是通过URL中的某个键过滤列表页面中给出的对象。之前我们在URLconf中对发布者的名称进行了硬编码,但是如果我们想编写一个显示某个任意发布者的所有书籍的视图呢?

很方便,我们可以覆盖ListView中的 get_queryset()方法。以前,它刚好返回queryset属性的值 ,但现在我们可以添加更多逻辑。

使这项工作的关键部分是,当调用基于类的视图时,self中存储各种有用的东西; 如request(self.request),它包括根据URLconf捕获的 self.argsself.kwargs参数。

在这里,我们有一个带有单个捕获组的URLconf:

# urls.py
from django.urls import path
from books.views import PublisherBookListurlpatterns = [path('books/<publisher>/', PublisherBookList.as_view()),
]

接下来,我们将编写PublisherBookList视图:

# views.py
from django.shortcuts import get_object_or_404
from django.views.generic import ListView
from books.models import Book, Publisherclass PublisherBookList(ListView):template_name = 'books/books_by_publisher.html'def get_queryset(self):self.publisher = get_object_or_404(Publisher, name=self.kwargs['publisher'])return Book.objects.filter(publisher=self.publisher)

如您所见,在查询集选择中添加更多逻辑非常容易; 如果我们想要,我们可以使用self.request.user过滤当前用户或其他更复杂的逻辑操作。

我们也可以同时将发布者添加到上下文中,因此我们可以在模板中使用它:

# ...def get_context_data(self, **kwargs):# Call the base implementation first to get a contextcontext = super().get_context_data(**kwargs)# Add in the publishercontext['publisher'] = self.publisherreturn context

7. 执行额外的工作

我们将看到的最后一个常见模式涉及在调用通用视图之前或之后做一些额外的工作。

想象一下,我们的Author模型上有一个 last_accessed 字段,我们用它来跟踪上次有人看过那个作者:

# models.py
from django.db import modelsclass Author(models.Model):salutation = models.CharField(max_length=10)name = models.CharField(max_length=200)email = models.EmailField()headshot = models.ImageField(upload_to='author_headshots')last_accessed = models.DateTimeField()

通用视图DetailView类对此字段一无所知,但我们可以再次轻松编写自定义视图以更新该字段。

首先,我们需要在URLconf中添加一个作者详细信息位以指向自定义视图:

from django.urls import path
from books.views import AuthorDetailViewurlpatterns = [#...path('authors/<int:pk>/', AuthorDetailView.as_view(), name='author-detail'),
]

然后我们编写新的视图 - get_object是检索对象的方法 - 所以我们简单地覆盖它并包装调用:

from django.utils import timezone
from django.views.generic import DetailView
from books.models import Authorclass AuthorDetailView(DetailView):queryset = Author.objects.all()def get_object(self):obj = super().get_object()# Record the last accessed dateobj.last_accessed = timezone.now()obj.save()return obj

注意
此处的URLconf使用命名组 pk- 此名称是DetailView用于查找用于过滤查询集的主键值的默认名称
如果要将该组调用为其他内容,可以 在视图上设置pk_url_kwarg,更多细节可以在 DetailView参考文献中找到。

Django 2.1.3 视图层 内置CBV通用视图相关推荐

  1. Tornado-02-Tornado、路由进阶、视图进阶(视图中内置的钩子方法、视图方法调用顺序、冲刷缓存、用户认证)、模板语法(基本语法、内置标签或函数)

    Tornado 一.路由进阶 路由语法和参数 在路由列表的路由成员中,我们一共可以设置4个参数 url(r"/uri路径", 视图类, {"参数名":" ...

  2. 视图层详解,cbv和fbv,文件上传

    day64 一.复习 二.视图层之请求对象 三.视图层之响应对象 补充知识之json序列化与反序列化 四.cbv和fbv 五.文件上传 六.postman软件 七.form表单,提交地址 八.Pych ...

  3. 【微信小程序】echarts视图层会悬浮在所有视图之上问题原因

    问题:小程序使用下拉菜单时,echarts视图层会悬浮在所有视图之上问题 项目场景: 小程序使用echarts视图层会悬浮在所有视图之上问题原因 问题描述: 真机调试时小程序使用echarts视图层会 ...

  4. django redirect传递参数_Django 视图层(四):视图函数 - views.py

    介绍 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图 ...

  5. MySQL内置函数存储过程视图JDBC

    MySQL存储过程&视图&JDBC-笔记 回顾 能够使用内连接进行多表查询 SELECT * FROM 表1 , 表2 WHERE 条件; SELECT * FROM 表1 INNER ...

  6. 前端ui框架layui——layer弹出层-内置方法

    提示:本页内容所展示的内置方法是除了所有弹出方法(eg:layer.open)以外的,想看弹出方法请到这里 --------内置方法---------- 1.layer.config(options) ...

  7. django 1.8 官方文档翻译: 3-4-2 基于类的内建通用视图

    基于类的内建通用视图 编写Web应用可能是单调的,因为你需要不断的重复某一种模式. Django尝试从model和 template层移除一些单调的情况,但是Web开发者依然会在view(视图)层经历 ...

  8. 深入Django(1): 通用视图 (generic views)

    如果对Django的基础部分尚不熟悉,请参考<Django实战>系列. 内容提要 1. 回顾Django的视图函数(view function) 2. 在视图函数中使用模板 3. 简化视图 ...

  9. dmv 统计数据库io_使用内置功能和动态管理视图(DMV)发现特定于数据库的信息

    dmv 统计数据库io 介绍 (Introduction) In the last two articles on dynamic management views in SQL Server, Di ...

最新文章

  1. C# Attribute简介
  2. Distributed Configuration Management Platform(分布式配置管理平台)
  3. Go Web学习(2)——实现中间件(middleware)
  4. ubuntu 循环登录问题,
  5. 洛谷P3902 递增
  6. 精心设计的基于组件的C# Win Forms实践 一个框架数据库驱动多个业务逻辑数据库...
  7. this全面解析, 如何定位this指向,一文总结,再也不怕面试官追问啦
  8. hex文件格式解析_玩转Hex文件
  9. MyEclipse打包jar 并加入第三方包
  10. 如何计算java对象占用的内存
  11. c语言人事管理系统,c语言人事管理系统
  12. 好程序员分享js实现简单的板球游
  13. 山寨机java游戏下载_Q版水浒-山寨英雄
  14. STM32开发(2)----CubeMX的安装和使用
  15. PyCharm4注册码
  16. Android实现动态贴纸,Android开发之仿微博贴纸效果实现——进阶篇
  17. 什么是websocket
  18. NPI (Neural Program Interpreter) 逆波兰表达式--什么是逆波兰表达式
  19. Python自动登录淘宝
  20. 公钥 私钥 数字签名 CA证书

热门文章

  1. 全国彩礼地图分析,江西福建等地彩礼均30万以上
  2. jsp成绩单综合设计
  3. python?java?都能制作自己的植物大战僵尸!
  4. java二嗨租车项目_Java入门第二季6-1项目问题 —嗒嗒租车系统(参考各位大神的思路写出来的)...
  5. 测试人员如何使用浏览器的f12_如何使用 F12 开发人员工具调试网页
  6. 封装一个抽象类 Shape,其中包括有求形状面积的抽象方法getArea()和求 形状周长的非抽象方法getPerimeter()。
  7. Stable Diffusion 多人绘画经验札记
  8. spring进阶第三天之AOP
  9. jenkins构建UNSTABLE原因及解决方案一二三四五(不断更新中。。。)
  10. 【Minecraft java edition 模组开发】(一):实现一个简单的模组