Django内建通用视图可以实现如下功能:
1.完成常用的简单任务: 重定向到另一个页面以及渲染一个指定的模板。
2.显示列表和某个特定对象的详细内容页面。 第8章中提到的 event_list 和 entry_list 视图就是列表视图的一个例子。 一个单一的 event 页面就是我们所说的详细内容页面。
3.呈现基于日期的数据的年/月/日归档页面,关联的详情页面,最新页面。 Django Weblogs (http://www.djangoproject.com/weblog/)的年、月、日的归档就是使用通用视图 架构的,就像是典型的新闻报纸归档。
使用通用视图:
使用通用视图的方法是在URLconf文件中创建配置字典,然后把这些字典作为URLconf元组的第三个成员。
from django.conf.urls.defaults import *
from django.views.generic.simple import direct_to_template
from mysite.books.views import about_pages
urlpatterns = patterns('',
(r'^about/$', direct_to_template, {
'template': 'about.html'
}),
(r'^about/(\w+)/$', about_pages),
)
接下来,我们编写 about_pages 视图的代码:
from django.http import Http404
from django.template import TemplateDoesNotExist
from django.views.generic.simple import direct_to_template
def about_pages(request, page):
try:
return direct_to_template(request, template="about/%s.html" % page)
except TemplateDoesNotExist:
raise Http404()
View function: django.views.generic.simple.direct_to_template
This view renders a given template, passing it a {{ params }} templatevariable, which is a dictionary of the parameters captured in the URL.
direct_to_template() 通过{{ params }}在URL中捕获的参数是一个字典。
例子:urlpatterns=patterns(' ',r'^foo/(?P<id>\d+)/$',direct_to_template,'foo.detail.html'
如果请求的网址是foo/1/ 则模板渲染时{{params.id}}会被设置为1
Publisher 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']
url 配置,
在缺少template_name的情况下,object_list通用视图将自动使用一个对象名称。 在这个例子中,这个推导出的模板名称将是"books/publisher_list.html" ,其中books部分是定义这个模型的app的名称, publisher部分是这个模型名称的小写。
在模板中,通用视图会通过在template_object_name后追加一个_list的方式来创建一个表示列表项目的变量名。
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' #使用模板
'template_object_name': 'publisher',
}
urlpatterns = patterns('',
(r'^publishers/$', list_detail.object_list, publisher_info)
)
{% extends "base.html" %}
{% block content %}
<h2>Publishers</h2>
<ul>
{% for publisher in object_list %}
<li>{{ publisher.name }}</li>
{% endfor %}
</ul>
{% endblock %}
base.html 如下:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<h1>My helpful timestamp site</h1>
{% block content %}{% endblock %}
{% block footer %}
<hr>
<p>Thanks for visiting my site.</p>
{% endblock %}
</body>
</html>
添加额外的Context
你常常需要呈现比通用视图提供的更多的额外信息。 例如,考虑一下在每个出版商的详细页面显示所有其他出版商列表。object_detail 通用视图为context提供了出版商信息,但是看起来没有办法在模板中 获取所有 出版商列表。
publisher_info = {
'queryset': Publisher.objects.all(),
'template_object_name': 'publisher',
**'extra_context': {'book_list': Book.objects.all()}**
}
因为在这个例子中,我们把 Publisher.objects.all() 放在URLconf中,它只会执行一次(当URLconf第一次加载的时候)。 当你添加或删除出版商,你会发现在重启Web服务器之前,通用视图不会反映出这些修改
这个问题不适用于通用视图的 queryset 参数。 因为Django知道有些特别的 QuerySet 永远不能 被缓存,通用视图在渲染前都做了缓存清除工作。
**def get_books():** **return Book.objects.all()** publisher_info = { 'queryset': Publisher.objects.all(), 'template_object_name': 'publisher', 'extra_context': **{'book_list': get_books}** }
或者你可以使用另一个不是那么清晰但是很简短的方法,事实上 Publisher.objects.all 本身就是可以调用的:
publisher_info = { 'queryset': Publisher.objects.all(), 'template_object_name': 'publisher', 'extra_context': **{'book_list': Book.objects.all}** }注意 Book.objects.all 后面没有括号;这表示这是一个函数的引用,并没有真正调用它(通用视图将会在渲染时调用它)。
显示对象的子集
现在让我们来仔细看看这个 queryset 。 大多数通用视图有一个queryset参数,这个参数告诉视图要显示对象的集合 (有关QuerySet的解释请看第五章的 “选择对象”章节,详细资料请参看附录B)。
举一个简单的例子,我们打算对书籍列表按出版日期排序,最近的排在最前:
book_info = { 'queryset': Book.objects.order_by('-publication_date'), } urlpatterns = patterns('', (r'^publishers/$', list_detail.object_list, publisher_info), **(r'^books/$', list_detail.object_list, book_info),** )
这是一个相当简单的例子,但是很说明问题。 当然,你通常还想做比重新排序更多的事。 如果你想要呈现某个特定出版商出版的所有书籍列表,你可以使用同样的技术:
**apress_books = {** **'queryset': Book.objects.filter(publisher__name='Apress Publishing'),** **'template_name': 'books/apress_list.html'** **}** urlpatterns = patterns('', (r'^publishers/$', list_detail.object_list, publisher_info), **(r'^books/apress/$', list_detail.object_list, apress_books),**对 object_list 通用视图进行包装来避免 写一大堆的手工代码。 按惯例,我们先从写URL配置开始:
urlpatterns = patterns('', (r'^publishers/$', list_detail.object_list, publisher_info), **(r'^books/(\w+)/$', books_by_publisher),** )
接下来,我们写 books_by_publisher 这个视图:
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} )
处理额外工作
我们再来看看最后一个常用模式:
想象一下我们在 Author 对象里有一个last_accessed 字段,我们用这个字段来记录最近一次对author的访问。 当然通用视图object_detail 并不能处理这个问题,但是我们仍然可以很容易地编写一个自定义的视图来更新这个字段。
from mysite.books.views import author_detail urlpatterns = patterns('', # ... **(r'^authors/(?P<author_id>\d+)/$', author_detail),** # ... )
接下来写包装函数:
import datetime from django.shortcuts import get_object_or_404 from django.views.generic import list_detail from mysite.books.models import Author def author_detail(request, author_id): # Delegate to the generic view and get an HttpResponse. response = list_detail.object_detail( request, queryset = Author.objects.all(), object_id = author_id, ) # Record the last accessed date. We do this *after* the call # to object_detail(), not before it, so that this won't be called # unless the Author actually exists. (If the author doesn't exist, # object_detail() will raise Http404, and we won't reach this point.) now = datetime.datetime.now() Author.objects.filter(id=author_id).update(last_accessed=now) return response
我们可以用同样的方法修改通用视图的返回值。如果我们想要提供一个供下载用的 纯文本版本的author列表,我们可以用下面这个视图:
def author_list_plaintext(request): response = list_detail.object_list( request, queryset = Author.objects.all(), mimetype = 'text/plain', template_name = 'books/author_list.txt' ) response["Content-Disposition"] = "attachment; filename=authors.txt" return response
补充知识:
什么是 MIME Type?
首先,我们要了解浏览器是如何处理内容的。在浏览器中显示的内容有 HTML、有 XML、有 GIF、还有 Flash ……那么,浏览器是如何区分它们,决定什么内容用什么形式来显示呢?答案是 MIME Type,也就是该资源的媒体类型。媒体类型通常是通过 HTTP 协议,由 Web 服务器告知浏览器的,更准确地说,是通过 Content-Type 来表示的,例如:
Content-Type: text/HTML
表示内容是 text/HTML 类型,也就是超文本文件。
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,并渲染模板,最后返回HTTPResponse对象。object_list函数创建的context中会包含以下字典项:
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 页码范围的列表
slug_field='slug', template_name=None, template_name_field=None,
template_loader=loader, extra_context=None,
context_processors=None, template_object_name='object',
mimetype=None)
参考:http://www.cnblogs.com/holbrook/archive/2012/02/12/2357342.html
Generic Views 官方文档:http://www.djangobook.com/en/2.0/appendixC.html