{% raw %}
# 使用Django输出PDF #
这篇文档阐述了如何通过使用Django视图动态输出PDF。这可以通过一个出色的、开源的Python PDF库[ReportLab](http://www.reportlab.com/opensource/)来实现。
动态生成PDF文件的优点是,你可以为不同目的创建自定义的PDF -- 这就是说,为不同的用户或者不同的内容。
例如,Django在[kusports.com](http://www.kusports.com/)上用来为那些参加March Madness比赛的人,生成自定义的,便于打印的 NCAA 锦标赛晋级表作为PDF文件。
## 安装ReportLab ##
ReportLab库在[PyPI](https://pypi.python.org/pypi/reportlab)上提供。也可以下载到[用户指南](http://www.reportlab.com/docs/reportlab-userguide.pdf) (PDF文件,不是巧合)。 你可以使用`pip`来安装ReportLab:
```
$ pip install reportlab
```
通过在Python交互解释器中导入它来测试你的安装:
```
>>> import reportlab
```
若没有抛出任何错误,则已安装成功。
## 编写你的视图 ##
使用Django动态生成PDF的关键是,ReportLab API作用于类似于文件的对象,并且Django的 `HttpResponse`对象就是类似于文件的对象。
这里是一个 “Hello World”的例子:
```
from reportlab.pdfgen import canvas
from django.http import HttpResponse
def some_view(request):
# Create the HttpResponse object with the appropriate PDF headers.
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'
# Create the PDF object, using the response object as its "file."
p = canvas.Canvas(response)
# Draw things on the PDF. Here's where the PDF generation happens.
# See the ReportLab documentation for the full list of functionality.
p.drawString(100, 100, "Hello world.")
# Close the PDF object cleanly, and we're done.
p.showPage()
p.save()
return response
```
代码和注释是不用多说的,但是一些事情需要提醒一下:
+ 响应对象获得了一个特殊的MIME类型, `application/pdf`。这会告诉浏览器,文档是个PDF文件而不是HTML文件。 如果你把它去掉,浏览器可能会把输出解释为HTML,会在浏览器窗口中显示一篇丑陋的、可怕的官样文章。
+ 响应对象获取了附加的`Content-Disposition`协议头,它含有PDF文件的名称。 文件名可以是任意的;你想把它叫做什么都可以。浏览器会在”另存为“对话框中使用它,或者其它。
+ 在这个例子中,`Content-Disposition` 协议头以 `'attachment;'` 开头。 这样就强制让浏览器弹出对话框来提示或者确认,如果机器上设置了默认值要如何处理文档。如果你去掉了`'attachment;'`,无论什么程序或控件被设置为用于处理PDF,浏览器都会使用它。代码就像这样:
```
response['Content-Disposition'] = 'filename="somefilename.pdf"'
```
+ 钩住ReportLab API 非常简单:只需要向`canvas.Canvas`传递`response`作为第一个参数。`Canvas`函数接受一个类似于文件的对象,而 `HttpResponse`对象正好合适。
+ 注意所有随后的PDF生成方法都在PDF对象(这个例子是p)上调用,而不是`response`对象上。
+ 最后,在PDF文件上调用`showPage()` 和 `save()`非常重要。
> 注意
>
> ReportLab并不是线程安全的。一些用户报告了一些奇怪的问题,在构建生成PDF的Django视图时出现,这些视图在同一时间被很多人访问。
## 复杂的PDF ##
如果你使用ReportLab创建复杂的PDF文档,考虑使用`io`库作为你PDF文件的临时保存地点。这个库提供了一个类似于文件的对象接口,非常实用。这个是上面的“Hello World”示例采用 `io`重写后的样子:
```
from io import BytesIO
from reportlab.pdfgen import canvas
from django.http import HttpResponse
def some_view(request):
# Create the HttpResponse object with the appropriate PDF headers.
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'
buffer = BytesIO()
# Create the PDF object, using the BytesIO object as its "file."
p = canvas.Canvas(buffer)
# Draw things on the PDF. Here's where the PDF generation happens.
# See the ReportLab documentation for the full list of functionality.
p.drawString(100, 100, "Hello world.")
# Close the PDF object cleanly.
p.showPage()
p.save()
# Get the value of the BytesIO buffer and write it to the response.
pdf = buffer.getvalue()
buffer.close()
response.write(pdf)
return response
```
## 更多资源 ##
+ [PDFlib](http://www.pdflib.org/)与Python捆绑的另一个PDF生成库。在Django中使用它的方法和这篇文章所阐述的相同。
+ [Pisa XHTML2PDF](http://www.xhtml2pdf.com/)是另一个PDF生成库。Pisa自带了如何将 Pisa 集成到 Django的例子。
+ [HTMLdoc](http://www.htmldoc.org/)是一个命令行脚本,它可以把HTML转换为PDF。它并没有Python接口,但是你可以使用`system` 或者 `popen`,在控制台中使用它,然后再Python中取回输出。
## 其它格式 ##
要注意在这些例子中并没有很多PDF特定的东西 -- 只是使用了`reportlab`。你可以使用相似的技巧来生成任何格式,只要你可以找到对应的Python库。关于用于生成基于文本的格式的其它例子和技巧,另见[使用Django输出CSV](http://python.usyiyi.cn/django/howto/outputting-csv.html)。
> 译者:[Django 文档协作翻译小组](http://python.usyiyi.cn/django/index.html),原文:[Generating PDF](https://docs.djangoproject.com/en/1.8/howto/outputting-pdf/)。
>
> 本文以 [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/cn/) 协议发布,转载请保留作者署名和文章出处。
>
> [Django 文档协作翻译小组](http://python.usyiyi.cn/django/index.html)人手紧缺,有兴趣的朋友可以加入我们,完全公益性质。交流群:467338606。
{% endraw %}
- 新手入门
- 从零开始
- 概览
- 安装
- 教程
- 第1部分:模型
- 第2部分:管理站点
- 第3部分:视图和模板
- 第4部分:表单和通用视图
- 第5部分:测试
- 第6部分:静态文件
- 高级教程
- 如何编写可重用的应用
- 为Django编写首个补丁
- 模型层
- 模型
- 模型语法
- 元选项
- 模型类
- 查询集
- 执行查询
- 查找表达式
- 模型的实例
- 实例方法
- 访问关联对象
- 迁移
- 模式编辑器
- 编写迁移
- 高级
- 管理器
- 原始的SQL查询
- 聚合
- 多数据库
- 自定义查找
- 条件表达式
- 数据库函数
- 其它
- 遗留的数据库
- 提供初始数据
- 优化数据库访问
- 视图层
- 基础
- URL配置
- 视图函数
- 快捷函数
- 装饰器
- 参考
- 内建的视图
- TemplateResponse 对象
- 文件上传
- 概览
- File 对象
- 储存API
- 管理文件
- 自定义存储
- 基于类的视图
- 概览
- 内建显示视图
- 内建编辑视图
- API参考
- 分类索引
- 高级
- 生成 CSV
- 生成 PDF
- 中间件
- 概览
- 内建的中间件类
- 模板层
- 基础
- 面向设计师
- 语言概览
- 人性化
- 面向程序员
- 表单
- 基础
- 概览
- 表单API
- 内建的Widget
- 高级
- 整合媒体
- 开发过程
- 设置
- 概览
- 应用程序
- 异常
- 概览
- django-admin 和 manage.py
- 添加自定义的命令
- 测试
- 介绍
- 部署
- 概述
- WSGI服务器
- 部署静态文件
- 通过email追踪代码错误
- Admin
- 管理操作
- 管理文档生成器
- 安全
- 安全概述
- 说明Django中的安全问题
- 点击劫持保护
- 加密签名
- 国际化和本地化
- 概述
- 本地化WEB UI格式化输入
- “本地特色”
- 常见的网站应用工具
- 认证
- 概览
- 使用认证系统
- 密码管理
- 日志
- 分页
- 会话
- 数据验证
- 其它核心功能
- 按需内容处理
- 重定向
- 信号
- 系统检查框架