ListView

TemplateView

DetailView

 

之前的代码实例基本上都是基于FBV的模式来撰写的,好处么,当然就是简单粗暴。。正如:

def index(request):
    return HttpResponse('hello world')

上面的写法,基本接触不到视图函数里面的通用视图。只是在介绍CBV的时候稍微介绍了下引用,大概用法。

 

导入

之前的导入一直用的是

from django.views import View

这里从view下钻一下会发现:

from django.views.generic.base import View

__all__ = ['View']

对头、view视图函数基本都来自于generic里面,此篇blog具体讲述的内容也是generic内部的几个通用视图:ListView、DetailView、TemplateView。

 

 

View

基础类视图:

from django.http import HttpResponse
from django.views import View

class MyView(View):
    def get(self, request):
        return HttpResponse('ok')
urlpatterns = [
    path('index/',views.MyView.as_view(), name='index'),
]

as_view()方法会返回一个函数来处理请求和响应,还可以将类视图中定义的属性作为该方法参数,覆盖类视图中的属性值。 

 

基本视图

基本视图包括三类:View、TemplateView和RedirectView。用户可继承基本类视图来定义视图,所有的通用视图也都继承与这三类基本视图实现,因此相比于通用视图,基本视图提供的功能较少。

View

View是所有类视图的父类,可以直接从from django.views中导入,如:

from django.views import View

class MyView(View):

      def get(self,request):
          pass

http请求的方法

http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

as_view():该方法是一个类方法,被@classonlymethod修饰,是http请求和响应的入口,用于url配置。在Http请求和响应的过程中,会将request对象和其他参数作为参数传入该方法,内部调用dispatch()方法后返回一个Response对象。

 

TemplateView

继承结构:

Python Django CBV下的通用视图函数

class TemplateView(TemplateResponseMixin, ContextMixin, View):

TemplateView视图通过给定的模板进行渲染。

实例

class StudentDetailTemplate(TemplateView):  # 继承TemplateView
    template_name = 'student_template.html'  # 模版名称

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)  # 继承父类里面的get_context_data,返回上下文数据
        context['name'] = 'dandy'  # 添加新的数据
        context['data'] = {
            'age': 18,  # 添加新的字典
            'flag': 'aaa'
        }
        context['data1'] = models.Student.objects.all()  # 添加新的queryset
        return context  # 返回更新过的上下文文数据

url:

    path('templateview/', views.StudentDetailTemplate.as_view(), name='student_template'),

 

其他为涉及到的属性或方法:

get_template_names()

除了使用template_name指定模板文件,也可通过该方法指定模板文件:

def get_template_names(self):
        return "student_template.html"

extra_content

除了在get_context_data()中添加上下文信息外,也可以在url配置时在as_view()方法中指定extra_context属性来添加上下文信息,如:

    path('templateview/', views.StudentDetailTemplate.as_view(extra_context={"extra": "。。。。"}), name='student_template'),

CBV正常是需要在下面定义一个get或之类的方法,用来匹配method,但是此处是不需要的,因为查看TemplateView内部时会发现:

class TemplateView(TemplateResponseMixin, ContextMixin, View):
    """
    Render a template. Pass keyword arguments from the URLconf to the context.
    """
    def get(self, request, *args, **kwargs):
        context = self.get_context_data(**kwargs)
        return self.render_to_response(context)

内部已经写好了这个get方法,一方面TemplateView的基础需求其实就是返回模版给浏览器的。当然了,因为继承了TemplateView,这里还是可以重写这个get方法,进行自定义数据。

    def get(self, request, *args, **kwargs):
        context = self.get_context_data(**kwargs)
        context['end'] = 'ending'
        new_data ={
            'a': 'b'
        }
        context.update(new_data)
        return self.render_to_response(context)

 

RedirectView

用来进行跳转, 默认是永久重定向(301),可以直接在urls.py中使用,非常方便:

    path('', views.IndexPage.as_view(), name='baidu'),
class ArticleCounterRedirectView(RedirectView):
 
    url = ' # 要跳转的网址,
    # url 可以不给,用 pattern_name 和 get_redirect_url() 函数 来解析到要跳转的网址
     
    permanent = False #是否为永久重定向, 默认为 False
    query_string = True # 是否传递GET的参数到跳转网址,True时会传递,默认为 False
    pattern_name = 'article-detail' # 用来跳转的 URL, 看下面的 get_redirect_url() 函数
 
     
    # 如果url没有设定,此函数就会尝试用pattern_name和从网址中捕捉的参数来获取对应网址
    # 即 reverse(pattern_name, args) 得到相应的网址,
    def get_redirect_url(self, *args, **kwargs):
        article = get_object_or_404(Article, pk=kwargs['pk'])
        article.update_counter() # 更新文章点击数,在models.py中实现
        return super(ArticleCounterRedirectView, self).get_redirect_url(*args, **kwargs)

RedirectView源码:

class RedirectView(View):
    """Provide a redirect on any GET request."""
    permanent = False
    url = None
    pattern_name = None
    query_string = False

    def get_redirect_url(self, *args, **kwargs):
        """
        Return the URL redirect to. Keyword arguments from the URL pattern
        match generating the redirect request are provided as kwargs to this
        method.
        """
        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
        def get(self, request, *args, **kwargs):
        url = self.get_redirect_url(*args, **kwargs)
        if url:
            if self.permanent:
                return HttpResponsePermanentRedirect(url)
            else:
                return HttpResponseRedirect(url)
        else:
            logger.warning(
                'Gone: %s', request.path,
                extra={'status_code': 410, 'request': request}
            )
            return HttpResponseGone()

    def head(self, request, *args, **kwargs):
        return self.get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.get(request, *args, **kwargs)

    def options(self, request, *args, **kwargs):
        return self.get(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.get(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        return self.get(request, *args, **kwargs)

    def patch(self, request, *args, **kwargs):
        return self.get(request, *args, **kwargs)

View Code