【问题标题】:Django/Python: CSV for-in loop overriding first row each time throughDjango / Python:CSV for-in循环每次都覆盖第一行
【发布时间】:2015-01-24 05:04:18
【问题描述】:
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中打开文件时,文件只会输出列表中的最后一项,见

这让我相信每一行都覆盖了第一行。虽然这不应该是这样。看看我在终端中进行的这些测试。

>>> 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),我怎样才能获得相同的效果?

谢谢!

编辑更多信息:

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>]

【问题讨论】:

  • 你的visit_list是什么样的?

标签: python django csv django-views stringio


【解决方案1】:

底线:我怀疑您需要将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)

现在将ff.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'

现在请注意在将实例与字符串传递给HttpResponseresponse 对象的区别:

# 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']

请注意,当您将实例传递给HttpResponse 时,响应的_container 属性为空,但当您将f.getvalue() 字符串传递给HttpResponse 时,为空。

我会试试这个,然后:

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

【讨论】:

  • 美丽的解释,并且回答有效。虽然发生了一些有趣的事情。通过 PEP8 检查缩进/制表符检查后,我最终运行了我的旧代码(仅返回 f),它似乎工作正常。我仍然对这是如何发生的感到困惑,因为它实际上是相同的代码。甚至 github 修订版也无法区分。不过,您的答案有效,我认为这是返回 f 的更好方法。谢谢贾斯汀!
  • @ApathyBear 多么有趣。我用你的代码工作了一段时间,最终发现了这些差异。我从来没有收到任何提示标签会成为问题的错误,但肯定是这样!无论如何,我很高兴您现在可以使用它!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-11-25
  • 1970-01-01
  • 2019-06-08
  • 1970-01-01
  • 2019-07-07
  • 1970-01-01
  • 2016-07-17
相关资源
最近更新 更多