我正嘗試將csv文件作爲附件下載進行流式處理。 CSV文件大小已達到4MB或更多,我需要一種方式讓用戶主動下載文件,而無需等待所有數據被創建並首先提交到內存。在Django中流式傳輸CSV文件
我第一次使用我自己的文件包裝基於Django的FileWrapper
類。那失敗了。然後我在這裏看到了一種使用發電機來流的響應: How to stream an HttpResponse with Django
當我在發電機內產生一個錯誤,我可以看到,我創建與get_row_data()
功能正確的數據,但是當我嘗試返回它回覆空的響應。我也禁用了Django GZipMiddleware
。有誰知道我做錯了什麼?
編輯:我遇到的問題是與ConditionalGetMiddleware
。我不得不更換它,代碼在下面的答案。
這裏是視圖:
from django.views.decorators.http import condition
@condition(etag_func=None)
def csv_view(request, app_label, model_name):
""" Based on the filters in the query, return a csv file for the given model """
#Get the model
model = models.get_model(app_label, model_name)
#if there are filters in the query
if request.method == 'GET':
#if the query is not empty
if request.META['QUERY_STRING'] != None:
keyword_arg_dict = {}
for key, value in request.GET.items():
#get the query filters
keyword_arg_dict[str(key)] = str(value)
#generate a list of row objects, based on the filters
objects_list = model.objects.filter(**keyword_arg_dict)
else:
#get all the model's objects
objects_list = model.objects.all()
else:
#get all the model's objects
objects_list = model.objects.all()
#create the reponse object with a csv mimetype
response = HttpResponse(
stream_response_generator(model, objects_list),
mimetype='text/plain',
)
response['Content-Disposition'] = "attachment; filename=foo.csv"
return response
這裏是我使用流式傳輸的響應發電機:
def stream_response_generator(model, objects_list):
"""Streaming function to return data iteratively """
for row_item in objects_list:
yield get_row_data(model, row_item)
time.sleep(1)
,這裏是我如何創建CSV行數據:
def get_row_data(model, row):
"""Get a row of csv data from an object"""
#Create a temporary csv handle
csv_handle = cStringIO.StringIO()
#create the csv output object
csv_output = csv.writer(csv_handle)
value_list = []
for field in model._meta.fields:
#if the field is a related field (ForeignKey, ManyToMany, OneToOne)
if isinstance(field, RelatedField):
#get the related model from the field object
related_model = field.rel.to
for key in row.__dict__.keys():
#find the field in the row that matches the related field
if key.startswith(field.name):
#Get the unicode version of the row in the related model, based on the id
try:
entry = related_model.objects.get(
id__exact=int(row.__dict__[key]),
)
except:
pass
else:
value = entry.__unicode__().encode("utf-8")
break
#if it isn't a related field
else:
#get the value of the field
if isinstance(row.__dict__[field.name], basestring):
value = row.__dict__[field.name].encode("utf-8")
else:
value = row.__dict__[field.name]
value_list.append(value)
#add the row of csv values to the csv file
csv_output.writerow(value_list)
#Return the string value of the csv output
return csv_handle.getvalue()
我還沒有流數據的需求,但很高興知道獲得簡單而優雅的東西有多快。 –
雖然我很喜歡這個答案,但事實證明,這不是我的問題。我從字面上使用了你寫的確切代碼,只是爲了看看它是否會產生響應,但響應回來爲0字節。所以我仍然堅持相同的結果。 – bfrederix
此代碼正常工作,因此您的環境出現問題,需要進行故障排除。 –