Django 视图设计 - 从用户生成的内容中导出 CSV



在我的 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所需的所有信息。

假设

  • 方法 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 模块并更改内容类型和内容处置标头(并提供下载。

这是一些代码 我的应用 urls.py

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

我的应用 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']]

核糖核酸.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 源代码 {{ cassettes|json_script:"cassette-json" }} 中的这一行(。我还有另一个脚本标签,其中我将磁带作为 json 分配给隐藏输入(名称为"盒式磁带数据"(。"下载CSV"按钮嵌入在另一种形式中,该表单将"盒式数据"作为有效载荷发送到myapp/download/csv。

我的应用 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 

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

  • >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错误。

我正在尝试找到一种方法,而不是在客户端对此对象进行锯齿化并在视图上反序列化它。

最新更新