2014-11-26 1 views
1
class CSVDownload(View): 
    """ Prepares CSV file version to download """  

     #more code here 

     f = StringIO.StringIO() 
     writer = csv.writer(f, dialect='excel') 
     for v in visit_list: 
      writer.writerow([v.idfa.idfa, v.name, v.duration, v.firstSeen, v.lastSeen, v.identifier, v.closestProximity]) 
     f.seek(0) 
     response = HttpResponse(f, content_type='text/csv') 
     response['Content-Disposition'] = 'attachment; filename=AdvertiserData.csv' 

     return response 

По некоторым причинам, при открытии файла в Excel, файл будет выводиться только последний элемент в списке, см hereDjango/Python: CSV для в цикле перекрывая первую строку каждый раз через

Это заставляет меня думать, что каждая строка переопределяет первую строку. Хотя этого не должно быть. Посмотрите на эти тесты, которые я провел в терминале.

>>> f.getvalue() 
'FFAC6F6C-1B2E-47C2-8110-5E619B239FB1,PPTest1,00:00:24,2014-11-11 23:20:24.730000,2014-11-11 23:20:48.750000,nkfe-cnb7s,NEAR\r\nFFAC6F6C-1B2E-47C2-8110-5E619B239FB1,moo2,00:00:24,2014-11-11 23:20:24.730000,2014-11-11 23:20:48.750000,nkfe-cnb7s,NEAR\r\n' 

Это возвращает более одного значения, с \r\n между значениями.

Кроме того, я попытался

>>> print response 
Content-Type: text/csv 
Content-Disposition: attachment; filename=boo.csv 

FFAC6F6C-1B2E-47C2-8110-5E619B239FB1,PPTest1,00:00:24,2014-11-11 23:20:24.730000,2014-11-11 23:20:48.750000,nkfe-cnb7s,NEAR 
FFAC6F6C-1B2E-47C2-8110-5E619B239FB1,moo2,00:00:24,2014-11-11 23:20:24.730000,2014-11-11 23:20:48.750000,nkfe-cnb7s,NEAR 

И также показали более чем одно значение.

Я недавно увидел SO-поток, который обсуждает добавление в файл: How do you append to a file? Но так как я создаю этот элемент только в памяти (используя stringIO), как я могу получить тот же эффект?

Спасибо!

EDIT Для дополнительной информации:

visit_list скомпрометирован моделей визита:

class Visit(models.Model): 
    idfa = models.ForeignKey(Report) 
    name = models.CharField(max_length=255) 
    lastSeen = models.CharField(max_length=255) 
    duration = models.CharField(max_length=255) 
    firstSeen = models.CharField(max_length=255) 
    identifier = models.CharField(max_length=255) 
    closestProximity = models.CharField(max_length=255) 

    def __unicode__(self): 
     return self.name 

    class Meta: 
     verbose_name = "Visit" 
     verbose_name_plural = "Visits" 

В данном конкретном случае, visit_list возвращает:

>>> visit_list 
[<Visit: PPTest1>, <Visit: moo2>] 
+0

Что ваш 'visit_list' выглядеть? –

ответ

1

Bottom Line: Я подозреваю, что вам необходимо пройти f.getvalue() до HttpResponse, а не f.

Объяснение:

HttpResponse prefers strings, хотя она также может рассматриваться как объект файла или принимать итераторы. Тем не менее, f является экземпляром StringIO.StringIO, а не строкой как таковой.

Рассмотрим следующую установку:

import StringIO 
import csv 

>>> f = StringIO.StringIO() 
>>> writer = csv.writer(f, dialect='excel') 
>>> row = range(4)       # first row is [0, 1, 2, 3] 
>>> for i in range(5): 
     writer.writerow([row])    # write more rows 
     row = [x + 1 for x in row] 

>>> f.seek(0) 

Теперь сравните f с результатом f.getvalue():

# an instance 
>>> f 
<StringIO.StringIO instance at 0x03656990> 

# a string 
>>> f.getvalue() 
'"[0, 1, 2, 3]"\r\n"[1, 2, 3, 4]"\r\n"[2, 3, 4, 5]"\r\n"[3, 4, 5, 6]"\r\n"[4, 5, 6, 7]"\r\n' 

Теперь обратите внимание на разницу в response объекта при передаче экземпляра против строки в HttpResponse :

# The instance 
>>> response = HttpResponse(f, content_type='text/csv') # f is an instance 
>>> response['Content-Disposition'] = 'attachment; filename=AdvertiserData.csv' 
>>> response._container 
[''] 

# The string 
>>> response = HttpResponse(f.getvalue(), content_type='text/csv') # f.getvalue() returns a string 
>>> response['Content-Disposition'] = 'attachment; filename=AdvertiserData.csv' 
>>> response._container 
['"[0, 1, 2, 3]"\r\n"[1, 2, 3, 4]"\r\n"[2, 3, 4, 5]"\r\n"[3, 4, 5, 6]"\r\n"[4, 5 , 6, 7]"\r\n'] 

Обратите внимание, что атрибут ответа _container пуст, когда вы передаете экземпляр HttpResponse, но не пустым, когда вы передаете строку f.getvalue() на номер HttpResponse.

Я хотел бы попробовать это вместо того, чтобы, затем:

>>> response = HttpResponse(f.getvalue(), content_type='text/csv') 
>>> # etc. 
+0

Красивое объяснение, и ответ сработал. Хотя произошло что-то интересное. Я закончил тем, что запустил мой старый код (вернувшись только f) после запуска его через проверку PEP8 для проверки отступов/вкладок, и, похоже, он работал нормально. Я все еще не понимаю, как это произошло, потому что это буквально один и тот же код. даже пересмотры github не могли отличить друг от друга. Тем не менее, ваш ответ работает, и я думаю, что это лучший способ вернуть f. Спасибо, Джастин! – ApathyBear

+1

@ApathyBear Как интересно. Некоторое время я работал с вашим кодом и в конце концов обнаружил эти различия. Я никогда не получал никаких ошибок, которые предполагали, что вкладки будут проблемой, но это, безусловно, может быть так! В любом случае, я рад, что вы сейчас работали! –

Смежные вопросы