跳到主要内容

类视图的使用

· 阅读需 4 分钟
Jason Lee
The owner of this blog site

前言

对于类视图和函数视图,在我初学 django 的时,有过这样的迷思:自己定义的类视图似乎和函数视图没有太大的区别,无非就是判断请求方式的时候,CBV 用函数,FBV 用if...else...。而如果上了框架提供的通用类视图,代码风格似乎过于抽象,且不灵活,无法完全替代函数视图。今天,就以刚刚用函数视图完成的项目为例,尝试将所有函数视图转为类视图,看看过程中有什么新的感悟。

通用类视图里的方法

添加额外的上下文:

def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super().get_context_data(**kwargs)
# Add in a QuerySet of all the books
context["book_list"] = Book.objects.all()
return context

根据 url 内传来的 query 参数来动态查询

这项工作的关键部分是当基于类的视图被调用的时候,各种常用的东西被存储在 self 上,而且请求 (self.request) 根据 URLconf 抓取位置(self.args) 和基于名称 (self.kwargs) 的参数。

def get_queryset(self):
self.publisher = get_object_or_404(Publisher, name=self.kwargs["publisher"])
return Book.objects.filter(publisher=self.publisher)

执行额外的任务

class AuthorDetailView(DetailView):
queryset = Author.objects.all()

def get_object(self):
obj = super().get_object()
# Record the last accessed date
obj.last_accessed = timezone.now()
obj.save()
return obj

通用类视图到底为开发者默认做了哪些事

django 框架内置的通用类视图之所以能少些很多代码,很明显是它有一些默认行为。那么这里就记录一下各种常见内置视图的默认行为。

FormView

class ContactFormView(FormView):
template_name = "contact.html"
form_class = ContactForm
success_url = "/thanks/"

def form_valid(self, form):
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
form.send_email()
return super().form_valid(form)

表单视图的一般行为是判断请求方式,如果是 post,就检验字段有效性,且把错误返回给浏览器,成功则重定向;如果是 get 就返回待填写的表单。

所以,FormView 就是通过暴露一些简单的配置给开发者,比如 template_name,其他行为会自动完成。如果有特殊需求,重写 get 或 post 方法。form_valid 是执行表单验证之后的程序。

form_valid 函数是一定要重写的,这也说明 django 文档里一般都是最小实现形式,不能减少。

总结

  • 类视图完全可以替代函数视图。
  • 优先用内置的通用类视图,首先确认任务类型,如果是展示类,就考虑 ListView、DetailVIew;如果是修改类,就是 CreateView、UpdateView、DeleteView。
  • 修改类的通用视图,注意表单相关项。运用上面提到的三个函数,可以实现较复杂的需求。
  • 如果不方便,也可以不用内置视图,而采用根据请求方式划分方法,比如 get 请求。
  • 类视图在采用了内置类的写法后,代码会变少;但更重要的意义是,增加了代码重用的可能性。比如,另外一个 views.py 可以继承过来。