Class-based views是Django为解决建站过程中的常见的呈现模式而建立的. 在这节中, 我们着重讲一下CBVs的使用技巧和一般原则.
在编程中mixin是指为继承它的class提供额外的功能, 但它自身却不能单独使用的类. 在具有多继承能力的编程语言中, mixin可以为类增加额外功能或方法. 在Django中, 我们可以使用mixin为CBVs提供更多的扩展性, 当然在类继承过程中, 我们推荐以下原则:
在这里顺便推荐一个很好的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"
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 | 显示一段时间内的对象 | 按时间归类的博客 |
在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
当需要在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)
当需要在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)
下面我们介绍一下常见的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})
下面的例子中, 我们利用django.contrib.messages和CBVs构建一套创建, 更新和显示一篇article的view, 包括:
# 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 %} <ul class="messages"> {% for message in messages %} <li>{ message } </li> </ul> {% endif %}
下面我们以搜索article功能为例子, 介绍一下CBV和form的常见使用样式, 在article列表页中点击搜索按钮, 显示搜友符合条件的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 #} <form action="{% url "article_list" %} method="GET""> <input type="text" name="q"></> <button type="submit">搜索</> </form>
只用django.views.generic.View, 而不用FBV来构建所有django项目中的view也是可行的, 这也没有你所想象的那么复杂. 使用View的好处是, 我们不需要写许多内套式的if语句, 我们可以直接覆盖使用View的get(), post()等方法:
from django.shortcuts import get_object_or_404, render, redirect from django.views.generic import View from braces.views import LoginRequiredMixin from .forms import ArticleForm from .models import Article class ArticleView(LoginRequiredMixin, View): def get(self, request, *args, **kwargs): article = get_object_or_404(Article, pl=kwargs[‘slug‘]) return render(request, "myapp/article_detail.html", {"article": article} ) def post(sele, request, *args, **kwargs): article = get_object_or_404(Article, pl=kwargs[‘slug‘]) form = ArticleForm(request.POST) if form.is_valid(): form.save() return redirect("myapp:article", article.slug)
Django 1.6 CBVs,布布扣,bubuko.com
原文地址:http://blog.csdn.net/zouyee/article/details/26468773