Django通用视图

在开发网站的过程中,有一些视图函数虽然处理的对象不同,但是其大致的代码逻辑是一样的。比如一个博客和一个论坛,通常其首页都是展示一系列的文章列表或者帖子列表。对处理首页的视图函数来说,虽然其处理的对象一个是文章,另一个是帖子,但是其处理的过程是非常类似的。

于是Django使用通用视图,抽象出一些在视图开发中常用的代码和模式,这样就可以在无需编写大量代码的情况下,快速编写出常用的数据视图。

基本视图

View

引入

from django.views.generic.base import View

介绍

这个类是通用类的基类,其他类都是继承自这个类。

当我们继承这个类,构造基于类的视图时,只需要实现不同request请求的处理函数。例如实现get(self, request, *args, **kwargs)处理来自GET方法的请求、实现post(self, request, *args, **kwargs)处理来自POST方法的请求。函数名为请求名的小写。

类函数

只列举部分个人认为比较重要的函数

  • dispatch

      #分发函数,将请求根据其方法类型分发到不同处理函数(handler)
      def dispatch(self, request, *args, **kwargs):
          if request.method.lower() in self.http_method_names:
              handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
          else:
              handler = self.http_method_not_allowed
          return handler(request, *args, **kwargs)
    
  • as_view

      #在URLconf处调用,请求入口函数,在函数内部调用`dispatch`将请求分发处理
      @classonlymethod
      def as_view(cls, **initkwargs):
          ...
          def view(request, *args, **kwargs):
              self = cls(**initkwargs)
              if hasattr(self, 'get') and not hasattr(self, 'head'):
                  self.head = self.get
              self.request = request
              self.args = args
              self.kwargs = kwargs
              return self.dispatch(request, *args, **kwargs)
          ...
          return view
    

当构造基于类的视图时,基本就是靠以上两个函数来将请求分发到我们实现的处理函数里的。

示例

# views.py
from django.http import HttpResponse
from django.views.generic import View

class MyView(View):
    #实现get函数处理来自GET方法的请求
    def get(self, request, *args, **kwargs):
        return HttpResponse('Hello, World!')

# urls.py
from django.urls import path 
from myapp.views import MyView

urlpatterns = [
    path('mine/', MyView.as_view(), name='my-view'),
]

TemplateView

引入

from django.views.generic.base import TemplateView

介绍

渲染给定的模板文件。

类图

TemplateView类图

  • View类提供了as_view()类方法,它返回一个内方法view(),在这个方法中,做的事情就是dispatch的事情,根据请求的方法,调用相应的方法去处理请求,如果你发送了一个GET请求,那么在view()方法中就会分发到get()方法中去处理。

  • ContextMixin类则只是实现了一个方法,get_context_data(),这是为在渲染template的时候,提供了一个默认的context,一般子类都会重写这个方法的。

  • TemplateResponseMixin类,就是真正干事的类了,它在render_to_response()方法中,返回一个TemplateResponse对象,template用的就是类属性template_name指定的。

然后TemplateView继承上面的三个类,实现了get()方法。

类函数

  • get_template_names
      #通过`template_name`属性获取模板文件名称
      def get_template_names(self):
          """
          Return a list of template names to be used for the request. Must return
          a list. May not be called if render_to_response() is overridden.
          """
          if self.template_name is None:
              raise ImproperlyConfigured(
                  "TemplateResponseMixin requires either a definition of "
                  "'template_name' or an implementation of 'get_template_names()'")
          else:
              return [self.template_name]
    
  • get_context_data
      #传递额外参数到模板,一般继承TemplateView时会重载这个函数,以传递自定义参数到模板中
      def get_context_data(self, **kwargs):
          if 'view' not in kwargs:
              kwargs['view'] = self
          if self.extra_context is not None:
              kwargs.update(self.extra_context)
          return kwargs
    

示例

  1. 省略view层,直接在url层返回结果

     #urls.py
     from django.urls import path
     from django.views.generic import TemplateView
    
     urlpatterns = [
         path('', TemplateView.as_view(template_name='home.html'), name='home'),
     ]
    
  2. 在view层自定义类集成TemplateView类实现

     # views.py
     from django.views.generic.base import TemplateView
     from articles.models import Article
    
     class HomeView(TemplateView):
    
         template_name = "home.html" #定义模板名称,必须有。而且template_name这个变量名固定
    
         def get_context_data(self, **kwargs): #传递额外参数到模板,例如模板中可通过变量名latest_articles获取其对象
             context = super().get_context_data(**kwargs)
             context['latest_articles'] = Article.objects.all()[:5]
             return context
    
     #urls.py
     from django.urls import path
     from myapp.views import HomeView
    
     urlpatterns = [
         path('', HomeView.as_view(), name='home'),
     ]
    
     <!-- home.html -->
    
     <!-- 模板语言会在后续介绍 -->
    

RedirectView

引入

from django.views.generic.base import RedictView

介绍

重定向到给定的URL。如果给定的URL是None,Django将返回一个HttpResponseGone (410)。

主要:因为Python使用%来实现字符串格式化,所以在url中要包含%的话,必须使用%%。

类图

TemplateView类图

类变量

    permanent = False     #是否为永久重定向
    url = None            #要跳转的网址
    pattern_name = None   #要跳转的路由地址别名
    query_string = False  #是否传递GET的参数到跳转网址,True时会传递,默认为 False

类函数

  • get_redirect_url
    #获取跳转地址
    def get_redirect_url(self, *args, **kwargs):
        if self.url:
            url = self.url % kwargs
        elif self.pattern_name:
            url = reverse(self.pattern_name, args=args, kwargs=kwargs)
        else:
            return None

        args = self.request.META.get('QUERY_STRING', '')
        if args and self.query_string:
            url = "%s?%s" % (url, args)
        return url
    #可以看出url和patter_name是不能同时使用的,优先使用url

示例

# views.py
from django.shortcuts import get_object_or_404
from django.views.generic.base import RedirectView

from articles.models import Article

class ArticleCounterRedirectView(RedirectView):

    permanent = False
    query_string = True
    pattern_name = 'article-detail'

    def get_redirect_url(self, *args, **kwargs):
        article = get_object_or_404(Article, pk=kwargs['pk'])
        article.update_counter()
        return super().get_redirect_url(*args, **kwargs)
# urls.py
from django.urls import path
from django.views.generic.base import RedirectView

from article.views import ArticleCounterRedirectView

urlpatterns = [
    path('counter/<int:pk>/', ArticleCounterRedirectView.as_view(), name='article-counter'),
    path('go-to-django/', RedirectView.as_view(url='https://djangoproject.com'), name='go-to-django'),
]
Copyright © itrunner.cn 2020 all right reserved,powered by Gitbook该文章修订时间: 2022-08-28 07:44:16

results matching ""

    No results matching ""