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>

验证:

posted @ 2024-05-04 11:26  chuangzhou  阅读(8)  评论(0编辑  收藏  举报