Tôi đang cố phát tệp csv dưới dạng tệp tải xuống tệp đính kèm. Các tệp CSV có kích thước 4MB trở lên và tôi cần một cách để người dùng chủ động tải xuống tệp mà không phải chờ tất cả dữ liệu được tạo và cam kết với bộ nhớ trước.Truyền trực tuyến tệp CSV ở Django
Lần đầu tiên tôi sử dụng trình bao bọc tệp của riêng mình dựa trên lớp FileWrapper
của Django. Điều đó thất bại. Sau đó, tôi nhìn thấy một phương pháp vào đây để sử dụng một máy phát điện để dòng phản ứng: How to stream an HttpResponse with Django
Khi tôi nâng cao một lỗi trong máy phát điện, tôi có thể thấy rằng tôi đang tạo ra các dữ liệu phù hợp với get_row_data()
chức năng, nhưng khi tôi cố gắng trả về phản hồi nó trở lại trống rỗng. Tôi cũng đã vô hiệu hóa Django GZipMiddleware
. Có ai biết tôi đang làm gì sai không?
Chỉnh sửa: Vấn đề tôi gặp phải là với ConditionalGetMiddleware
. Tôi đã phải thay thế nó, mã trong một câu trả lời dưới đây.
Dưới đây là quan điểm:
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
Dưới đây là các máy phát điện tôi sử dụng để truyền các phản ứng:
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)
Và đây là làm thế nào tôi có thể tạo dữ liệu csv hàng:
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()
Tôi chưa có nhu cầu truyền dữ liệu, nhưng thật tuyệt khi biết nhanh như thế nào để có được thứ gì đó đơn giản và thanh lịch. –
Mặc dù tôi thực sự thích câu trả lời này, nó chỉ ra rằng đây không phải là vấn đề của tôi. Tôi đã sử dụng chính xác mã này chính xác mà bạn đã viết, chỉ để xem liệu nó có tạo ra một phản hồi hay không, nhưng phản hồi trả về là 0 byte. Vì vậy, tôi vẫn bị mắc kẹt với cùng một kết quả. – bfrederix
Mã này hoạt động tốt, vì vậy có điều gì đó không ổn với môi trường của bạn mà bạn sẽ cần khắc phục sự cố. –