Django 4, how can I download a generated CSV file to browser while passing additional context to template?

huangapple go评论137阅读模式
英文:

Django 4, how can I download a generated CSV file to browser while passing additional context to template?

问题

In views.py,我有一个视图,向用户显示发票信息,并有一个按钮用于创建批量支付文件。当点击按钮时,它会读取一个CSV模板文件,然后从数据库中更新数据创建一个新的CSV文件,然后直接下载到浏览器。

同时,我想返回一些上下文信息以生成有关处理状态的通知,返回错误消息等。似乎我需要通过多个HTTP请求/响应来实现这一点,但我不确定如何去做。

这是视图:

  1. class InvoiceView(TemplateView):
  2. model = Cost
  3. template_name = "pipeline/invoices_list.html"
  4. costs = Cost.objects.all()
  5. def get_context_data(self, **kwargs):
  6. # 一些上下文数据
  7. return context
  8. def post(self, request, *args, **kwargs):
  9. if "batch-pay-csv" in request.POST:
  10. response, batch_payment_status = create_batch_payment_template(self.costs)
  11. context = self.get_context_data(**kwargs)
  12. context['batch_payment_status'] = batch_payment_status
  13. return response

以下是create_batch_payment_file()函数的缩写版本(在utils.py中):

  1. def create_batch_payment_file(costs):
  2. '''
  3. 从/static中的模板创建批量支付文件。
  4. '''
  5. invoices = costs.filter(invoice_status__in=["REC", "REC2"])
  6. processing_status = {} # 格式:发票PO号 {状态(成功/错误),消息}
  7. response = HttpResponse(
  8. content_type='text/csv',
  9. headers={'Content-Disposition': 'attachment; filename="WISE_BATCH_PAYMENT.csv"'},
  10. )
  11. # 对于每个发票,将数据写入CSV
  12. context = processing_status
  13. return response, context

我开始认为在模板上生成一个下载按钮可能会更容易,而不是尝试自动下载到浏览器,但很乐意听听任何想法。

英文:

In views.py, I have a view that displays invoice information to the user, and a button for creating a batch payment file. When the button is clicked, a CSV template file is read, and a new CSV is created from that template with updated with data from the database, and then downloaded directly to the browser.

At the same time, I want to return some context to generate toast notifications about the processing status, return error messages, etc. It seems I need to do this via multiple HTTP requests/responses, and I'm not sure how to go about it.

Here's the view:

  1. class InvoiceView(TemplateView):
  2. model = Cost
  3. template_name = "pipeline/invoices_list.html"
  4. costs = Cost.objects.all()
  5. def get_context_data(self, **kwargs):
  6. # some context data
  7. return context
  8. def post(self, request, *args, **kwargs):
  9. if "batch-pay-csv" in request.POST:
  10. response, batch_payment_status = create_batch_payment_template(self.costs)
  11. context = self.get_context_data(**kwargs)
  12. context['batch_payment_status'] = batch_payment_status
  13. return response

and an abbreviated version of the create_batch_payment_file() function (in utils.py):

  1. def create_batch_payment_file(costs):
  2. '''
  3. Create a batch payment file from the template in /static.
  4. '''
  5. invoices = costs.filter(invoice_status__in=["REC", "REC2"])
  6. processing_status = {} # format: invoice PO number {status (success/error), message}
  7. response = HttpResponse(
  8. content_type='text/csv',
  9. headers = {'Content-Disposition': 'attachment; filename = "WISE_BATCH_PAYMENT.csv"'},
  10. )
  11. # for invoice in invoices, write stuff to the CSV
  12. context = processing_status
  13. return response, context

I'm starting to think it would be easier to generate a download button on the template rather than try to automatically download it to the browser, but would love to hear any ideas.

答案1

得分: 1

搞清楚了!我将其从实用函数更改为views.py中的视图,以便我可以通过AJAX调用它,并将数据字典传递给HttpResponse对象的头文件。

  1. def create_batch_payment_file(request):
  2. '''
  3. 从/static中的模板创建批量付款文件。
  4. '''
  5. invoices = Cost.objects.filter(invoice_status__in=["REC", "REC2"])
  6. processing_status = {} # 格式:发票PO号 {状态(成功/错误),消息}
  7. response = HttpResponse(
  8. content_type='text/csv',
  9. headers={'Content-Disposition': 'attachment; filename="WISE_BATCH_PAYMENT.csv"'},
  10. )
  11. # 对于每张发票,将内容写入CSV
  12. data = processing_status
  13. response['X-Processing-Status'] = json.dumps(data)
  14. return response

然后在客户端进行AJAX调用:

  1. $("#batch-payment-create").on("submit", function(e) {
  2. e.preventDefault()
  3. const csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value;
  4. $.ajax({
  5. headers: { 'X-CSRFToken': csrftoken },
  6. type: "POST",
  7. url: "/myapp/myview/",
  8. data: "",
  9. success: function(data, testStatus, xhr) {
  10. var blob = new Blob([data]);
  11. var link = document.createElement('a');
  12. var processing_status = xhr.getResponseHeader('X-Processing-Status');
  13. console.log('Processing status:', processing_status);
  14. link.href = window.URL.createObjectURL(blob);
  15. link.download = "WISE_batch_payment.csv";
  16. link.click();
  17. }
  18. })
  19. })

希望对其他人有所帮助!

英文:

Figured it out! Instead of using it as a utility function, I turned it into a view in views.py so I could call it with AJAX, and passed the data dict into the headers of the HttpResponse object.

  1. def create_batch_payment_file(request):
  2. '''
  3. Create a batch payment file from the template in /static.
  4. '''
  5. invoices = Cost.objects.filter(invoice_status__in=["REC", "REC2"])
  6. processing_status = {} # format: invoice PO number {status (success/error), message}
  7. response = HttpResponse(
  8. content_type='text/csv',
  9. headers = {'Content-Disposition': 'attachment; filename = "WISE_BATCH_PAYMENT.csv"'},
  10. )
  11. # for invoice in invoices, write stuff to the CSV
  12. data = processing_status
  13. response['X-Processing-Status'] = json.dumps(data)
  14. return response

Then on the client side, made an AJAX call:

  1. $("#batch-payment-create").on("submit", function(e) {
  2. e.preventDefault()
  3. const csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value;
  4. $.ajax({
  5. headers: { 'X-CSRFToken': csrftoken },
  6. type: "POST",
  7. url: "/myapp/myview/",
  8. data: "",
  9. success: function(data, testStatus, xhr) {
  10. var blob = new Blob([data]);
  11. var link = document.createElement('a');
  12. var processing_status = xhr.getResponseHeader('X-Processing-Status');
  13. console.log('Processing status:', processing_status);
  14. link.href = window.URL.createObjectURL(blob);
  15. link.download = "WISE_batch_payment.csv";
  16. link.click();
  17. }
  18. })
  19. })

Hopefully this helps someone else!

huangapple
  • 本文由 发表于 2023年5月13日 10:34:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76240848.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定