渲染为XLSX

如果我们希望有一个渲染器始终使用与主渲染器相同的数据(如mako或jinja2),但将其渲染为其他对象,例如XLSX,该怎么办?然后我们可以这样做:

 1# the first view_config for the xlsx renderer that
 2# kicks in when there is a request parameter xlsx
 3@view_config(context="myapp.resources.DBContext",
 4             renderer="dbtable.xlsx",
 5             request_param="xlsx")
 6# the second view_config for mako
 7@view_config(context="myapp.resources.DBContext",
 8             renderer="templates/dbtable.mako")
 9def dbtable(request):
10    # any code that prepares the data
11    # this time, the data have been loaded into context
12    return {}

这意味着 custom renderers 是不够的。我们必须定义一个模板系统。我们的渲染器必须查找模板,渲染它,并作为一个XLSX文档返回。

让我们定义模板接口。我们的模板将是放置在项目的 xlsx 子目录,定义了两个函数:

  • get_header 将返回表标题单元格

  • iterate_rows 将生成表行

我们的渲染器必须:

  • 导入模板

  • 运行函数以获取数据

  • 将数据放入XLSX文件

  • 返回文件

因为我们的模板将是python文件,所以我们将使用一个技巧。在 view_config 我们将模板的后缀改为 .xlsx 这样我们就可以配置视图。在渲染器中,我们用 .py 后缀而不是 .xlsx .

将以下代码添加到名为 xlsxrenderer.py 在您的应用程序中。

 1import importlib
 2
 3import openpyxl
 4import openpyxl.styles
 5import openpyxl.writer.excel
 6
 7
 8class XLSXRenderer(object):
 9    XLSX_CONTENT_TYPE = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
10    def __init__(self, info):
11        self.suffix = info.type
12        self.templates_pkg = info.package.__name__ + ".xlsx"
13
14    def __call__(self, value, system):
15        templ_name = system["renderer_name"][:-len(self.suffix)]
16        templ_module = importlib.import_module("." + templ_name, self.templates_pkg)
17        wb = openpyxl.Workbook()
18        ws = wb.active
19        if "get_header" in dir(templ_module):
20            ws.append(getattr(templ_module, "get_header")(system, value))
21            ws.row_dimensions[1].font = openpyxl.styles.Font(bold=True)
22        if "iterate_rows" in dir(templ_module):
23            for row in getattr(templ_module, "iterate_rows")(system, value):
24                ws.append(row)
25
26        request = system.get('request')
27        if not request is None:
28            response = request.response
29            ct = response.content_type
30            if ct == response.default_content_type:
31                response.content_type = XLSXRenderer.XLSX_CONTENT_TYPE
32            response.content_disposition = 'attachment;filename=%s.xlsx' % templ_name
33
34        return openpyxl.writer.excel.save_virtual_workbook(wb)

现在有了渲染器。我们在申请表上登记一下 Configurator

config.add_renderer('.xlsx', 'myapp.xlsxrenderer.XLSXRenderer')

Of course, you need to modify the dotted-string to point to the module location you decided upon. You must also write the templates in the directory myapp/xlsx ,如 myapp/xlsx/dbtable.py . 下面是一个虚拟模板的示例:

1def get_header(system, value):
2    # value is the dictionary returned from the view
3    # request = system["request"]
4    # context = system["context"]
5    return ["Row number", "A number", "A string"]
6
7def iterate_rows(system, value):
8    for row in range(100):
9        return [row, 100, "A string"]

要查看此方法的工作示例,请访问:

这里有一个捷克版本的配方:

有关如何添加自定义渲染器的详细信息,请参阅 Pyramid 文档和 Pyramid 技术体系说明手册的以下部分: