用cherrypy下载docxtpl生成的文件

时间:2016-07-29 11:33:14

标签: python cherrypy

我正在使用docxtpl生成word文档,并想知道用户使用cherrypy生成后如何下载此文件,请参阅下面的代码。

我能想出的唯一解决方案是将其保存到www文件夹并创建指向该位置的链接,但我确信这可以简化。

代码:

import os, os.path
import random
import string
import cherrypy
from docxtpl import DocxTemplate
import sys
from auth import AuthController, require, member_of, name_is
import socket

reload(sys)  
sys.setdefaultencoding('utf8')
cherrypy.config.update({'server.socket_port': 8000})
cherrypy.server.socket_host = '0.0.0.0'
cherrypy.engine.restart()

class Root(object):

    _cp_config = {
        'tools.sessions.on': True,
        'tools.auth.on': True    }

    @cherrypy.expose()
    def default(self, **kwargs):
        print kwargs    
        if kwargs.get('csa_no'):
#             print kwargs.get('csa_no')
            tpl=DocxTemplate('csa_tpl.docx')            
            sd = tpl.new_subdoc()
            p = sd.add_paragraph('This 1st insert')
            sd2 = tpl.new_subdoc()
            p = sd2.add_paragraph('This 2nd insert')
            context1 = {
                    'date': 'jkh',
                    'company_name' : 'Test Footer',
                    'cost' : '10,000',
                    'project_description': kwargs['project_description'],
                    'site': kwargs['site'],
                    'sp': kwargs['sp'],
                    'wo': kwargs['WO'],
                    'contract_manager': kwargs['contract_manager'],
                    'csa_no': kwargs['csa_no'],
                    'variation_reason': kwargs['variation_reason'],
                    'variation_scope_of_works': kwargs['variation_scope_of_works'],

                    'Initial_Contract_Value': '$300,000',
                    'variation_total': '$20,000',
                    'Ammended_Contract_Value': '$320,000',
                    'project_manager': kwargs['project_manager'],
                    'construction_manager': 'Dane Wilson',
                    'date': '30/04/2016',    
                }
            tpl.render(context1)
            file_name_with_path = '/var/www/html/csa_documents/' + kwargs['sp'] + '-'+ kwargs['WO'] + '_' + kwargs['site'] + '_-_' + 'CSA' + kwargs['csa_no'] +'.docx'
            file_name = kwargs['sp'] + '-'+ kwargs['WO'] + '_' + kwargs['site'] + '_-_' + 'CSA' + kwargs['csa_no'] +'.docx'
            print file_name
            print file_name_with_path
            tpl.save(file_name_with_path)
            return '''

            <!DOCTYPE html>
            <html>
            <head>
            <meta name="viewport" content="width=device-width, initial-scale=1">
            <meta charset="utf-8" http-equiv="X-UA-Compatible" content="IE=9" />
            <link href="//ajax.googleapis.com/ajax/libs/jquerymobile/1.4.2/jquery.mobile.min.css" rel="stylesheet">
            <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
            <script src="//ajax.googleapis.com/ajax/libs/jquerymobile/1.4.2/jquery.mobile.min.js"></script>
            <title>Broadspectrum</title>
            </head>
            <body>
            <div data-role="header" data-theme="b">
            <h1>TCSS Gateway</h1>
            </div>
            <h2>Success</h2>
            <a href="http://192.168.1.7">another submission</a>
            <a href="http://192.168.1.7/csa_documents/%s">Download & Review CSA Document</a>
            </body>

            ''' % file_name

1 个答案:

答案 0 :(得分:1)

简短的回答是,基本上你需要编写一些内存中的流(例如BytesIO),预先设置一些HTTP头并返回file_generator。 你的问题与一个月前提出的问题几乎相同,here是我对它的回答。

我已经在python3中为你起草了一个小片段:

from io import BytesIO

import cherrypy
from cherrypy.lib import file_generator

from docxtpl import DocxTemplate


class GenerateDocx:
    @cherrypy.expose
    def build_docx(self, *args, **kwargs):
        iostream = BytesIO()

        tpl = DocxTemplate('csa_tpl.docx')
        ...
        # build your tpl here
        ...
        tpl.get_docx().save(iostream)

        cherrypy.response.headers['Content-Type'] = (
            # set the correct MIME type for docx
            'application/vnd.openxmlformats-officedocument'
            '.wordprocessingml.document'
        )
        cherrypy.response.headers['Content-Disposition'] = (
            'attachment; filename={fname}.docx'.format(
                fname='put your file name here'
            )
        )

        iostream.seek(0)
        return file_generator(iostream)

UPD:我刚检查了the response body gets automatically wrapped with file_generator if the return value of a handler has read() method support