0

django笔记之Generic views

 2 years ago
source link: http://wwj718.github.io/post/%E6%8A%80%E6%9C%AF/django-generic-views/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

django笔记之Generic views

2014-03-11

为何要使用通用视图呢,一步步地定义url,写函数取数据,渲染模板不也能完成任务么?仅仅因为这些函数比较高级,我们就得学,为了证明自己django用的熟练?当然不是啦,djangobook中有一段话很好地回答了why的问题:

  • 在最坏的情况下, Web开发是一项无聊而且单调的工作(大多情况还是很有趣的啦~)。在视图的层面上,也经历着这种令人厌倦的事情。Django的通用视图可以减少这些痛苦。 它抽象出一些在视图开发中常用的代码和模式,这样就可以在无需编写大量代码的情况下,快速编写出常用的数据视图。 事实上,前面章节中的几乎所有视图的示例都可以在通用视图的帮助下重写。

‘技术让生活更美好’,我们只是想拥有更多的时间陪喜欢的人,做喜欢的事,更多的时间出游,看书,睡懒觉。所以我们需要更高级的工具来节省时间,提高效率。那么我们还有什么理由不好好学习高级工具呢。
好的既然值得学习,我们趁热打铁进入内容部分吧。

Djangobook第11章中说内建通用视图可以实现如下功能:

  • 完成常用的简单任务: 重定向到另一个页面以及渲染一个指定的模板。
  • 显示列表和某个特定对象的详细内容页面。
  • 呈现基于日期的数据的年/月/日归档页面,关联的详情页面,最新页面。像是典型的新闻报纸归档。

这些都是极其常见的需求,尤其是在一个新闻发布系统中,而大多企业建站需要的仅仅是个新闻发布系统而已。

###使用举例:

####direct_to_template

#url.py
#coding=utf-8
#呈现静态“关于”页面

from django.conf.urls.defaults import *
from django.views.generic.simple import direct_to_template

urlpatterns = patterns('',
    (r'^about/$', direct_to_template, {
        'template': 'about.html'
    })
)

direct_to_template视图仅仅是直接从传递过来的额外参数获取信息并用于渲染视图。
这样就不用为了呈现一个静态页,mvc都得走一遍。
direct_to_template 。 因为它返回一个HttpResponse对象,我们只需要简单的返回它就好了。例如可以这样:

def about_pages(request, page):
    try:
        return direct_to_template(request, template="about/%s.html" % page)
    except TemplateDoesNotExist:
        raise Http404()

其他通用视图也是同理。

####对象的通用视图list_detail(使用djangobook中的例子)

#models.py
class Publisher(models.Model):
    name = models.CharField(max_length=30)
    address = models.CharField(max_length=50)
    city = models.CharField(max_length=60)
    state_province = models.CharField(max_length=30)
    country = models.CharField(max_length=50)
    website = models.URLField()

    def __unicode__(self):
        return self.name

    class Meta:
        ordering = ['name']

#urls.py
from django.conf.urls.defaults import *
from django.views.generic import list_detail
from mysite.books.models import Publisher

publisher_info = {
    'queryset': Publisher.objects.all(),
    'template_name': 'publisher_list_page.html',#
}

urlpatterns = patterns('',
    (r'^publishers/$', list_detail.object_list, publisher_info)
)

)

那么通用视图究竟有哪些可选的参数呢,可以参考这里Appendix C: Generic View Reference

object_list(request, queryset, paginate_by=None, page=None, allow_empty=True, 
        template_name=None, template_loader=loader, extra_context=None, 
        context_processors=None, template_object_name='object', mimetype=None
)

特别说明下context字典项会被模板使用。如果不指定模板,该函数将使用[app_name]/[model_name]_list.html作为模板,这很有些约定优于配置味道。

object_list函数创建的context中会包含许多字典项: 深入Django(1): 通用视图 (generic views)这篇博客给出了详细的中文注释:

  • object_list 要显示的对象的list
  • is_paginated 是否分页
  • results_per_page 如果分页,存储每页记录数
  • has_next 是否有下一页
  • has_previous 是否有上一页
  • page 当前页码
  • next 下一页
  • previous 上一页
  • pages 总页数
  • hits 总条目数
  • last_on_page 本页最后录一条记录的序数(从1开始)
  • first_on_page 本页第一条记录的序数(从1开始)
  • page_range 页码范围的列表

如果这些context字典项不能满足你的需要,还可以通过指定extra_context参数,传入一个字典,该字典中的内容会被合并到context字典中。我们接下去说如何扩展通用视图,go on ~

####扩展通用视图

在我们最开始举的publisher例子中(来自djanobook),可以这样扩展context字典

publisher_info = {
    'queryset': Publisher.objects.all(),
    'template_object_name': 'publisher',
    'extra_context': {'book_list': Book.objects.all()},#这是错的!!使用下面一个
    'extra_context': **{'book_list': Book.objects.all}
}

这样就把一个 {{ book_list }} 变量放到模板的context中。 这个方法可以用来传递任意数据 到通用视图模板中去,这是非常方便的.
需要注意的是all()不可立刻触发,应当由请求事件来触发,因此作为函数传递,不写().这是一个函数的引用,并没有真正调用它(通用视图将会在渲染时调用它)。
还有就是选项’queryset’仅仅是普通的queryset,你可以用对象的子集,比如'queryset':Publisher.objects.filter(name='Harry')

###当数据过滤比较复杂时

这是我们可以把通用视图写到函数里,前头说过通用视图返回一个HttpResponse对象,我们提供参数返回它就好,故而用在views中是没问题的,像酱紫:

#urls.py
urlpatterns = patterns('',
    (r'^publishers/$', list_detail.object_list, publisher_info),
    **(r'^books/(\w+)/$', books_by_publisher),**
)

#views.py
from django.shortcuts import get_object_or_404
from django.views.generic import list_detail
from mysite.books.models import Book, Publisher

def books_by_publisher(request, name):

    # Look up the publisher (and raise a 404 if it can't be found).
    publisher = get_object_or_404(Publisher, name__iexact=name)

    # Use the object_list view for the heavy lifting.
    return list_detail.object_list(
        request,
        queryset = Book.objects.filter(publisher=publisher),
        template_name = 'books/books_by_publisher.html',
        template_object_name = 'book',
        extra_context = {'publisher': publisher}
    )

我的个人习惯是直接查阅源码来得快些。推荐使用github的库内搜索功能,比如我们搜索django,之后在django项目中搜索object_list,这样每回遇到新的库,不一定非要下载到本地看代码样随时随地想起来都可以查阅,甚至火车晚点时,可以用手机看看源码。读源码也挺有意思的。许多大项目,源码都写得十分漂亮。

好了,你现在有了更高效的工具了,因此节约出来的时间可以陪小伙伴去玩耍啦

###Django提供的其他通用视图

我们用深入Django(1): 通用视图 (generic views)中归纳的:

分布在几个模块中:

  • django.views.generic.list_detail模块
  • object_list 显示模型对象列表
  • object_detail 显示单个模型对象
  • django.views.generic.create_update模块
  • create_object 创建模型对象
  • update_object 修改模型对象
  • delete_object 删除模型对象
  • django.views.generic.simple模块
  • direct_to_template 直接使用指定的模板渲染给定的context对象
  • redirect_to 重定向到指定的url
  • django.views.generic.date_based模块

这个模块主要处理“按时间查看存档”的功能,来源于新闻出版行业。具体包括:

  • archive_index 最顶级的归档,列出所有年份及指定数量的最新对象
  • archive_year 按年归档,列出所有拥有对象的月份
  • archive_month 按月归档,列出本月的所有对象,找到拥有对象的上一个、下一个月份
  • archive_week 按周归档,列出本周的所有对象
  • archive_day 按日归档,列出当天的所有对象,找到拥有对象的上一个、下一个日期
  • archive_today 当前日期(今天)的按日归档
  • object_detail 显示按照年/月/日/序号找到的对象

剩下的就是查阅文档,了解参数了。

我的个人习惯是直接查阅源码来得快些。推荐使用github的库内搜索功能,比如我们搜索django,之后在django项目中搜索object_list,这样每回遇到新的库,不一定非要下载到本地看代码样随时随地想起来都可以查阅,甚至火车晚点时,可以用手机看看源码。读源码也挺有意思的。许多大项目,源码都写得十分漂亮。

###参考资料:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK