2011-02-28 25 views
17

Bir csv dosyasını ek indirme olarak kaydetmeye çalışıyorum. CSV dosyalarının boyutu 4 MB veya daha fazla olacak ve kullanıcının, önce belleğe oluşturulacak ve belleğe yüklenecek tüm verileri beklemeden dosyaları etkin bir şekilde indirebilmesi için bir yola ihtiyacım var.Django'da bir CSV dosyası akışı

İlk olarak Django'nun FileWrapper sınıfına dayanan kendi dosya sarıcımı kullandım. Bu başarısız oldu. Sonra tepkisini akışı için bir jeneratör kullanarak burada bir yöntem gördüm: Ben jeneratör içinde bir hata kaldırdıklarında How to stream an HttpResponse with Django

, ben get_row_data() fonksiyonu ile uygun veri oluşturma görüyoruz, ama ben çalıştığınızda cevabı geri döndüğünde geri döner. Ayrıca Django GZipMiddleware'u da devre dışı bıraktım. Yanlış yaptığımı bilen var mı?

Düzeltme: Sorun yaşıyorum ConditionalGetMiddleware ile oldu. Onu değiştirmek zorundaydım, kod aşağıda bir cevapta. İşte

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 

Ben tepkisini akarsu kullanmak jeneratör:

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() 
: Burada

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) 

Ve csv satır veri oluşturmak nasıl olduğunu Burada

görünümüdür

cevap

30

Burada bir CSV yayınlayacak bazı basit kodlar var; muhtemelen bundan yapmanız gereken ne olursa olsun gidebilir:

import cStringIO as StringIO 
import csv 

def csv(request): 
    def data(): 
     for i in xrange(10): 
      csvfile = StringIO.StringIO() 
      csvwriter = csv.writer(csvfile) 
      csvwriter.writerow([i,"a","b","c"]) 
      yield csvfile.getvalue() 

    response = HttpResponse(data(), mimetype="text/csv") 
    response["Content-Disposition"] = "attachment; filename=test.csv" 
    return response 

Bu sadece satır okur ve onu verir, bir bellek içi dosya her satırı yazar.

Bu sürüm toplu veri üretilmesi için daha etkili olmakla birlikte, kullanmadan önce, yukarıda anlama emin olun: I 'e sahip olan

import cStringIO as StringIO 
import csv 

def csv(request): 
    csvfile = StringIO.StringIO() 
    csvwriter = csv.writer(csvfile) 

    def read_and_flush(): 
     csvfile.seek(0) 
     data = csvfile.read() 
     csvfile.seek(0) 
     csvfile.truncate() 
     return data 

    def data(): 
     for i in xrange(10): 
      csvwriter.writerow([i,"a","b","c"]) 
     data = read_and_flush() 
     yield data 

    response = HttpResponse(data(), mimetype="text/csv") 
    response["Content-Disposition"] = "attachment; filename=test.csv" 
    return response 
+0

Henüz veri akışı ihtiyacım olmadı, ancak basit ve zarif bir şey elde etmenin ne kadar hızlı olduğunu bilmek güzel. –

+0

Bu cevabı gerçekten beğenmeme rağmen, bunun benim sorunum olmadığı ortaya çıkıyor. Tam olarak yazdığınız bu tam kodu kullandım, sadece bir yanıt üretip üretmeyeceğini görmek için, ancak yanıt 0 bayt olarak geri dönüyor. Yani hala aynı sonuca sıkıştım. – bfrederix

+0

Bu kod düzgün çalışıyor, bu nedenle sorun gidermeniz gereken ortamınızla ilgili bir sorun var. –

2

sorun ConditionalGetMiddleware oldu. Bu soruya akıllı bir cevap dan (ödünç kodu

from django.middleware.http import ConditionalGetMiddleware 

def compat_middleware_factory(klass): 
    """ 
    Class wrapper that only executes `process_response` 
    if `streaming` is not set on the `HttpResponse` object. 
    Django has a bad habbit of looking at the content, 
    which will prematurely exhaust the data source if we're 
    using generators or buffers. 
    """ 
    class compatwrapper(klass): 
     def process_response(self, req, resp): 
      if not hasattr(resp, 'streaming'): 
       return klass.process_response(self, req, resp) 
      return resp 
    return compatwrapper 

ConditionalMiddlewareCompatProxy = compat_middleware_factory(ConditionalGetMiddleware) 

Yani o zaman ConditionalMiddlewareCompatProxy katman ile ConditionalGetMiddleware yerini alacak, ve görünümde: Django-pistonlu akışı verir ConditionalGetMiddleware yerini katman ile gelip gördü):

def csv_view(request): 
    def data(): 
     for i in xrange(10): 
      csvfile = StringIO.StringIO() 
      csvwriter = csv.writer(csvfile) 
      csvwriter.writerow([i,"a","b","c"]) 
      yield csvfile.getvalue() 

    #create the reponse object with a csv mimetype 
    response = HttpResponse(
     data(), 
     mimetype='text/csv', 
     ) 
    #Set the response as an attachment with a filename 
    response['Content-Disposition'] = "attachment; filename=test.csv" 
    response.streaming = True 
    return response 
11

katman sorunu Django 1.5 itibariyle çözülmüştür ve bir StreamingHttpResponse tanıtıldı. Aşağıdaki yapmalıdır: Orada how to output csv from Django bazı belgeler var ama StreamingHttpResponse yüzden önde ve opened a ticket in order to track it gitti ve o yararlanmak gelmez

import cStringIO as StringIO 
import csv 

def csv_view(request): 
    ... 
    # Assume `rows` is an iterator or lists 
    def stream(): 
     buffer_ = StringIO.StringIO() 
     writer = csv.writer(buffer_) 
     for row in rows: 
      writer.writerow(row) 
      buffer_.seek(0) 
      data = buffer_.read() 
      buffer_.seek(0) 
      buffer_.truncate() 
      yield data 
    response = StreamingHttpResponse(
     stream(), content_type='text/csv' 
    ) 
    disposition = "attachment; filename=file.csv" 
    response['Content-Disposition'] = disposition 
    return response 

.

İlgili konular