Django 1.6 CBVs

本文介绍了Django中Class-based views (CBVs)的最佳实践,包括使用原则、mixin技巧及如何结合form使用等。通过具体示例展示了如何限制访问权限、在form提交后执行自定义代码等内容。

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: 用于创建新article
  • ArticleUpdateView: 用于更新article
  • ArticleDetailView: 用于确认创建或更新后的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 %}
  <ul class="messages">
    {% for message in messages %}
    <li>{ message } </li>
  </ul>
  {% 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 #}
    <form action="{% url "article_list" %} method="GET"">
        <input type="text" name="q"></>
        <button type="submit">搜索</>
    </form>

6. 单独使用View

仅仅用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)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值