如何在Django项目中下载python-docx生成的文档?

How to download a document generated with python-docx in Django project?

我正在尝试了解如何在我的 Django 应用程序中下载使用 python-docx 生成的 Word 文档(我仍在学习,这是我第一次使用文档);在 ajax 的帮助下,我将所有需要的信息发送到视图并调用使用该信息和 returns 文档的函数,然后我尝试发送该文档作为响应以便下载在我提交数据的同一模板中借助 "Download" 按钮(或显示 Web 浏览器下载对话框),但这是我卡住的地方。

将此文档作为响应发送,以便在我提交数据的同一模板中借助 "Download" 按钮(或显示网络浏览器下载对话框)下载它,但在这里是我卡住的地方。

我现在的情况是:

1) 在javascript我发送信息如下:

data = {
        categoria: cat,
        familia: fam,
        Gcas: gcas,
        FI: FI,
        FF: FF,
        Test: test,
        Grafica: grafica
    },
        $.ajax({
            type: 'post',
            headers: {
                "X-CSRFToken": csrftoken
            },
            url: url,
            data: { json_data: JSON.stringify(data) },

            success: function (response) {
                $('#instrucciones').hide(); //Hide a div with a message 
                $('#btndesc').show(); //Show the button to download the file generated                
            }
        });
    return false;
}

2) 在我的 Django 视图中:

def Documento(request):
    if request.method == "GET":
        context={}
        context['form'] = catForm
        return render(request, 'report/report_base.html', context)

    if request.method == 'POST':
    #Data from ajax
    datos = request.POST.get('json_data')
    jsondata = json.loads(datos)
    Gcas = jsondata['Gcas']
    FI = jsondata['FI']
    FF = jsondata['FF']
    grafica = jsondata['Grafica']
    #Using function to create the report
    Reporte = ReporteWord(Gcas, FI, FF, grafica)
    #Response
    response = HttpResponse(content_type='application/vnd.openxmlformats-
    officedocument.wordprocessingml.document')
    response['Content-Disposition'] = 'attachment; filename = "Reporte.docx"'
    response['Content-Encoding'] = 'UTF-8'
    Reporte.save(response)
    return response

3) 我创建文档的函数如下所示:

def ReporteWord( gcas, FI, FF, Chart):
    #Cargamos el template
    template = finders.find('otros/Template_reporte.docx')
    document = Document(template) 

    #Header
    logo = finders.find('otros/logo.png')
    header = document.sections[0].header
    paragraph = header.paragraphs[0]
    r = paragraph.add_run()
    r.add_picture(logo)

    #Adding title
    titulo = document.add_heading('', 0)
    titulo.add_run('Mi reporte').bold = True
    titulo.style.font.size=Pt(13)
    .
    Many other steps to add more content    
    .
    .
    #IF I SAVE THE FILE NORMALLY ALL WORKS FINE
    #document.save(r'C:\tests\new_demo.docx')

    return document

如果有任何想法或建议,我将不胜感激,非常感谢。

注意:我已经查看了这些答案(以及其他答案),但运气不佳。

Q1, Q2, Q3,

更新:感谢收到的反馈,我终于找到了如何生成文档并显示下载对话框:

正如所建议的那样,最好的实现方式是使用视图而不是 ajax,因此代码中的最终更新是:

a) 更新视图以按反馈

中所示工作

b) JavaScript - Ajax 对 POST 方法的控制被删除,现在所有的都直接用 python 处理(不需要额外的代码)

1) 查看:

def Reporte(request):
    if request.method == "GET":
        context={}
        context['form'] = catForm
        return render(request, 'reportes/reporte_base.html', context)

    if request.method == 'POST':
        #Getting data needed after submit the form in the page
        GcasID = request.POST.get('GCASS')
        FI = request.POST.get('dp1')
        FF = request.POST.get('dp2')
        Grafica = request.POST.get('options')

        #Function to obtain complete code from GcasID 
        Gcas =  GcasNumber(GcasID)

        #Report creation
        Reporte = ReporteWord(Gcas, FI, FF, Grafica)

        #PART UPDATED TO SHOW DOWNLOAD REPORT DIALOG
        bio = io.BytesIO()
        Reporte.save(bio)  # save to memory stream
        bio.seek(0)  # rewind the stream
        response = HttpResponse(
        bio.getvalue(),  # use the stream's contents
        content_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
    )

        response["Content-Disposition"] = 'attachment; filename = "Reporte.docx"'
        response["Content-Encoding"] = "UTF-8"
        return response

有了这些更改,当我按下 "Create report"(表单的提交按钮)时,一切都按预期工作(此外,不再需要更多的库)。最后,正如您所建议的那样,这样做比使用 ajax.

更容易

非常感谢大家的帮助。

Python-docx 的 Document.save() 方法接受流而不是文件名。因此,您可以初始化一个 io.BytesIO() 对象来保存文档,然后将其转储给用户。

Reporte = ReporteWord(Gcas, FI, FF, grafica)
bio = io.BytesIO()
Reporte.save(bio)  # save to memory stream
bio.seek(0)  # rewind the stream
response = HttpResponse(
    bio.getvalue(),  # use the stream's contents
    content_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
)
response["Content-Disposition"] = 'attachment; filename = "Reporte.docx"'
response["Content-Encoding"] = "UTF-8"
return response

如果您使用常规 link 或表单提交请求,这将有效,但由于您使用的是 $.ajax,您可能需要在浏览器端做额外的工作才能让客户端下载文件。不使用 $.ajax.

会更容易

是的,更简洁的选项,如 wardk 所述,使用 https://python-docx.readthedocs.org/:

from docx import Document
from django.http import HttpResponse

def download_docx(request):
    document = Document()
    document.add_heading('Document Title', 0)

    response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.wordprocessingml.document')
    response['Content-Disposition'] = 'attachment; filename=download.docx'
    document.save(response)

    return response

Know more