zoukankan      html  css  js  c++  java
  • Python Django CBV下的通用视图函数

    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

    继承结构:

    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

    看完应该就会一目了然。

        path('', RedirectView.as_view(pattern_name='backend:index')),

    通用显示视图

    ListView

    继承关系:

    ListView,用于显示一个对象列表的视图,包含一个属性值object_list,表示对象的列表。因此在模板文件中可以通过遍历该属性来显示model的所有数据。

    class StudentList(ListView):
        model = models.Student  # orm的model
        template_name = 'student_list.html'  # 要返回的模版文件
        context_object_name = 'student_obj'  # orm数据实例化对象,前端调用的名称
        extra_context = {'name': 'dandy'}  # 额外的上下文数据信息
    
        def get(self, request, *args, **kwargs):  # 重写get方法
            response = super().get(request, *args, **kwargs)
            return response
    
        def get_context_data(self, *, object_list=None, **kwargs):  # 重写get_context_data方法
            context = super().get_context_data(**kwargs)  # 拿到返回值context并更新或者扩充
            context['num'] = 11
            return context
    
        def get_queryset(self):
            # query_set = super().get_queryset()
            # query_set = super().get_queryset()[:1]
            self.kwargs['name'] = 'dandy'
            cate = get_object_or_404(models.Student, name=self.kwargs.get('name'))
            return super().get_queryset().filter(name=cate)

    上面有一个参数没有设计到:

    queryset = Student.objects.filter(name='zhangsan')

    该属性表示该视图显示项的集合,可以通过get_queryset()方法来进行定义。

    所以上面的这一句筛选跟上面的get_queryset自定义的筛选,其实差不多。

    context_object_name

    在模板中使用object_list是一个不太友好的方法,因为不知道object_list具体指的是哪个模板的数据,因此在通用视图中还提供了一个属性:context_object_name来制定一个上下文,如:

    class showStu(ListView):
        ...
        context_object_name = "student"

    看一下模版内:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h3>{{ name }}</h3>
        <table>
            <thead>
                <td>姓名</td>
                <td>年龄</td>
            </thead>
            <tbody>
                {% for student in student_obj %}
                    <tr>
                        <td>{{ student.name }}</td>
                        <td>{{ student.age }}</td>
                    </tr>
                {% endfor %}
            </tbody>
        </table>
        <br>
        <h2>{{ num }}</h2>
    </body>
    </html>
    View Code

    DetailView

    继承关系:

    DetailView用于显示一个特定类型对象的详细信息。DetailView的大部分属性和方法和ListView相同。不同的是该视图没有object_list属性,因为该视图负责显示一个特定对象的详细信息,因此有一个object属性,表示model的一个对象(或一条记录)。

    class StudentDetailView(DetailView):
        model = models.Student  # orm的model
        template_name = 'student_detail.html'  # 调用的模版文件
        context_object_name = 'aaa'  # 模版文件里面对应的orm数据对象的名称
    
        def get(self, request, *args, **kwargs):
            response = super().get(request, *args, **kwargs)  # 同样的重写的方法可以做一些自定义,比如访问量+1等等的
            return response
    
        def get_object(self):
            obj = super().get_object()
            return obj  # 这里的obj其实已经是指向一条数据了;比如一篇文章,可以进行一些修改之类的操作,obj.aa = 'dandy', obj.save()
    
        def get_context_data(self, **kwargs):
            context = super().get_context_data(**kwargs)  # 重写,获取返回数据
            classes = self.object.classes_set.all()  # 反向获取所有关联数据
            context.update({  # 添加新的上下文信息
                'classes': classes,
                'test_name': 'dandy'
            })
            return context

    这里需要注意的是url,因为明确表面了这个通用视图的目的,所以url固定的指向了某个具体的事物的id

        path('detailview/<int:pk>/', views.StudentDetailView.as_view(), name='student_detail'),

    内部形成处理。

    默认情况下,DetailView 使用<appname>/<model name>_detail.html的模板,如果没有该模板,则应该通过”template_name”指定一个模板。

  • 相关阅读:
    初学C++到底应该用什么工具比较合适——工具简析
    便携式办公套件LibreOffice Portable 4.0.1
    Hibernate和JPA之间的联系
    央视《家有妙招》整理版,共250招,值得永远收藏
    思科Vs华为:不可避免的对决
    Facebook手机刺激了谁?
    Facebook利用Home平台加速进军移动领域
    英特尔Haswell处理器已出货 预计6月推出
    苹果自建街景地图 或与谷歌针锋相对
    图片链接
  • 原文地址:https://www.cnblogs.com/wuzdandz/p/9448310.html
Copyright © 2011-2022 走看看