[Django] Django(六) 通用视图ListView和DetailView

基于类的视图概述

在Django视图刚开始创建时,通过在app/views.py中定义一个函数来表示一个视图,获取用户的请求并进行响应,这种方式的最大缺点是重用性差,因此,除了通过函数来定义一个视图之外,还可以通过类来定义一个视图。和视图函数相比,基于类的视图有以下两个特点:

  • 1.HTTP请求通过特定的方法处理,不需要通过条件语句判断。比如如果是函数视图:
from django.http import HttpResponse

def my_view(request):
    if request.method == 'GET':
        # <view logic>
        return HttpResponse('result')

如果使用类视图:

from django.http import HttpResponse
from django.views import View

class MyView(View):
    def get(self, request):
        # <view logic>
        return HttpResponse('result')
  • 2.由于Python支持多继承,通过mixins可以增强复用性

Django中提供了多种通过视图API,如TemplateView、RedictView、ListView,它们的父类都是View,通过继承这些类,覆盖类中的属性可以提供新的值或方法。
由于在请求时,url解析器会将请求和参数发送到一个方法中进行,比如函数视图。因此,每个类视图都带有一个as_view()方法,用于将类视图转换为一个可调用函数。类视图的UrlConf如下:

urlpatterns = [
    path('myview/',views.MyView.as_view(), name='my_view'),
]

as_view()方法会返回一个函数来处理请求和响应,还可以将类视图中定义的属性作为该方法参数,覆盖类视图中的属性值。
下面对基于类的视图分类进行下总结归纳。

基本视图

基本视图包括三类:View、TemplateView和RedirectView。用户可继承基本类视图来定义视图,所有的通用视图也都继承与这三类基本视图实现,因此相比于通用视图,基本视图提供的功能较少。

View

View是所有类视图的父类,可以直接从from django.views中导入,如:

from django.views import View

class MyView(View):

      def get(self,request):
          pass
as_view()

该方法是一个类方法,被@classonlymethod修饰,是http请求和响应的入口,用于url配置。在Http请求和响应的过程中,会将request对象和其他参数作为参数传入该方法,内部调用dispatch()方法后返回一个Response对象。可用如下形式的代码表示:

response = MyView.as_view()(request)

其他方法:

dispatch()

该方法是HTTP请求响应过程中调用的一个方法,在请求时as_view(),as_view()立即将request对象和其他参数对象传给该方法并调用,随后该方法返回一个HttpResponse对象。

TemplateView

继承结构:

class TemplateView(TemplateResponseMixin, ContextMixin, View):
     pass

TemplateView视图通过给定的模板进行渲染。常用方法和属性如下:

template_name

通过属性template_name指定一个模板,使用TemplateView时必须指定一个模板文件,否则在运行时出现ImproperlyConfigured异常。

get_template_names()

除了使用template_name指定模板文件,也可通过该方法指定模板文件:

    def get_template_names(self):
        return "student_template.html"
get_context_data()

该方法返回一个代表模板上下文的字典,因此可以利用该方法添加上下文信息,上下文是一个包含给定的参数的字典,如:

class StudentTemplate(TemplateView):

    template_name = "student_template.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
    # 上下文中添加一个number
        context['number'] = random.randrange(0,100)
        return context
extra_context

除了在get_context_data()中添加上下文信息外,也可以在url配置时在as_view()方法中指定extra_context属性来添加上下文信息,如:

from . import views

urlpatterns = [
    path('StudentTemplate/', views.StudentTemplate.as_view(extra_context={"summary": "Big news"})),
]
get()

GET请求时会调用该方法,该方法原型如下:

    def get(self, request, *args, **kwargs):
        context = self.get_context_data(**kwargs)
        return self.render_to_response(context)
render_to_response()

该方法返回一个HttpResponse对象。

RedirectView

暂略

通用显示视图

由于Python支持多继承,因此,通用显示视图继承于包括基础视图的多个类,用于显示数据,有两类:ListView和DetailView。

ListView

ListView,用于显示一个对象列表的视图,包含一个属性值object_list,表示对象的列表。因此在模板文件中可以通过遍历该属性来显示model的所有数据,如:

from django.views.generic import ListView

class StudentList(ListView):
    model = Student
    template_name = "student_list.html"

    def get_context_data(self, *, object_list=None, **kwargs):
        context = super().get_context_data(**kwargs)
        context['number'] = random.randrange(1, 100)
        return context

常用属性、方法总结如下:

model =

该属性用来指定要显示的model。在该例中,model = Student相当于:

querySet = Student.objects.all()

表示将会把所有model中的记录提供给模板显示,因此,如果要显示满足条件的记录,可以通过如下方式提供指定数据,并存储在queryset属性中,比如要显示model中姓名为‘zhangsan’的人,而不是所有人,可以将model = Student修改为:

queryset = Student.objects.filter(name='zhangsan')
queryset

该属性表示该视图显示项的集合,可以通过get_queryset()方法来进行定义。

get_queryset()

该方法得到一个该视图显示项的集合,在方法内部实际上是对queryset的操作,返回值必须是可迭代的,或者是QuerySet,比如:

from django.shortcuts import get_object_or_404

    def get_queryset(self):
        stulist = []
        stulist.append(get_object_or_404(Student, name='Zhangsan'))
        return stulist

由于Student不可迭代,因此返回一个可迭代的list集合,相当于:

queryset = Student.objects.filter(name='zhangsan')
template_name =

template_name表示要使用的模板,如果不指定模板,则对于ListView来说,会自动推断模板名, 使用名为<appname>/<modelname>_list.html的默认模板,不存在则出现TemplateDoesNotExist。

object_list

指定模板后,再来看看模板文件中如何显示通用视图中的数据:

{% block content %}
    <h2>Student</h2>
    <ul>
        {% for student in object_list %}
        <li>
             {{student.name }}
        </li>
        {% endfor %}
        <li>
            {{number}}
        </li>
    </ul>

{% endblock %}

在刚开始已经说过了,ListView中的object_list属性中,存放了model中要显示的记录(或者说model对象),因此可以通过遍历object_list属性直接获取即可显示。

context_object_name

在模板中使用object_list是一个不太友好的方法,因为不知道object_list具体指的是哪个模板的数据,因此在通用视图中还提供了一个属性:context_object_name来制定一个上下文,如:

class showStu(ListView):
    ...
    context_object_name = "student"

在模板文件中,就可使用student来替换object_list,当然object_list依旧是可用的。
通常使用model的小写字母来赋值context_object_name

DetailView

DetailView用于显示一个特定类型对象的详细信息。DetailView的大部分属性和方法和ListView相同。不同的是该视图没有object_list属性,因为该视图负责显示一个特定对象的详细信息,因此有一个object属性,表示model的一个对象(或一条记录)。

get_context_data()

该方法返回视图的上下文,在ListView中,即返回的是object_list,在DetailViewView,则返回object对象。如果要使用该视图显示model中的所有对象(或记录),则可以通过get_context_data()方法返回上下文,将所有对象信息添加到上下文中,也可以添加其他信息到上下文中,如:

from django.views.generic import DetailView

class ShowStuDetail(DetailView):
    model = Student
    template_name = "show_stu_detail.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
    # 添加一个上下文信息
        context["number"] = random.randrange(10)
        return context
object

在模板中,可以通过object来获取详细信息,如:

<h2>name:{{object.name}}</h2>
<h2>age:{{object.age}}</h2>
get_object()

该方法返回要显示的对象,即object,如果提供了queryset,则queryset将作为该方法返回值。因此,如果需要修改要显示对象的信息,可以通过该方法,如:

 def get_object(self):
        # Call the superclass
        object = super().get_object()
        # 修改属性值
        object.last_accessed = timezone.now()
        object.save()
        # Return the object
        return object

在配置URL时,DetailView 期望从URL中捕获名为 “pk” 的主键值,所以DetailView的url配置一般为这种形式:

path('<int:pk>/', views.QuestionDetailView.as_view(), name='detail'),

默认情况下,DetailView 使用<appname>/<model name>_detail.html的模板,如果没有该模板,则应该通过”template_name”指定一个模板。

猜你喜欢

转载自blog.csdn.net/fightfightfight/article/details/80038569