Django 1.6 最佳实践: 怎样正确使用 CBVs (Class-based views)

Class-based views是Django为解决建站过程中的常见的呈现模式而建立的. 在这节中, 我们着重讲一下CBVs的使用技巧和一般原则.

1. CBVs的使用原则

代码越少越好永远不要反复代码View应当仅仅包括呈现逻辑, 不应包括业务逻辑保持view逻辑清晰简单不要将CBVs用作403, 404, 500的错误处理程序保持mixin简单明了

2. 怎样使用mixin

在编程中mixin是指为继承它的class提供额外的功能, 但它自身却不能单独使用的类. 在具有多继承能力的编程语言中, mixin能够为类添加额外功能或方法. 在Django中, 我们能够使用mixin为CBVs提供很多其它的扩展性, 当然在类继承过程中, 我们推荐下面原则:

Django自身提供的View永远在最右边mixin依次在以上view的左边mixin永远继承自Python的object类型

在这里顺便推荐一个非常好的django库: django-braces . 该库中提供众多django的mixin, 能够方便我们日常使用.

下面是一个简单地样例, TemplateView是django自身提供的基本View, 因此在最右边; FreshFruitMixin则在TemplateView左边; FreshFruitmixin继承自object:

from django.views.generic import TemplateView

class FreshFruitMixin(object):

def get_context_data(self, **kwargs):

context = super(FreshFruitMixin, self).get_context_data(**kwargs)

context["has_fresh_fruit"] = True

return context

class FruitFlavorView(FreshFruitMixin, TemplateView):

template_name = "fruit_flavor.html"

3. 怎样使用Django自身的CBV

CBVs在功能上的可扩展性, 牺牲的是简单性, 一个CBV最多的时候拥有8个import关系. (假设希望进一步了解这些继承关系, 能够使用 Classy Class-Based Views 进行查看.)

所以要弄懂那个View最适合当下的场景对于开发者也是一个挑战. 为了降低CBVs的使用难度, 我们将这些View和主要的使用方法列在下表中, 为了显示方便, 名字前的django.views.generic前缀皆省去:

名字

目的

样例

View

基本View, 能够在不论什么时候使用

见后面具体介绍

RedirectView

又一次定向到其它URL

将訪问"/log-in/"的用户又一次定向到"/login/"

TemplateView

显示Django HTML template

一般站点中使用模板显示的页

ListView

显示对象列表

文章列表页

DetailView

显示对象详情

文章具体页

FormView

提交From

站点联系我们或emai订阅form

CreateView

创建对象

创建新文章页

UpdateView

更新对象

改动文章页

DeleteView

删除对象

删除文章页

Generic date views

显示一段时间内的对象

按时间归类的博客

4. CBVs的使用技巧

a. 限定訪问权限

在django tutorial中介绍了 怎样一起使用django.contrib.auth.decorators.login_required和CBV ,

这是一个典型的错误样例.

还好, 我们有django-braces. 在django-braces中已经提供了一个LoginRequiredMixin:

# myapp/views.py

from django.views.generic import DetailView

from braces.views import LoginRequiredMixin

from .models import Article

class ArticleDetailView(LoginRequiredMixin, DetailView):

model = Article

b. 在form提交成功后运行代码

当须要在form提交成功后运行自己定义的代码时, 能够使用form_valid()方法, form_valid()方法返回的是django.http.HttpResponseRedirect:

# myapp/views.py

from django.views.generic import CreateView

from braces.views import LoginRequiredMixin

from .models import Article

class ArticleCreateView(LoginRequiredMixin, CreateView):

model = Article

field = ('title', 'slug', 'content')

def form_valid(self, form):

# 自己定义的代码逻辑写在这里

return super(ArticleCreateView, self).form_valid(form)

c. 在form提交不成功后运行代码

当须要在form提交不成功后运行自己定义的代码时, 能够使用form_invalid()方法, form_invalid()方法返回的也是django.http.HttpResponseRedirect:

# myapp/views.py

from django.views.generic import CreateView

from braces.views import LoginRequiredMixin

from .models import Article

class ArticleCreateView(LoginRequiredMixin, CreateView):

model = Article

def form_invalid(self, form):

# 自己定义的代码逻辑写在这里

return super(ArticleCreateView, self).form_invalid(form)

5. CBV和form怎样结合使用

以下我们介绍一下常见的django form和CBV结合使用的模式, 首先我们定义一个Article model方便举例:

# myapp/models.py

from django.db import models

from django.core.urlresolvers import reverse

STATUS = {

(0, 'zero'),

(1, 'one'),

}

class Article(models.Model):

title = model.CharField(max_length=255)

slug = model.SlugField()

review_num = models.IntegerField(default=0, choices=STATUS)

def get_absolute_url(self):

return reverse("article_detail", kwargs={"slug": self.slug})

a. Views和ModelForm

以下的样例中, 我们利用django.contrib.messages和CBVs构建一套创建, 更新和显示一篇article的view, 包含:

ArticleCreateView: 用于创建新articleArticleUpdateView: 用于更新articleArticleDetailView: 用于确认创建或更新后的article

# myapp/views.py

from django.contrib import messages

from django.views.generic import CreateView, UpdateView, DetailView

from braces.views import LoginRequiredMixin

from .models import Article

class ArticleActionMixin(object):

@property

def success_msg(self):

return NotImplemented

def form_valid(self, form):

messages.info(self.request, self.success_msg)

return super(ArticleActionMixin, self).form_valid(form)

class ArticleCreateView(LoginRequiredMixin, ArticleActionMixin, CreateView):

model = Article

field = ('title', 'slug', 'review_num')

success_msg = "Article Created!"

class ArticleUpdateView(LoginRequiredMixin, ArticleActionMixin, UpdateView):

model = Article

field = ('title', 'slug', 'review_num')

success_msg = "Article Updated!"

class ArticleDetailView(DetailView):

model = Article

接下来是template

{# templates/myapp/article_detail.html #}

{% if messages %}

    {% for message in messages %}

  • { message }

{% endif %}

b. Views和Form

以下我们以搜索article功能为样例, 介绍一下CBV和form的常见使用样式, 在article列表页中点击搜索button, 显示搜友符合条件的article列表:

# myapp/views.py

from django.views.generic import ListView

from .models import Article

class ArticleListView(ListView):

model = Article

def get_queryset(self):

queryset = super(ArticleListView, self).get_queryset()

q = self.request.GET.get('q')

if q:

return queryset.filter(title__icontains=q)

return queryset

然后能够使用include下面tenplate呈现搜索form:

{# templates/myapp/_article_search.html #}