前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Django来敲门~第一部分【9.使用Django内置视图处理对象简化开发】

Django来敲门~第一部分【9.使用Django内置视图处理对象简化开发】

作者头像
大牧莫邪
发布2018-08-27 17:34:54
8830
发布2018-08-27 17:34:54
举报

常使民无知、无欲,使夫智者不敢为也。为无为,则无不治 ——老子《道德经》


首先,要说这是Django基础部分的最后一个章节了。后面会详细讲解Django每一部分的使用方式和API了

本节内容

  • 内置视图处理对象的定义
  • 内置视图处理对象的使用
  • 源代码分析

1. 内置视图处理对象的定义

对于我们视图处理函数,从最原始的HttpResponse()来进行页面数据的输出,到render()函数进行模板页面的操作,已经是可以满足我们的需求了,但是Django赶脚还不够,不够~所以提供了常规的一些页面视图对象对页面模板和模板中要展示的数据进行了封装处理。

常规情况下,对应页面中要展示数据列表的视图,通过继承Django的django.views.generic.ListView对象来实现,页面中要展示数据信息的视图,通过继承Django的django.views.generic.DetailView进行实现。

我们改造polls/views.py视图模块如下:

代码语言:javascript
复制
from django.shortcuts import render, get_object_or_404

from django.http import HttpResponseRedirect
from django.views import generic
from django.urls import reverse

from .models import Question


# 封装:定义展示应用首页的处理类
class IndexView(generic.ListView):
    # 模板路径
    template_name = "index.html"
    # 指定变量名称,保存查询到的数据
    context_object_name = "question_list"

    # 列表页面,需要查询对应的数据集合
    def get_queryset(self):
        return Question.objects.order_by("-pub_date")


# 封装:定义展示问题详细信息的处理类
class DetailView(generic.DetailView):
    # 指定要展示的数据类型
    model = Question
    # 指定展示的模板页面
    template_name = "details.html"


# 封装:定义展示结果的视图处理类
class ResultView(generic.DetailView):
    model = Question
    template_name = "results.html"


# 定义投票结果
def vote(request, question_id):
    # 获取查询的问题对象
    question = get_object_or_404(Question, pk=question_id)
    print(request.POST)
    try:
        select_choice = question.choice_set.get(pk=request.POST['choice'])
    except Exception as e:
        print(e)
        return render(request, "details.html",
                      {
                          "question": question,
                          "error_message": "你的问题还没有发布解决方案"
                      })
    else:
        # 投票数量增加1
        select_choice.votes += 1
        # 保存到数据库
        select_choice.save()
        # 代码中使用配置的方式跳转到指定的路由
        return HttpResponseRedirect(reverse("polls:results", args=(question.id,)))

上述代码中,对于展示问题列表的首页,继承了generic.ListView内置类,通过template_name指定了HTML视图,通过context_object_name指定了保存数据的变量,在get_queryset()函数中定义了数据的查询方式

问题详细信息页面和问题解决方案的结果展示页面,继承了generic.DetailView内置类,通过model指定了展示的数据的类型,template_name指定了HTML视图的名称

vote函数暂时不做任何处理,这是一个包含了业务逻辑处理的视图函数

2. 视图对象的使用

经过上述的改造,我们可以看到视图处理函数已经变得非常的简洁,但是存在这样一个问题,IndexView处理类中的数据,我们可以看懂是通过get_queryset()函数进行查询的,然后自动复制给变量question_list,那么后面的DetailViewResultView中的数据是怎么来的呢?

DetailViewResultView中的要查询的数据,同样也是通过主键编号进行查询的,默认的变量名称是pk,所以在路由中要进行如下的修改配置,才可以正常使用

改造polls/urls.py路由模块

代码语言:javascript
复制
from django.conf.urls import url
from . import views

app_name = "polls"

urlpatterns = [
    # url(r"^$", views.index, name="index"),
    # url(r"^(?P<question_id>\d+)$", views.detail, name="detail"),
    # url(r"^(?P<question_id>\d+)/results/$", views.results, name="results"),
    url(r"^$", views.IndexView.as_view(), name="index"),
    url(r"^(?P<pk>\d+)/$", views.DetailView.as_view(), name="detail"),
    url(r"^(?P<pk>\d+)/results/$", views.ResultView.as_view(), name="results"),
    url(r"^(?P<question_id>\d+)/vote/$", views.vote, name="vote"),
]

这里路由配置的过程中,通过as_view()函数,会自动对目标视图类进行封装,将视图处理类中的template_name模板进行加载,然后渲染由model或者context_object_name指定的数据。

2.1. 项目测试

重启项目,打开网页进行访问

访问首页

查看问题

投票操作

3. 源码分析

此时,会有个问题困扰着我们,为什么要继承视图处理类,为什么要继承不同的处理类ListViewDetailView

这个问题就对了,我们看看Django源代码

首先查看ListView

代码语言:javascript
复制
class ListView(MultipleObjectTemplateResponseMixin, BaseListView):
    """
    Render some list of objects, set by `self.model` or `self.queryset`.
    `self.queryset` can actually be any iterable of items, not just a queryset.
    """
......
class MultipleObjectMixin(ContextMixin):
    """
    A mixin for views manipulating multiple objects.
    """
    allow_empty = True 
    queryset = None
    model = None
    paginate_by = None
    paginate_orphans = 0
    context_object_name = None
    paginator_class = Paginator
    page_kwarg = 'page'
    ordering = None
......
    def get_queryset(self):
        """
        Return the list of items for this view.

        The return value must be an iterable and may be an instance of
        `QuerySet` in which case `QuerySet` specific behavior will be enabled.
        """
......

我们可以从上述代码中看到,继承自ListView视图处理类的类型,已经在内部封装好了分页操作功能,这也是我们项目中经常用到的技术呢,非常棒吧,我们继承了这个视图处理对象,就可以在后续的项目中,通过重写它的属性和方法来快捷的完成数据展示的分页功能了。

接下来,我们继续看DetailView是怎么操作的吧

代码语言:javascript
复制
class DetailView(SingleObjectTemplateResponseMixin, BaseDetailView):
    """
    Render a "detail" view of an object.

    By default this is a model instance looked up from `self.queryset`, but the
    view will support display of *any* object by overriding `self.get_object()`.
    """
......
class SingleObjectMixin(ContextMixin):
    """
    Provides the ability to retrieve a single object for further manipulation.
    """
    model = None
    queryset = None
    slug_field = 'slug'
    context_object_name = None
    slug_url_kwarg = 'slug'
    pk_url_kwarg = 'pk'
    query_pk_and_slug = False  
......

我们可以在源代码中,看到各种操作的一些信息,官方注释用于使用对象数据来渲染详细信息页面的视图对象,继承的父类中,也定义了各种属性字段用于控制单个对象数据的展示操作

以上两个视图类,都间接继承了View内置类,我们看一下源代码

代码语言:javascript
复制
# 基础视图对象工具类,用于进行视图的渲染操作,包含了as_view()处理函数
class View(object):
    """
    Intentionally simple parent class for all views. Only implements
    dispatch-by-method and simple sanity checking.
    """
    ......
    @classonlymethod
    def as_view(cls, **initkwargs):
        """
        Main entry point for a request-response process.
        """
        for key in initkwargs:
        ......
# 用于进行视图模板和数据混合渲染的工具类,可以看到包含了template_name字段
class TemplateResponseMixin(object):
    """
    A mixin that can be used to render a template.
    """
    template_name = None
    template_engine = None
    response_class = TemplateResponse
    content_type = None
......
# 用于封装基础模板渲染页面视图的工具类
class TemplateView(TemplateResponseMixin, ContextMixin, View):
    """
    A view that renders a template.  This view will also pass into the context
    any keyword arguments passed by the URLconf.
    """
......
# 用于请求最终重定向的视图工具类
class RedirectView(View):
    """
    A view that provides a redirect on any GET request.
    """
......

从基础文件view.py中,我们可以看到,各种视图模板的基础处理操作和视图类型的封装都有了简洁的定义,我们需要做的就是在项目中,继承这些Django已经封装好的对象,快捷的完成项目的开发。


本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.06.13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 内置视图处理对象的定义
  • 2. 视图对象的使用
    • 2.1. 项目测试
    • 3. 源码分析
    相关产品与服务
    腾讯云代码分析
    腾讯云代码分析(内部代号CodeDog)是集众多代码分析工具的云原生、分布式、高性能的代码综合分析跟踪管理平台,其主要功能是持续跟踪分析代码,观测项目代码质量,支撑团队传承代码文化。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档