Python 在Django站点中将HTML呈现为PDF
对于我的django支持的站点,我正在寻找一个简单的解决方案,将动态html页面转换为pdf 页面包含来自Google visualization API的HTML和图表(基于javascript,但必须包含这些图形)。请从中尝试解决方案 下载它并使用python setup.py安装像往常一样安装它 您还需要安装以下模块:xhtml2pdf、html5lib、pypdf和easy_install 下面是一个使用示例: 首先定义此函数:Python 在Django站点中将HTML呈现为PDF,python,html,django,pdf,pdf-generation,Python,Html,Django,Pdf,Pdf Generation,对于我的django支持的站点,我正在寻找一个简单的解决方案,将动态html页面转换为pdf 页面包含来自Google visualization API的HTML和图表(基于javascript,但必须包含这些图形)。请从中尝试解决方案 下载它并使用python setup.py安装像往常一样安装它 您还需要安装以下模块:xhtml2pdf、html5lib、pypdf和easy_install 下面是一个使用示例: 首先定义此函数: import cStringIO as StringIO
import cStringIO as StringIO
from xhtml2pdf import pisa
from django.template.loader import get_template
from django.template import Context
from django.http import HttpResponse
from cgi import escape
def render_to_pdf(template_src, context_dict):
template = get_template(template_src)
context = Context(context_dict)
html = template.render(context)
result = StringIO.StringIO()
pdf = pisa.pisaDocument(StringIO.StringIO(html.encode("ISO-8859-1")), result)
if not pdf.err:
return HttpResponse(result.getvalue(), content_type='application/pdf')
return HttpResponse('We had some errors<pre>%s</pre>' % escape(html))
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>My Title</title>
<style type="text/css">
@page {
size: {{ pagesize }};
margin: 1cm;
@frame footer {
-pdf-frame-content: footerContent;
bottom: 0cm;
margin-left: 9cm;
margin-right: 9cm;
height: 1cm;
}
}
</style>
</head>
<body>
<div>
{% for item in mylist %}
RENDER MY CONTENT
{% endfor %}
</div>
<div id="footerContent">
{%block page_foot%}
Page <pdf:pagenumber>
{%endblock%}
</div>
</body>
</html>
import StringIO
from cgi import escape
from xhtml2pdf import pisa
from django.http import HttpResponse
from django.template.response import TemplateResponse
from django.views.generic import TemplateView
class PDFTemplateResponse(TemplateResponse):
def generate_pdf(self, retval):
html = self.content
result = StringIO.StringIO()
rendering = pisa.pisaDocument(StringIO.StringIO(html.encode("ISO-8859-1")), result)
if rendering.err:
return HttpResponse('We had some errors<pre>%s</pre>' % escape(html))
else:
self.content = result.getvalue()
def __init__(self, *args, **kwargs):
super(PDFTemplateResponse, self).__init__(*args, mimetype='application/pdf', **kwargs)
self.add_post_render_callback(self.generate_pdf)
class PDFTemplateView(TemplateView):
response_class = PDFTemplateResponse
模板:
import cStringIO as StringIO
from xhtml2pdf import pisa
from django.template.loader import get_template
from django.template import Context
from django.http import HttpResponse
from cgi import escape
def render_to_pdf(template_src, context_dict):
template = get_template(template_src)
context = Context(context_dict)
html = template.render(context)
result = StringIO.StringIO()
pdf = pisa.pisaDocument(StringIO.StringIO(html.encode("ISO-8859-1")), result)
if not pdf.err:
return HttpResponse(result.getvalue(), content_type='application/pdf')
return HttpResponse('We had some errors<pre>%s</pre>' % escape(html))
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>My Title</title>
<style type="text/css">
@page {
size: {{ pagesize }};
margin: 1cm;
@frame footer {
-pdf-frame-content: footerContent;
bottom: 0cm;
margin-left: 9cm;
margin-right: 9cm;
height: 1cm;
}
}
</style>
</head>
<body>
<div>
{% for item in mylist %}
RENDER MY CONTENT
{% endfor %}
</div>
<div id="footerContent">
{%block page_foot%}
Page <pdf:pagenumber>
{%endblock%}
</div>
</body>
</html>
import StringIO
from cgi import escape
from xhtml2pdf import pisa
from django.http import HttpResponse
from django.template.response import TemplateResponse
from django.views.generic import TemplateView
class PDFTemplateResponse(TemplateResponse):
def generate_pdf(self, retval):
html = self.content
result = StringIO.StringIO()
rendering = pisa.pisaDocument(StringIO.StringIO(html.encode("ISO-8859-1")), result)
if rendering.err:
return HttpResponse('We had some errors<pre>%s</pre>' % escape(html))
else:
self.content = result.getvalue()
def __init__(self, *args, **kwargs):
super(PDFTemplateResponse, self).__init__(*args, mimetype='application/pdf', **kwargs)
self.add_post_render_callback(self.generate_pdf)
class PDFTemplateView(TemplateView):
response_class = PDFTemplateResponse
我的头衔
@页面{
大小:{{pagesize}};
边缘:1cm;
@框架页脚{
-pdf框架内容:页脚内容;
底部:0厘米;
左边距:9厘米;
右边距:9厘米;
高度:1厘米;
}
}
{mylist%中项目的%s}
呈现我的内容
{%endfor%}
{%block page_foot%}
页
{%endblock%}
希望有帮助。我刚刚为CBV做了这个。不用于生产,但为我生成PDF。可能需要在错误报告方面做些工作,但到目前为止已经做到了
class MyPdfView(PDFTemplateView):
template_name = 'things/pdf.html'
您可以使用iReport编辑器定义布局,并在jasper reports server中发布报告。发布后,您可以调用RESTAPI来获得结果 以下是对功能的测试:
{% extends "easy_pdf/base.html" %}
{% block content %}
<div id="content">
<h1>Hi there!</h1>
</div>
{% endblock %}
来自django.test的导入测试用例
从x_reports_jasper.models导入JasperServerClient
"""
尝试通过rest与jasper服务器集成
"""
类TestJasperServerClient(TestCase):
#定义测试所需的对象
def设置(自):
#将连接加载到远程服务器
尝试:
self.j_url=”http://127.0.0.1:8080/jasperserver"
self.j_user=“jasperamin”
self.j_pass=“jasperamin”
self.client=JasperServerClient.create_客户端(self.j_url、self.j_用户、self.j_密码)
除例外情况外,e:
#如果出现错误,则无法执行给定条件下的测试
提升
#服务器数据无效时的测试异常
def测试\u登录到\u无效\u地址\u应引发(自我):
self.assertRaises(异常,JasperServerClient.create_client,“http://127.0.0.1:9090/jasperserver,self.j_用户,self.j_通行证)
#在服务器中测试并执行现有报表
def测试获取报告(自我):
r_resource_path=“/reports/”
r_format=“pdf”
r_params={'PARAM_TO_REPORT':“1”,}
#resource\u meta=client.load\u resource\u元数据(rep\u resource\u路径)
[uuid,out\u mime,out\u data]=self.client.generate\u报告(r\u资源路径,r\u格式,r\u参数)
self.assertionsnotnone(uuid)
下面是调用实现的一个示例:
from easy_pdf.views import PDFTemplateView
class HelloPDFView(PDFTemplateView):
template_name = "hello.html"
来自django.db导入模型的
导入请求
导入系统
从xml.etree导入元素树
导入日志记录
#模块记录器定义
logger=logging.getLogger(_名称__)
#在这里创建您的模型。
类JasperServerClient(models.Manager):
定义句柄异常(自身、异常根、异常id、执行信息):
类型、值、回溯=执行信息
raise JasperServerClientError(异常根,异常id),无,回溯
#01:报告元数据
#获取资源描述以生成报告
定义处理报告元数据(自我、代表资源路径):
l_path_base_resource=“/rest/resource”
l_path=self.j_url+l_path_base_资源
logger.info(“元数据(开始)[path=%s%s]”%(l\u path,rep\u resourcepath))
资源\u响应=无
尝试:
resource\u response=requests.get(“%s%s”%(l\u path,rep\u resourcepath),cookies=self.login\u response.cookies)
除例外情况外,e:
self.\u handle\u异常(例如,“报告元数据:调用错误”,sys.exc\u info())
资源\响应\ dom=无
尝试:
#解析到dom并设置参数
logger.debug(“-response[data=%s]”%(resource\u response.text))
resource\u response\u dom=ElementTree.fromstring(resource\u response.text)
datum=“”
对于资源\响应\ dom.getiterator()中的节点:
datum=“%s
%s-%s”%(datum,node.tag,node.text)
debug(“-response[xml=%s]”%(数据))
#
self.resource\u response\u payload=resource\u response.text
logger.info(“元数据(结束)”)
除例外情况外,e:
logger.error(“元数据(错误)[%s]”%(e))
self.\u handle\u异常(例如,“报告元数据:解析错误”,sys.exc\u info())
#02:REPORT-PARAMS
定义添加报告参数(自身、元数据、文本、参数):
如果(类型(参数)!=dict):
raise TypeError(“要报告的参数无效”)
其他:
logger.info(“添加参数(开始)[]”)
#复制参数
l_参数={}
对于参数项()中的k,v:
l_参数[k]=v
#获取有效负载元数据
metadata\u dom=ElementTree.fromstring(元数据\u文本)
#向有效负载元数据添加属性
root=metadata_dom#('report'):
对于l_参数项()中的k,v:
param_dom_element=ElementTree.element('parameter')
param_dom_element.attrib[“name”]=k
param_dom_element.text=v
追加(param_dom_元素)
#
metadata\u modified\u text=ElementTree.tostring(metadata\u dom,encoding='utf8',method='xml')
info(“添加参数(结束)[有效负载xml=%s]”%(元数据\u修改的\u文本))
返回元数据\u修改的\u文本
#03:REPORT-REQUEST-CALL
#调用以生成报告
def_uu ha
# views.py
from django_xhtml2pdf.views import PdfMixin
class GroupPDFGenerate(PdfMixin, DetailView):
model = PeerGroupSignIn
template_name = 'groups/pdf.html'
# templates/groups/pdf.html
<html>
<style>
@page { your xhtml2pdf pisa PDF parameters }
</style>
</head>
<body>
<div id="header_content"> (this is defined in the style section)
<h1>{{ peergroupsignin.this_group_title }}</h1>
...
# urls.py (using url namespaces defined in the main urls.py file)
url(
regex=r"^(?P<pk>\d+)/generate_pdf/$",
view=views.GroupPDFGenerate.as_view(),
name="generate_pdf",
),
import os
from weasyprint import HTML
from django.template import Template, Context
from django.http import HttpResponse
def generate_pdf(self, report_id):
# Render HTML into memory and get the template firstly
template_file_loc = os.path.join(os.path.dirname(__file__), os.pardir, 'templates', 'the_template_pdf_generator.html')
template_contents = read_all_as_str(template_file_loc)
render_template = Template(template_contents)
#rendering_map is the dict for params in the template
render_definition = Context(rendering_map)
render_output = render_template.render(render_definition)
# Using Rendered HTML to generate PDF
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename=%s-%s-%s.pdf' % \
('topic-test','topic-test', '2018-05-04')
# Generate PDF
pdf_doc = HTML(string=render_output).render()
pdf_doc.pages[0].height = pdf_doc.pages[0]._page_box.children[0].children[
0].height # Make PDF file as single page file
pdf_doc.write_pdf(response)
return response
def read_all_as_str(self, file_loc, read_method='r'):
if file_exists(file_loc):
handler = open(file_loc, read_method)
contents = handler.read()
handler.close()
return contents
else:
return 'file not exist'
from django.template.loader import get_template
import pdfkit
from django.conf import settings
context={....}
template = get_template('reports/products.html')
html_string = template.render(context)
pdfkit.from_string(html_string, os.path.join(settings.BASE_DIR, "media", 'products_report-%s.pdf'%(id)))