De la diffusion d'un fichier CSV dans Django
Je suis tenter de diffuser un fichier csv comme une pièce jointe à télécharger. Les fichiers CSV sont des indicateurs de 4 mo ou plus, et j'ai besoin d'un moyen pour l'utilisateur de activement télécharger les fichiers sans attendre que toutes les données soient créées et mémorisées en premier.
J'ai d'abord utilisé mon propre fichier wrapper basé sur Django FileWrapper
classe. Qui a échoué. Puis j'ai vu une méthode pour l'utilisation d'un générateur de flux de la réponse:
Comment diffuser une HttpResponse avec Django
Quand je lève une erreur à l'intérieur de la génératrice, je peux voir que je suis entrain de créer le bon de données avec le get_row_data()
fonction, mais quand j'ai essayer de retourner la réponse qu'il vient de revenir à vide. J'ai aussi désactivé le Django GZipMiddleware
. Personne ne sait ce que je fais mal?
Edit: Le problème j'ai eu a été avec le ConditionalGetMiddleware
. J'ai dû la remplacer, le code est dans la réponse ci-dessous.
Ici est le point de vue:
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
Ici est le générateur-je utiliser pour diffuser la réponse:
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)
Et voici comment j'ai créer le fichier csv des données de ligne:
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()
Vous devez vous connecter pour publier un commentaire.
Voici un code simple que vais diffuser un CSV; vous pouvez probablement aller à partir de ce que vous devez faire:
Ce simplement écrit chaque ligne d'un fichier de la mémoire, se lit la ligne et les rendements elle.
Cette version est plus efficace pour générer des données en vrac, mais assurez-vous de comprendre le ci-dessus avant de l'utiliser:
Le middleware problème a été résolu comme de Django 1.5 et un StreamingHttpResponse a été introduit. Ce qui suit devrait faire:
Il y a peu de documentation sur la façon de sortie csv à partir de Django mais il ne prend pas avantage de la
StreamingHttpResponse
donc je suis allé de l'avant et ouvert un ticket pour le suivre.Le problème que j'ai été avec le ConditionalGetMiddleware. J'ai vu django-piston venir avec un remplacement du middleware pour la ConditionalGetMiddleware qui permet le streaming:
Alors vous allez remplacer ConditionalGetMiddleware avec votre ConditionalMiddlewareCompatProxy middleware, et à votre avis (emprunté code à partir d'une réponse intelligente à cette question):