Function_Based_View函数实现的视图

基于函数的视图实现方式FBV不能像CBV一样继承Django的基础视图类

FBV的建议

➤ 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中
   
➤ Use them to write custom 403, 404, and 500 error handlers.
   处理错误
   
➤ Complex nested-if blocks are to be avoided.
   尽量不要出现复杂的,嵌套的 if-else 代码块

传递Django中的 django.http.HttpRequest object 或者 django.http.HttpResponse object

除了使用中间件 middleware 上下文 context processors, 可以创建一些公用的方法对 django.http.HttpRequest object进行处理


# sprinkles/utils.py

# 1 
from django.core.exceptions import PermissionDenied

def check_sprinkle_rights(request):
    if request.user.can_sprinkle or request.user.is_staff:
        return request
        
    # Return a HTTP 403 back to the user
    raise PermissionDenied



# 2
from django.core.exceptions import PermissionDenied

def check_sprinkles(request):
    if request.user.can_sprinkle or request.user.is_staff:
        # By adding this value here it means our display templates
        # can be more generic. We don't need to have
        # {  if request.user.can_sprinkle or request.user.is_staff  }
        # instead just using
        # {  if request.can_sprinkle  }
        request.can_sprinkle = True
        return request
        
    # Return a HTTP 403 back to the user
    raise PermissionDenied
    

在视图中使用 FBV


# sprinkles/views.py

from django.shortcuts import get_object_or_404
from django.shortcuts import render
from .models import Sprinkle
from .utils import check_sprinkles

def sprinkle_list(request):
    """Standard list view"""
    request = check_sprinkles(request)
    return render(request,
        "sprinkles/sprinkle_list.html",
        {"sprinkles": Sprinkle.objects.all()}
        )


def sprinkle_detail(request, pk):
    """Standard detail view"""
    request = check_sprinkles(request)
    sprinkle = get_object_or_404(Sprinkle, pk=pk)
    return render(request, "sprinkles/sprinkle_detail.html",
        {"sprinkle": sprinkle})
    
    
def sprinkle_preview(request):
    """Preview of new sprinkle, but without the
    check_sprinkles function being used.
    """
    sprinkle = Sprinkle.objects.all()
    return render(request,
        "sprinkles/sprinkle_preview.html",
        {"sprinkle": sprinkle})

在视图中使用 CBV

from django.views.generic import DetailView
from .models import Sprinkle
from .utils import check_sprinkles

class SprinkleDetail(DetailView):
    """Standard detail view"""
    model = Sprinkle
    
    def dispatch(self, request, *args, **kwargs):
        request = check_sprinkles(request)
        return super(SprinkleDetail, self).dispatch(
            request, *args, **kwargs)

FBV视图函数使用 装饰器


import functools

def decorator(view_func):
    @functools.wraps(view_func)
    def new_view_func(request, *args, **kwargs):
        # You can modify the request (HttpRequest) object here.
        response = view_func(request, *args, **kwargs)
        # You can modify the response (HttpResponse) object here.
        return response
    return new_view_func

使用装饰器改写上面的例子


# sprinkles/decorators.py

from functools import wraps
from . import utils

# based off the decorator template from the previous chapter
def check_sprinkles(view_func):
    """Check if a user can add sprinkles"""
    @wraps(view_func)
    def new_view_func(request, *args, **kwargs):
        # Act on the request object with utils.can_sprinkle()
        request = utils.can_sprinkle(request)
        # Call the view function
        response = view_func(request, *args, **kwargs)
        # Return the HttpResponse object
        return response
    return new_view_func
    
    
# sprinkles/views.py

from django.shortcuts import get_object_or_404, render
from .decorators import check_sprinkles
from .models import Sprinkle

# Attach the decorator to the view
@check_sprinkles
def sprinkle_detail(request, pk):
    """Standard detail view"""
    sprinkle = get_object_or_404(Sprinkle, pk=pk)
    return render(request, "sprinkles/sprinkle_detail.html",
        {"sprinkle": sprinkle})

functools.wraps()是python的标准包中的方法, 可以保持被装饰函数的原始数据

metadata including critical data like docstring
Buy me a 肥仔水!