Class_Based_View类实现的视图

Django的view是一个可以调用的函数, 在CBV中 view class类 调用 as_view()方法, 返回像FBV一样的可调用函数

这个方法在django.views.generic.View 中实现, 所有的 CBV 的类都要直接或者间接的继承

Django默认提供了一些基础的 generic class-based views (GCBVs)视图类

CBV的建议

 ➤ Less view code is better.Keep your views simple.
      精简代码
  
➤ Never repeat code in views.
   DRY不要重复代码
    
➤ Views should handle presentation logic. Try to keep business logic in models when possible,
   or in forms if you must.
   处理一些展示的逻辑, 业务逻辑最好放在model中或者是form中
   
➤ Keep your mixins simpler.

CBV中使用一些Mixins公共属性

使用 mixins构建views的建议

1 The base view classes provided by Django always go to the right.
2 Mixins go to the left of the base view.
3 Mixins should inherit from Python’s built-in object type. Keep your inheritance chain simple!

实例


from django.views.generic import TemplateView

class FreshFruitMixin:  # 3
    def get_context_data(self, **kwargs):
        context = super(FreshFruitMixin, self).get_context_data(**kwargs)
        context["has_fresh_fruit"] = True
        return context
    
class FruityFlavorView(FreshFruitMixin, TemplateView):  # 1, 2
    template_name = "fruity_flavor.html"

具体的GCBV在什么情况下使用 (需要渲染templates)

GCBV django.views.generic种类 使用目的
View Base view or handy view that can be used for anything.
RedirectView Redirect user to another URL
TemplateView Display a Django HTML template.
ListView List objects .
DetailView Display an object
FormView Submit a form
CreateView Create an object
UpdateView Update an object
DeleteView Delete an object
Generic date views For display of objects that occur over a range of time (Blog博客用)

如何使用 CBV

  • 控制权限 Constraining Django CBV/GCBV Access to Authenticated Users
# flavors/views.py

from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import DetailView
from .models import Flavor

class FlavorDetailView(LoginRequiredMixin, DetailView):
    model = Flavor
  • GCBV中增加自己的处理 Performing Custom Actions on Views With Valid Forms

重写 form_valid()


from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import CreateView
from .models import Flavor

class FlavorCreateView(LoginRequiredMixin, CreateView):
    model = Flavor
    fields = ['title', 'slug', 'scoops_remaining']
    
    def form_valid(self, form):
        # Do custom logic here
        return super(FlavorCreateView, self).form_valid(form)

  • GCBV中增加自己的处理 Performing Custom Actions on Views With InValid Forms

重写 form_invalid()


from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import CreateView
from .models import Flavor

class FlavorCreateView(LoginRequiredMixin, CreateView):
    model = Flavor
    
    def form_invalid(self, form):
    # Do custom logic here
    return super(FlavorCreateView, self).form_invalid(form)


listview 中的變量

{'paginator': None, 'page_obj': None, 'is_paginated': False, 'object_list': <QuerySet [<Flavor: Flavor object>]>, 'flavor_list': <QuerySet [<Flavor: Flavor object>]>, 'view': <
flavor.views.FlavorListView object at 0x0000018A506386D8>}
  • 使用 view object对象

from django.contrib.auth.mixins import LoginRequiredMixin
from django.utils.functional import cached_property
from django.views.generic import UpdateView, TemplateView
from .models import Flavor
from .tasks import update_user_who_favorited

class FavoriteMixin:
    @cached_property
    def likes_and_favorites(self):
        """Returns a dictionary of likes and favorites"""
        likes = self.object.likes()
        favorites = self.object.favorites()
        return {
            "likes": likes,
            "favorites": favorites,
            "favorites_count": favorites.count(),
        }


class FlavorUpdateView(LoginRequiredMixin, FavoriteMixin, UpdateView):
    model = Flavor
    fields = ['title', 'slug', 'scoops_remaining']
    
    def form_valid(self, form):
        update_user_who_favorited(
            instance=self.object,
            favorites=self.likes_and_favorites['favorites']
        )
        return super(FlavorUpdateView, self).form_valid(form)

class FlavorDetailView(LoginRequiredMixin, FavoriteMixin, TemplateView):
    model = Flavor

GCBV视图form组合方式 How GCBVs and Forms Fit Together

# flavors/models.py

from django.db import models
from django.urls import reverse

class Flavor(models.Model):
    STATUS_0 = 0
    STATUS_1 = 1
    STATUS_CHOICES=(
        (STATUS_0, 'zero'),
        (STATUS_1 = 'one'),
        )
    title = models.CharField(max_length=255)
    slug = models.SlugField(unique=True)
    scoops_remaining = models.IntegerField(choices=STATUS_CHOICES,
        default=STATUS_0)

    def get_absolute_url(self):
        return reverse("flavors:detail", kwargs={"slug": self.slug})

  • GCBV Views + ModelForm

# flavors/views.py

# 1
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import CreateView, DetailView, UpdateView
from .models import Flavor

class FlavorCreateView(LoginRequiredMixin, CreateView):
    model = Flavor
    fields = ['title', 'slug', 'scoops_remaining']
    
class FlavorUpdateView(LoginRequiredMixin, UpdateView):
    model = Flavor
    fields = ['title', 'slug', 'scoops_remaining']
    
class FlavorDetailView(DetailView):
    model = Flavor


# 2 使用 form_valid() 和 Django 的 message 发送附加的信息给用户

from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import CreateView, DetailView, UpdateView
from .models import Flavor

class FlavorActionMixin:
    fields = ['title', 'slug', 'scoops_remaining']
    
    @property
    def success_msg(self):
        return NotImplemented
        
    def form_valid(self, form):
        messages.info(self.request, self.success_msg)
        return super(FlavorActionMixin, self).form_valid(form)
        
        
class FlavorCreateView(LoginRequiredMixin, FlavorActionMixin,CreateView):
    model = Flavor
    success_msg = "Flavor created!"
    
        
class FlavorUpdateView(LoginRequiredMixin, FlavorActionMixin, UpdateView):
        model = Flavor
        success_msg = "Flavor updated!"
        
class FlavorDetailView(DetailView):
    model = Flavor

# 

{ if messages  }
    <ul class="messages">
    {  for message in messages  }
        <li id="message_"
            {  if message.tags  } class=""
                {  endif  }>
            
        </li>
    {  endfor  }
    </ul>
{  endif  }

  • GCBV Views + Form

from django.views.generic import ListView
from .models import Flavor

class FlavorListView(ListView):
    model = Flavor
    
    def get_queryset(self):
        # Fetch the queryset from the parent get_queryset
        queryset = super(FlavorListView, self).get_queryset()
        
        # Get the q GET parameter
        q = self.request.GET.get("q")
        if q:
            # Return a filtered queryset
            return queryset.filter(title__icontains=q)
        # Return the base queryset
        return queryset


{# templates/flavors/_flavor_search.html #}
{  comment  }
Usage: {  include "flavors/_flavor_search.html"  }
{  endcomment  }
<form action="{  url "flavor_list"  }" method="GET">
<input type="text" name="q" />
<button type="submit">search</button>
</form>

使用普通的django.views.generic.View

实例


from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import get_object_or_404
from django.shortcuts import render, redirect
from django.views.generic import View

from .forms import FlavorForm
from .models import Flavor

class FlavorView(LoginRequiredMixin, View):
    def get(self, request, *args, **kwargs):
        # Handles display of the Flavor object
        flavor = get_object_or_404(Flavor, slug=kwargs['slug'])
        
        return render(request,
            "flavors/flavor_detail.html",
            {"flavor": flavor}
            )
                
    def post(self, request, *args, **kwargs):
        # Handles updates of the Flavor object
        flavor = get_object_or_404(Flavor, slug=kwargs['slug'])
        form = FlavorForm(request.POST)
        if form.is_valid():
            form.save()
        return redirect("flavors:detail", flavor.slug)

可以处理JSONPDF 或者其他 non-HTML


from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from django.views.generic import View

from .models import Flavor
from .reports import make_flavor_pdf
    
    class FlavorPDFView(LoginRequiredMixin, View):
    
        def get(self, request, *args, **kwargs):
            # Get the flavor
            flavor = get_object_or_404(Flavor, slug=kwargs['slug'])
            
            # create the response
            response = HttpResponse(content_type='application/pdf')
            
            # generate the PDF stream and attach to the response
            response = make_flavor_pdf(response, flavor)
            
            return response
Buy me a 肥仔水!