Django Step by Step (四)

作者:limodou
联系:limodou@gmail.com
版本:0.1
主页:http://wiki.woodpecker.org.cn/moin/NewEdit
BLOG:http://www.donews.net/limodou
版权:FDL

目录

1   引言

经过前几节的学习,我想大家应该比较熟悉 Django 的大致开发流程了:

  • 增加 view 方法
  • 增加模板
  • 修改 urls.py

就是这样。剩下的就是挖掘 Django 提供的其它的能力。在我们还没有进入模型(model)之前还是再看一看外围的东西,再更进一步体验 Django 吧。

在 Django 中我看到了一个生成 csv 格式的文档(Outputting CSV dynamically),非常好,它没有数据库,正好用来做演示。

现在我的需求就是提供 csv 格式文件的下载。

我们会在原来 list(表格) 例子基础上进行演示,步骤就是上面的流程。

2   修改 templates/list.html

在文件最后增加:

<p><a href="/csv/address/">csv格式下载</a></p>

它将显示为一个链接,它所指向的链接将用来生成 csv 文件。

3   在newtest下增加 csv_test.py

#coding=utf-8
from django.http import HttpResponse
from django.template import loader, Context

address = [
    ('张三', '地址一'),
    ('李四', '地址二')
    ]

def output(request, filename):
    response = HttpResponse(mimetype='text/csv')
    response['Content-Disposition'] = 'attachment; filename=%s.csv' % filename

    t = loader.get_template('csv.html')
    c = Context({
        'data': address,
    })
    response.write(t.render(c))
    return response

Note

此文件原来为 csv.py ,但后来发现与系统的 csv 模块重名,因此改名

Note

在 0.91 版中 HttpResponse 是从 django.utils.httpwrappers 导入的,而 0.95 为 django.httploader, Context 是从 django.core.template 导入的,而 0.95 为 django.template 。具体可以参考: NamespaceSimplification 文档。以后类似的地方不再详述。

这里使用的东西多了一些。这里没有 render_to_response 了,而是演示了一个完整的从头进行模板解析的处理过程。为什么需要这样,因为我们需要修改 response 对象的值,而 render_to_response 封装了它使得我们无法修改。从这里我们也可以看到,在调用一个方法时, Django 会传入一个 request 对象,在返回时,你需要将内容写入 response ,必要时修改它的某些属性。更详细的建议你参考 django 所带的 request_response 文档,里面详细描述了两个对象的内容,并且还可以在交互环境下进行测试,学习非常方便。

Note

response 对象也是由 Django 自动维护的。具体的内容参见 Request and response objects 文档。

这里 address 不再是字典的列表,而是 tuple 的列表。让人高兴的是, Django 的模板除了可以处理字典,还可以处理序列,而且可以处理序列中的元素。一会在模板定义中我们会看到。

这里 output() 是我们希望 Django 调用的方法,不再是 index() 了。(不能老是一样的呀。)而且它与前面的 index() 不同,它带了一个参数。这里主要是想演示 url 的参数解析。因此你要注意,这个参数一定是放在 url 上的。它表示输出文件名。

response = HttpResponse(mimetype='text/csv')
response['Content-Disposition'] = 'attachment; filename=%s.csv' % filename

这两行是用来处理输出类型和附件的,以前我也没有用过,这回也学到了。它表明返回的是一个 csv 格式的文件。

t = loader.get_template('csv.html')
c = Context({
    'data': address,
})
response.write(t.render(c))

这几行就是最原始的模板使用方法。先通过 loader 来找到需要的模板,然后生成一个 template 对象,再生成一个 Context 对象,它就是一个字典集。然后 t.render(c) 这个用来对模板和提供的变量进行合并处理,生成最终的结果。最后调用 response.write() 将内容写入。

4   增加 templates/csv.html

{% for row in data %}"{{ row.0|addslashes}}", "{{ row.1|addslashes}}",
{% endfor %}

使用了一个 for 循环。这里 data 与上面的 Contextdata 相对应。因为 data 是一个列表,它的每行是一个 tuple ,因此 row.0, row.1 就是取 tuple 的第一个和第二个元素。 | 是一个过滤符,它表示将前一个的处理结果作为输入传入下一个处理。因此 Django 的模板很强大,使用起来也非常直观和方便。 addslashes 是 Django 模板内置的过滤 Tag ,它用来将结果中的特殊字符加上反斜线。

同时我们注意到,每个 {{}} 前后都有一个双引号,这样就保证每个字符串使用双引号引起来。然后在第一个与第二个元素之间还使用了逗号分隔。最后 endfor 在下一行,表示上面每行模板后有一个回车。

Django 还允许你自定义 Tag ,在 The Django template language: For Python programmers 文档中有描述,其实是很简单的。

5   修改 urls.py

from django.conf.urls.defaults import *

urlpatterns = patterns('',
    # Example:
    # (r'^testit/', include('newtest.apps.foo.urls.foo')),
    (r'^$', 'newtest.helloworld.index'),
    (r'^add/$', 'newtest.add.index'),
    (r'^list/$', 'newtest.list.index'),
    (r'^csv/(?P<filename>\w+)/$', 'newtest.csv_test.output'),

    # Uncomment this for admin:
#     (r'^admin/', include('django.contrib.admin.urls')),
)

增加了 csv 的 url 映射。

上面的正则表达式有些复杂了,因为有参数的处理在里面。 (?P<filename>\w+) 这是一个将解析结果起名为 filename 的正则表达式,它完全符合 Python 正则表达式的用法。在最新的 Django 中,还可以简化一下: (\w+) 。但这样需要你的参数是按顺序传入的,在一个方法有多个参数时一定要注意顺序。

Note

关于 url 的配置问题在 URL configuration 文档中有说明。

还记得吗?我们的链接是写成 /csv/address/ ,因此上面实际上会变成对 csv.output(filename='address') 的调用。

6   启动 server

看一下结果吧。点击链接,浏览器会提示你保存文件的。

很简单吧。但这里面的内容其实也不少,而且许多地方都有很大的扩展空间。