详解Django通用视图中的函数包装

yipeiwu_com7年前Python基础

用函数包装来处理复杂的数据过滤

另一个常见的需求是按URL里的关键字来过滤数据对象。 之前,我们在URLconf中硬编码了出版商的名字,但是如果我们想用一个视图就显示某个任意指定的出版商的所有书籍,那该怎么办呢? 我们可以通过对 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}
 )

这样写没问题,因为通用视图就是Python函数。 和其他的视图函数一样,通用视图也是接受一些 参数并返回 HttpResponse 对象。 因此,通过包装通用视图函数可以做更多的事。

注意

注意在前面这个例子中我们在 extra_context中传递了当前出版商这个参数。
处理额外工作

我们再来看看最后一个常用模式:

想象一下我们在 Author 对象里有一个 last_accessed 字段,我们用这个字段来记录最近一次对author的访问。 当然通用视图 object_detail 并不能处理这个问题,但是我们仍然可以很容易地编写一个自定义的视图来更新这个字段。

首先,我们需要在URL配置里设置指向到新的自定义视图:

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

注意

除非你添加 last_accessed 字段到你的 Author 模型并创建 books/author_detail.html 模板,否则这段代码不能真正工作。

我们可以用同样的方法修改通用视图的返回值。 如果我们想要提供一个供下载用的 纯文本版本的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

这个方法之所以工作是因为通用视图返回的 HttpResponse 对象可以象一个字典 一样的设置HTTP的头部。 随便说一下,这个 Content-Disposition 的含义是 告诉浏览器下载并保存这个页面,而不是在浏览器中显示它。

相关文章

解决Python一行输出不显示的问题

在使用python函数print()时,如下代码会出现输出无法显示的问题: 分三次在一行输出 123 print(1, end="") print(2, end="") print(...

Python3中在Anaconda环境下安装basemap包

Python3中在Anaconda环境下安装basemap包

Basemap是matplotlib子包,也是python中最常用、最方便的地理数据可视化工具之一。 在中端输入pip list先查看是否有jupyter,一般安装了Anaconda都会...

利用python写个下载teahour音频的小脚本

前言 最近空闲的时候看到了之前就关注的一个小站http://teahour.fm/,一直想把这里的音频都听一遍,可转眼间怎么着也有两年了,却什么也没做。有些伤感,于是就写了个脚本,抓了下...

跟老齐学Python之私有函数和专有方法

在任何语言中,都会规定某些对象(属性、方法、函数、类等)只能够在某个范围内访问,出了这个范围就不能访问了。这是“公”、“私”之分。此外,还会专门为某些特殊的东西指定一些特殊表示,比如类的...

浅谈pandas中shift和diff函数关系

通过?pandas.DataFrame.shift命令查看帮助文档 Signature: pandas.DataFrame.shift(self, periods=1, fr...