CBV视图--数据显示视图


数据显示视图

数据显示视图是将后台的数据展示在网页上,数据主要来自模型,一共定义了四个视图类。

  • RedirectView:用于实现HTTP重定向,默认只定义了GET请求的处理方法。
  • TemplateView:视图类的基础视图,可将数据传递给HTML模板,默认只定义了GET请求的处理方法。
  • ListView:在TemplateView的基础上将数据以列表显示,通常将某个数据表的数据以列表表示。
  • DetailView:在在TemplateView的基础上将数据详细展示,通常获取数据表的单条数据。

1.重定向视图RedirectView

RedirectView用于实现HTTP重定向功能,即网页跳转功能。在Django的源码内可以看到RedirectView的定义过程。从源码中可以看到RedirectView类,定义了四个属性和八个类方法。

class RedirectView(View):
    """Provide a redirect on any GET request."""

    permanent = False
    url = None
    pattern_name = None
    query_string = False

    def get_redirect_url(self, *args, **kwargs):
        """
        Return the URL redirect to. Keyword arguments from the URL pattern
        match generating the redirect request are provided as kwargs to this
        method.
        """
        if self.url:
            url = self.url % kwargs
        elif self.pattern_name:
            url = reverse(self.pattern_name, args=args, kwargs=kwargs)
        else:
            return None

        args = self.request.META.get("QUERY_STRING", "")
        if args and self.query_string:
            url = "%s?%s" % (url, args)
        return url

    def get(self, request, *args, **kwargs):
        url = self.get_redirect_url(*args, **kwargs)
        if url:
            if self.permanent:
                return HttpResponsePermanentRedirect(url)
            else:
                return HttpResponseRedirect(url)
        else:
            logger.warning(
                "Gone: %s", request.path, extra={"status_code": 410, "request": request}
            )
            return HttpResponseGone()

    def head(self, request, *args, **kwargs):
        return self.get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.get(request, *args, **kwargs)

    def options(self, request, *args, **kwargs):
        return self.get(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.get(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        return self.get(request, *args, **kwargs)

    def patch(self, request, *args, **kwargs):
        return self.get(request, *args, **kwargs)

其中

  • permanent:根据属性值的真假来选择重定向的方式,若为True,则HTTP状态码为301,False则为302。
  • url:代表重定向的路径。
  • pattern_name:代表重定向的路由命名,若已经设置了url,则不用设置该参数。
  • query_string:是否将当前路由地址的请求参传递到重定向的路由地址。
  • get_redirect_url():根据属性pattern_name所指向的路由命名来生成相应的路由地址。
  • get():触发HTTP的GET请求所执行的响应处理。
  • 其余类方法:是HTTP的不同请求方式,都由get()方法完成响应处理。
# app的urls.py
from django.urls import path
from . import views
urlpatterns = [
    path('', views.index, name='index'),
    path('turnTo/', views.turmTO.as_view(), name='turnTo'),
]
# app的views.py
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
from django.views.generic import RedirectView


def index(request):
    return HttpResponse('hello world')


class turmTO(RedirectView):
    permanent = False
    url = None
    pattern_name = 'index:index'
    query_string = False

    def get_redirect_url(self, *args, **kwargs):
        url = super().get_redirect_url(*args, **kwargs)
        print(url)
        return url
# index.html模板
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Redirect View</title>
</head>
<body>
<a href="{% url 'index:turnTo' %}">turn</a>
</body>
</html>

在app中定义了视图类turnTo,它继承父类RedirectView,对父类的属性和类方法进行重写,通过这样的方式可以扩展RedirectView的功能,从而满足开发需求。在定义路由时,使用视图类处理HTTP请求,则需要对视图类使用.as_view()方法(对视图类进行实例化处理),在开发时若需要对其他的HTTP请求进行处理,那么只需要重新定义相应的类方法即可。运行Django项目以上代码,可见

September 16, 2022 - 22:54:47
Django version 4.1.1, using settings 'djangoProject.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
[16/Sep/2022 22:54:48] "GET / HTTP/1.1" 200 11
redirect to /
[16/Sep/2022 22:54:51] "GET /turnTo/ HTTP/1.1" 302 0
[16/Sep/2022 22:54:51] "GET / HTTP/1.1" 200 11

2.基础视图TemplateView

视图类是所有视图类中的最基础的应用视图类,开发者可以直接调用应用视图类。它继承于多个父类,TemplateResponseMixin,ContextMixin和View,以下是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()方法中所调用的方法来自TemplateResponseMixin,ContextMixin。

  • ContextMixin类中的get_context_data()方法用于获取模板上下文内容,模板上下文是将视图里的数据传递到模板文件,再由模板引擎转换为HTML网页数据。
  • TemplateResponseMixin类中的render_to_response()方法用于实现响应处理,由响应类TemplateResponse处理。下面是TemplateResponseMixin类的定义。

    class TemplateResponseMixin:
        """A mixin that can be used to render a template."""
    
        template_name = None
        template_engine = None
        response_class = TemplateResponse
        content_type = None
    
        def render_to_response(self, context, **response_kwargs):
            """
            Return a response, using the `response_class` for this view, with a
            template rendered with the given context.
    
            Pass response_kwargs to the constructor of the response class.
            """
            response_kwargs.setdefault("content_type", self.content_type)
            return self.response_class(
                request=self.request,
                template=self.get_template_names(),
                context=context,
                using=self.template_engine,
                **response_kwargs,
            )
    
        def get_template_names(self):
            """
            Return a list of template names to be used for the request. Must return
            a list. May not be called if render_to_response() is overridden.
            """
            if self.template_name is None:
                raise ImproperlyConfigured(
                    "TemplateResponseMixin requires either a definition of "
                    "'template_name' or an implementation of 'get_template_names()'"
                )
            else:
                return [self.template_name]
    
    • template_name = None:设置模板文件的文件名
    • template_engine = None:设置模板文件的模板引擎
    • response_class = TemplateResponse:设置HTTP请求的响应类,默认为TemplateResponse类
    • content_type = None:设置响应内容的数据格式
    • render_to_response():实现响应处理
    • get_template_names():获取属性template_name的值
# app的urls.py

from django.urls import path
from . import views
urlpatterns = [
    path('', views.index.as_view(), name='index'),
]
# app 的views.py

from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
from django.views.generic import RedirectView, TemplateView


class index(TemplateView):
    template_name = 'index.html'
    template_engine = None
    content_type = None
    extra_context = {'title': 'this is get'}

    def get_context_data(self, **kwargs):
        context = super(index, self).get_context_data(**kwargs)
        context['name'] = 'ronie'
        return context

    def post(self, request, *args, **kwargs):
        self.extra_context['title'] = 'this is post'
        print('set post')
        return self.render_to_response(self.get_context_data(**kwargs))
!! index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Redirect View</title>
</head>
<body>
<h1>{{ title }}</h1>
<h1>{{ name }}</h1>
<form action="" method="post">
    {% csrf_token %}
    <input type="submit" value="submit">
</form>
</body>
</html>

上述代码将网站首页的index视图函数改为index视图类,自定义视图类index继承自TemplateView类,重设了四个属性,重写了两个类方法。

  • template_name:设置模板文件的index.html
  • template_engine:设置模板文件的模板引擎
  • content_type:设置响应内容的数据格式,none即代表数据为默认的text/html
  • get_context_data():继承并重写视图类TemplateView的类方法,在变量context里自定义name
  • post():自定义post()请求的处理方法,当触发post请求时,重设属性值,并调用get_context_data()将属性extra_context写入,动态的改变模板的内容。

当使用get访问时

当使用点击post,使用post访问时

bash信息

September 17, 2022 - 19:39:26
Django version 4.1.1, using settings 'djangoProject.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
[17/Sep/2022 19:39:27] "GET / HTTP/1.1" 200 372
set post
[17/Sep/2022 19:40:16] "POST / HTTP/1.1" 200 373

3.列表视图ListView

视图是连接模板和路由的中心枢纽,同时视图还可以连接模型。模型指Django通过一定的规则来映射数据库,从而方便Django与数据库的交互。因为Django可以通过一定的规则来映射数据库,因此Django提供了视图类ListView,该视图类将数据表的数据以列表的形式显示,常用于数据库的查询。以下通过源码分析ListView的定义过程:

class MultipleObjectMixin(ContextMixin):
   """A mixin for views manipulating multiple objects."""

    allow_empty = True
    queryset = None
    model = None
    paginate_by = None
    paginate_orphans = 0
    context_object_name = None
    paginator_class = Paginator
    page_kwarg = "page"
    ordering = None

    def get_queryset(self):
        """
        Return the list of items for this view.

        The return value must be an iterable and may be an instance of
        `QuerySet` in which case `QuerySet` specific behavior will be enabled.
        """
        
    def get_ordering(self):
        """Return the field or fields to use for ordering the queryset."""

    def paginate_queryset(self, queryset, page_size):
        """Paginate the queryset, if needed."""

    def get_paginate_by(self, queryset):
        """
        Get the number of items to paginate by, or ``None`` for no pagination.
        """

    def get_paginator(
        self, queryset, per_page, orphans=0, allow_empty_first_page=True, **kwargs
    ):
        """Return an instance of the paginator for this view."""

    def get_paginate_orphans(self):
        """
        Return the maximum number of orphans extend the last page by when
        paginating.
        """

    def get_allow_empty(self):
        """
        Return ``True`` if the view should display empty lists and ``False``
        if a 404 should be raised instead.
        """

    def get_context_object_name(self, object_list):
        """Get the name of the item to be used in the context."""

    def get_context_data(self, *, object_list=None, **kwargs):
        """Get the context for this view."""
        
        
class BaseListView(MultipleObjectMixin, View):
    """A base view for displaying a list of objects."""
    def get(self, request, *args, **kwargs):
    
class MultipleObjectTemplateResponseMixin(TemplateResponseMixin):
    """Mixin for responding with a template and list of objects."""

    template_name_suffix = "_list"

    def get_template_names(self):
        """
        Return a list of template names to be used for the request. Must return
        a list. May not be called if render_to_response is overridden.
        """
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.
    """

根据以上的继承关系可知,ListView的底层类是由TemplateResponseMixin,ContextMixin和View组成的,在这些底层类的基础上加入了模型的操作方法。通过分析得知,ListView类具有TemplateView类的全部属性和方法,此外i还新增了属性和方法。

  • allow_empty = True:在模型查询数据不存在指导情况下是否显示页面,默认为True,若为false且数据不存在,则引发404异常。
  • queryset = None:代表模型的查询对象,这是对模型对象进行查询操作所生成的查询对象。
  • model = None:代表模型,一个模型代表一个数据表。
  • paginate_by = None:代表每一页显示的数据量。
  • paginate_orphans = 0:代表最后一页可以包含的溢出的数据量,防止最后一页数据量过少。
  • context_object_name = None:设置模板上下文,即为模板变量命名。
  • paginator_class = Paginator:设置分页的功能类,默认为内置分页Paginator。
  • page_kwarg = "page":设置分页参数名称,默认为page。
  • ordering = None:对属性queryset查询结果进行排序。
  • get_context_data(self, , object_list=None, *kwargs):获取模板上下文(模板变量的内容)。
  • get_context_object_name(self, object_list):设置模板上下文的名称,若未设置,则上下文名称由模型名称+‘_list’表示。
  • get_allow_empty(self):获取属性allow_empty的属性值。
  • get_paginate_orphans(self):获取最后一页可以包含的溢出的数据量。
  • get_paginator():返回当前页数所对应的数据信息。
  • get_paginate_by(self, queryset):获取每一页所显示的数据量。
  • paginate_queryset(self, queryset, page_size):根据queryset的数据来进行分页处理。
  • get_ordering(self):获取属性ordering的值
  • get_queryset(self):获取queryset的值。
  • get(self, request, args, *kwargs):定义HTTP的GET请求处理方式。
  • get_template_names(self):获取属性template_name的值
#  app的urls.py
from django.urls import path
from . import views
urlpatterns = [
    path('', views.index.as_view(), name='index'),
]
# app的views.py
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
from django.views.generic import RedirectView, TemplateView, ListView
from .models import Person


class index(ListView):
    template_name = 'index.html'
    queryset = Person.objects.all()
    extra_context = {'title': 'Person Info'}
    paginate_by = 2
    context_object_name = 'Person'
# app的models.py 记得执行makemigrations  migrate,并向数据库中条件数据
from django.db import models
# Create your models here.

class Person(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=100)
    age = models.IntegerField()
    
!index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Redirect View</title>
</head>
<body>
<h1>{{ title }}</h1>
<table>
    <td>name</td>
    <td>age</td>
    {% for data in Person %}
        <tr>
            <th>{{ data.name }}</th>
            <th>{{ data.age }}</th>
        </tr>
    {% endfor %}
</table>
{% if page_obj.has_previous %}
<a href="/?page={{ page_obj.previous_page_number }}">previous page</a>
{% endif %}
<br>
{% if page_obj.has_next %}
<a href="/?page={{ page_obj.next_page_number }}">next page</a>
{% endif %}

<p>当前{{ page_obj.number }}页</p>
<p>共{{ page_obj.paginator.num_pages }}页</p>
</body>
</html>


4.详细视图DetailView

声明:Hello World|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - CBV视图--数据显示视图


我的朋友,理论是灰色的,而生活之树是常青的!