【问题标题】:Django view design - export CSV from user-generated contentDjango 视图设计 - 从用户生成的内容中导出 CSV
【发布时间】:2020-09-01 02:32:13
【问题描述】:

在我的 Django 应用程序中,用户会为每个请求获得一个唯一的(部分随机的)输出。 我想允许用户下载与 CSV 完全相同的输出(显示在 HTML 表中)。

我的困难是如何设计这个流程,以便从form.generate_cassettes() 生成的result 将用于 csv 导出。

导出逻辑应该去哪里? 在我看来,csv 响应应该位于哪里? HTML 页面中的“导出到 csv”按钮应该调用什么?

这是我的 django 应用程序中的视图:

def generate_rna(request):
if request.method == 'POST':
    form = RNAGeneratorForm(request.POST)

    if form.is_valid():
        result = form.generate_cassettes()
        context = {
            "form": form,
            "cassettes": result
        }

        return render(request, 'rnagen/RNA.html', context)

else:
    form = RNAGeneratorForm()

context = {
    "form": form
}

return render(request, 'rnagen/RNA.html', context)

"cassettes": result 和输入表单(字段名称string)是生成 csv 所需的所有信息。

【问题讨论】:

    标签: python django django-rest-framework django-forms django-views


    【解决方案1】:
    • cassettes是一个包含django模型对象sequence的对象

    • sequence 有自己的 get_type 和 score 属性需要解析:

        class Cassette:
        def __init__(self):
            self.sequences = []  # list of BaseSequences
            self.score = 0.0     # total cassette score
            self.scores = {}     # score per protein
    
        def add(self, sequence):
            self.sequences.append(sequence)
            self.score += sequence.score
    
            if isinstance(sequence, Binding):
                sequence_type = sequence.get_type()
                self.scores[sequence_type] = self.scores.get(sequence_type, 0) + sequence.score
    
        def add_list(self, sequence_list):
            for s in sequence_list:
                self.add(s)
    
    

    所以我得到Object of type Cassette is not JSON serializable 错误。

    我正在尝试找到一种方法来在客户端序列化此对象并在视图上反序列化它。

    【讨论】:

      【解决方案2】:

      假设

      • generate_cassettes() 方法会生成一个不会导致任何内存问题的小型数据集。
      • 没有使用模型(因此也没有使用模型实例)。

      方法

      • 我们有 2 个视图,即 generate_rna 和 download_csv。 generate_rna 指向 myapp/(在我的情况下,它通常可以指向其他任何需要的东西),而 download_csv 指向 myapp/download/csv(在我的情况下,它通常可以指向其他任何需要的东西)。
      • 当您点击 GET myapp/ 时,generate_rna 会呈现一个空表单
      • 当您点击 POST myapp/ 时,generate_rna 会接收用户提交的数据并对其进行验证,如果数据有效,它会调用 generate_cassettes,在其中创建数据,然后呈现一个包含填充数据的表单,一个表格显示了 generate_cassettes 生成的数据,还显示了一个“下载 CSV”按钮
      • 当您使用磁带数据(由 generate_cassettes 生成)作为有效负载点击 POST myapp/download/csv 时,它会从数据中创建一个 csv 文件(使用 python csv 模块并更改 Content-Type 和 Content-Disposition 标头)并提供供下载。

      这是一些代码 myapp urls.py

      from django.urls import path
      from .views import generate_rna, download_csv
      urlpatterns = [
          path('', generate_rna),
          path('download/csv/', download_csv)
      ]
      

      myapp forms.py

      from django import forms
          class RNAGeneratorForm(forms.Form):
              name = forms.CharField(max_length=100)
              price = forms.DecimalField(decimal_places=2)
              def generate_cassettes(self):
                  #The behaviour of this function is not given in question and hence is assumed.
                  return [['Name', 'Price'], ['Cassette 1', '130'], ['Cassette 2', '140']]
      

      RNA.html

      <html>
          <head>
              <style>
                  table, th, td {
                    border: 1px solid black;
                  }
              </style>
              <title> RNA Form </title>
          </head>
      <body>
          <!-- This form takes input from user -->
      <form action="/myapp/" method="POST">
          {% csrf_token %}
          {{ form }}
          <input type="submit" value = "Submit" />
      </form>
      
      {% if cassettes %}
      
      <table>
          <tr>
              {% for column_name in cassettes.0 %}
                  <th> {{ column_name }} </th>
              {% endfor %}
          </tr>
          {% for row in cassettes|slice:"1:" %}
          <tr>
              {% for column in row %}
                  <td> {{ column }} </td>
              {% endfor %}
          </tr>
          {% endfor %}
      </table>
      
      <form action="/myapp/download/csv/" method="POST">
          {% csrf_token %}
          <input type="submit" value="Download CSV">
          <input type="hidden" id="cassette-data" name="cassette-data">
      </form>
      {{ cassettes|json_script:"cassette-json" }}
      <script>
          document.getElementById("cassette-data").value = document.getElementById("cassette-json").textContent;
      </script>
      {% else %}
      No Cassettes
      {% endif %}
      </body>
      </html> 
      

      RNA.html 中使用的方法

      • 如果存在磁带(例如,如果服务器响应 POST myapp/),我会将数据呈现为表格并显示“下载 CSV 按钮”。如果你看到这个链接https://docs.djangoproject.com/en/3.0/ref/templates/builtins/#json-script, 通过使用 json_script,有一种方法可以以 json 的形式公开对象。然后我有一个 ID 为“cassette-json”的脚本(请参阅 html 源代码 {{cassette|json_script:"cassette-json" }} 中的这一行)。我有另一个脚本标签,我在其中将磁带作为 json 分配给隐藏的输入(名称为“cassette-data”)。 “下载 CSV”按钮嵌入在另一种形式中,将“盒式数据”作为有效负载发送到 myapp/download/csv。

      myapp views.py

      from django.shortcuts import render, HttpResponse
      from .forms import RNAGeneratorForm
      import csv
      import json
      
      def generate_rna(request):
          if request.method == 'POST':
              form = RNAGeneratorForm(request.POST)
              if form.is_valid():
                  result = form.generate_cassettes()
                  context = {
                      "form": form,
                      "cassettes": result
                  }
      
                  return render(request, 'myapp/RNA.html', context)
      
          else:
              form = RNAGeneratorForm()
      
          context = {
              "form": form
          }
      
          return render(request, 'myapp/RNA.html', context)
      
      def download_csv(request):
          if request.method == 'POST':
              data = request.POST
              response = HttpResponse(content_type='text/csv')
              response['Content-Disposition'] = 'attachment; filename="cassettes.csv"'
      
              csv_writer = csv.writer(response)
              for row in json.loads(data['cassette-data']):
                  print(row)
                  csv_writer.writerow(row)
              return response 
      

      如有任何疑问,请与我们联系。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-01-05
        • 1970-01-01
        • 1970-01-01
        • 2011-05-03
        • 2018-09-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多