在Django(四) View基础之函数视图中,通过在app/views.py中定义一个函数来表示一个视图,获取用户的请求并进行响应,这种方式的最大缺点是重用性差,因此,除了通过函数来定义一个视图之外,还可以通过类来定义一个视图。
和函数视图相比,基于类的视图有以下两个特点:
from django.http import HttpResponse
def my_view(request):
if request.method == 'GET':
#
return HttpResponse('result')
如果使用类视图:
from django.http import HttpResponse
from django.views import View
class MyView(View):
def get(self, request):
#
return HttpResponse('result')
Django中提供了多种通过视图API,如TemplateView、RedictView、ListView,它们的父类都是View,通过继承这些类,覆盖类中的属性可以提供新的值或方法。
由于在请求时,url解析器会将请求和参数发送到一个方法中进行。因此,每个类视图都带有一个as_view()
方法,用于将类视图转换为一个可调用函数,在配置url时需要使用as_view()
方法:
urlpatterns = [
path('myview/',views.MyView.as_view(), name='my_view'),
]
as_view()
方法会返回一个函数来处理请求和响应,还可以将类视图中定义的属性作为该方法参数,覆盖类视图中的属性值。
View是所有类视图的父类,包括在之后使用的最重要的DjangoRESTframework中的所有view,都是继承于它。View可以直接从from django.views
中导入:
from django.views import View
class MyView(View):
def get(self,request):
pass
由于Python支持多继承,因此,通用显示视图继承于包括基础视图的多个类,用于显示数据,有两类:ListView和DetailView。
关于Django中的视图,了解到这里就差不多了,以下内容可选。
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 = Student
相当于:
querySet = Student.objects.all()
表示将会把所有model中的记录提供给模板显示,因此,如果要显示满足条件的记录,可以通过如下方式提供指定数据,并存储在queryset属性中,比如要显示model中姓名为‘zhangsan’的人,而不是所有人,可以将model = Student
修改为:
queryset = Student.objects.filter(name='zhangsan')
该属性表示该视图显示项的集合,可以通过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
表示要使用的模板,如果不指定模板,则对于ListView来说,会自动推断模板名, 使用名为
的默认模板,不存在则出现TemplateDoesNotExist。
指定模板后,再来看看模板文件中如何显示通用视图中的数据:
{% block content %}
<h2>Studenth2>
<ul>
{% for student in object_list %}
<li>
{{student.name }}
li>
{% endfor %}
<li>
{{number}}
li>
ul>
{% endblock %}
在刚开始已经说过了,ListView中的object_list
属性中,存放了model中要显示的记录(或者说model对象),因此可以通过遍历object_list属性直接获取即可显示。
在模板中使用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的大部分属性和方法和ListView相同。不同的是该视图没有object_list
属性,因为该视图负责显示一个特定对象的详细信息,因此有一个object
属性,表示model的一个对象(或一条记录)。
该方法返回视图的上下文,在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来获取详细信息,如:
<h2>name:{{object.name}}h2>
<h2>age:{{object.age}}h2>
该方法返回要显示的对象,即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('/' , views.QuestionDetailView.as_view(), name='detail'),
以上虽然只对View、ListView、DetailView进行了总结,但还是有不少废话。其实,只需要通过View了解下类视图长啥样就行了,为什么?因为以后用不到其他的类视图,因为现在web开发前后端分离是趋势,不会使用Django中的模板进行前端的开发。所以应该将主要精力放在Django REST 框架中的View中,这也是之后要学习的重点。