Django - 探究CBV视图
为了减少痛苦,Django 植入了视图类这一功能,该功能封装了视图开发的常用代码,无须编写大量代码即可快速完成数据视图开发,这种以类形式实现响应与请求处理称为CBV(Class Base Views)
根据用途划分为3部分:数据显示视图、数据操作视图、日期筛选视图
数据显示视图
基础视图 TemplateView
视图类TemplateView 是所有视图类里最基础的应用视图类,开发者可以直接调用应用视图类,它继承多个父类
class TemplateView(TemplateResponseMixin, ContextMixin, View):
"""
Render a template. Pass keyword arguments from the URLconf to the context.
"""
def get(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
return self.render_to_response(context)
从源码看到,它只定义了get 方法,分别调用 get_context_data 和 render_to_response ,从而完成HTTP请求的响应过程。
- get_context_data 属于父类 ContextMixin:用于获取模板上下文内容,模板上下文是将视图里的数据传递到模板文件,再由模板引擎将数据转换成HTML网页数据
- render_to_response 属于父类 TemplateResponseMixin: 用于实现响应处理,由响应类 TemplateResponse 完成。
案例:
# index\urls.py
from index.views import *
urlpatterns = [
path('', index.as_view(), name='index')
]
# index\views.py
from django.views.generic import TemplateView
class index(TemplateView):
template_name = 'index.html'
template_engine = None
content_type = None
extra_context = {'title': 'this is a GET'}
# 覆盖父类方法,修改上下文数据
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['value'] = 'I am MyDjano index'
return context
# 定义 http post 请求的处理方法,若路由设置由变量,则可从参数kwargs获取
def post(self, request, *args, **kwargs):
self.extra_context = {'title': 'this is a POST'}
context = self.get_context_data(**kwargs)
return self.render_to_response(context)
# templatges\index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>Hello, {{title}}</h2>
<form action="" method="post">
<input type="submit" , value="Submit">
</form>
</body>
</html>
上述代码是将网站首页的视图函数index 改为视图类 index,自定义视图类 index继承视图类 TemplateView ,并重设了4个属性,重写了两个类方法,具体说明如下:
- template_name:将模板文件index.html 作为网页文件
- template_engine: 设置解析模板文件的模板引擎,默认值为None。即默认使用配置文件setting.py 的 TEMPLATES 所设置的模板引擎BACKEND
- content_type: 设置响应数据内容的数据格式,默认值为None,即代表数据格式为text/html
- extra_context: 为模板文件的上下文设置变量值,可将数据转换成网页数据展示在浏览器上
- get_context_data():继承并重写视图类 TemplateView 的方法,在变量context 里新增数据value
- post():自定义 POST 请求的处理方法,当触发POST 请求时,将会重设extra_context 的值,并调用get_context_data() 将extra_context的值重新写入,从而实现动态改变模板上下文的数据内容
在模板文件index.html 里看到模板上下文{{title}} 和{{value}},它们的数据来源于get_context_data() 的返回值
验证:
请求http://localhost:8001/, 走父类的GET方法,extra_context 未被修改:
点击Submit,走index 定义的post,修改extra_context,获取响应:
列表视图 ListView
视图是连接路由和模板的中心枢纽,初次之外,视图还可以连接模型。简单来说,模型是指DDjango 通过一定规则来映射数据库,从而方便Django 与 数据库之间实现数据交互,这个交互过程是在视图里实现的。因此Django定义了视图类ListView,该视图类是将数据表的数据以列表的形式显示,常用于数据的查询和展示。
class ListView(MultipleObjectTemplateResponseMixin, BaseListView):
"""
Render some list of objects, set by `self.model` or `self.queryset`.
`self.queryset` can actually be any iterable of items, not just a queryset.
"""
它具有视图类TemplteView 的所有属性和方法,因为两者的底层类是相同的,新增了以属性和方法:
- allow_empty: 由 MultipleObjectMixin 定义, 在模型查询数据不存在的情况下是否显示页面,若为False 并且数据不存在,则引发404,默认为True
- queryset:由 MultipleObjectMixin 定义,代表模型的查询对象,这是对模型对象进行查询操作所生成的查询对象
- model: 由 MultipleObjectMixin 定义,代表模型,模型以类表示,一个模型一个张数据表
- paginate_by: 由 MultipleObjectMixin 定义,属性值为整数,代表一页所显示的数据量
- conext_object_name: 由 MultipleObjectMixin 定义,设置模板上下文,即为模板上下文变量进行命名,
- paginator_class:由 MultipleObjectMixin 定义,设置分页的功能类,默认情况下使用内置分页功能.django.core.paginator.Paginator
- get_context_object_name(): 由 MultipleObjectMixin 定义。获取模板上下文的名称。若conext_object_name 未设置,则上下文名称由模型名称的小写+'_list' 表示
- get_conext_data(): 由 MultipleObjectMixin 定义,获取模板上下文的数据内容
虽然视图类ListView 定义了多个属性和方法,但实际开发中经常使用的属性和方法并不多。由于视图类ListView 需要使用模型对象,因此在MyDjango 项目里定义PersonInfo模型,在index\models.py 中编写以下代码:
from django.db import models
class PersonInfo(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=20)
age = models.IntegerField()
以上只是创建了Perinfo类和数据库表personinfo 的映射关系,但在数据库中并没有生成相应的数据表。因此,下一步,通过两者的映射关系在数据库里生成相应的数据表。
# 根据models.py 生成相关的.py文件,该文件用于创建数据库表
(venv) PS E:\PyProject\MyDjango> python manage.py makemigrations
Migrations for 'index':
index\migrations\0001_initial.py
- Create model PersonInfo
# 创建数据库表
(venv) PS E:\PyProject\MyDjango> python manage.py migrate
System check identified some issues:
WARNINGS:
?: (mysql.W002) MySQL Strict Mode is not set for database connection 'default'
HINT: MySQL's Strict Mode fixes many data integrity problems in MySQL, such as data truncation upon insertion, by escalating warnings into errors. It is strongly recommend
ed you activate it. See: https://docs.djangoproject.com/en/5.0/ref/databases/#mysql-sql-mode
Operations to perform:
Apply all migrations: admin, auth, contenttypes, index, sessions
Running migrations:
Applying index.0001_initial... OK
准备工作完毕,有以下需求:查出index_personinfo 表数据回显到页面并支持分页
# index\views.py
from .models import PersonInfo
class index(ListView):
template_name = 'index.html'
# 设置模型外的数据
extra_context = {'title': '人员信息表'}
# 查询模型PersonInfo
queryset=PersonInfo.objects.all()
# 每页展示1条数据
paginate_by = 1
# 若不设置,模板上下文默认为
#context_object_name = 'personinfo'
# templates\index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{title}}</title>
</head>
<body>
<h2>{{title}}</h2>
<table border="1">
{% for item in personinfo_list %}
<tr>
<th>{{item.name}}</th>
<th>{{item.age}}</th>
</tr>
{% endfor%}
</table>
<br>
{% if is_paginated %}
<div class="pagination">
<span class="page-links">
{% if page_obj.has_previous %}
<a href="/?page={{page_obj.previous_page_number}}">上一页</a>
{% endif %}
{% if page_obj.has_next %}
<a href="/?page={{ page_obj.next_page_number}}">下一页</a>
{% endif %}
<br>
<br>
<span clas="page-current">
第{{page_obj.number}}页,
共{{page_obj.paginator.num_pages}} 页.
</span>
</span>
</div>
{% endif%}
</body>
</html>
验证:
本文来自博客园,作者:chuangzhou,转载请注明原文链接:https://www.cnblogs.com/czzz/p/18172131