我尝试从存储在我的数据库中的对象生成CSV,然后将csv作为附件添加到电子邮件中。
我正在使用Django 1.7& Python 2.7。
我使用以下代码收到此错误:"属性错误:' _csv.writer'对象没有属性'编码'"
这是我的代码:
def export_as_csv(report, fields, force_fields):
print "export to csv started"
"""
Generic csv export admin action.
based on http://djangosnippets.org/snippets/2020/
extended for being able to give list_display as fields and work with admin-defined functions
"""
opts = report
if not force_fields:
field_names = set([field.name for field in opts.fields])
if fields:
fieldset = set(fields)
field_names = field_names & fieldset
elif fields:
field_names = set(fields)
else:
raise("option force_fields can only be used in parallel with option fields")
writer = csv.writer(open("myfile.csv","w"), delimiter=',',quoting=csv.QUOTE_ALL)
writer.writerow(list(field_names))
row = []
for field in field_names:
try:
row.append(unicode(getattr(report, field)).encode('utf-8'))
except AttributeError:
row.append(unicode((getattr(report, field)(report))).encode('utf-8'))
except:
raise
writer.writerow(row)
response = writer
return response
下面的代码将上述函数的输出作为mail.attach()中的参数返回。 报告参数是我创建的数据库模型/对象&在调用任何代码之前保存。
list_display = ('primary_id', 'created_date', 'report_size',)
mail = EmailMessage('Email Subject', 'Email Body', None, ['example@example.com'])
mail.attach("report.csv", export_as_csv(report, fields = list_display, force_fields=True) , "text/csv")
mail.send()
这是Report()对象的模型:
class Report(models.Model):
primary_id = models.IntegerField('Primary Key', primary_key = True, default=0)
created_date = models.DateTimeField('Created date', default=timezone.now)
report_size = models.IntegerField('Report Size', default=0)
非常感谢任何帮助。
以下是理想情况下我希望此代码如何工作:export_as_csv()返回一个我不需要保存为文件或数据库的CSV对象 - 然后代码将其附加到电子邮件中直接来自内存中的CSV对象,而不是已保存的文件。不确定这是否可行,但这对我的需求是理想的。
答案 0 :(得分:1)
csvwriter
可以使用write()
方法写入任何对象。当您需要内存中的文件类对象时,通常使用的Python类是the docs实例,如果您确定不会向其编写Unicode对象,则使用cStringIO
。因此,您的export_to_csv
函数应该类似于:
import cStringIO
def export_as_csv(report, fields, force_fields):
# define field_names as above, assuming your indentation is correct
csv_buffer = cStringIO.StringIO()
writer = csv.writer(csv_buffer, delimiter=',', quoting=csv.QUOTE_ALL)
field_names = list(field_names) # loses order, but at least it's consistent
writer.writerow(field_names)
row = []
for field in field_names:
row.append(getattr(report, field).encode('utf-8'))
writer.writerow(row)
return csv_buffer
然后像:
mail.attach("report.csv", export_as_csv(report, fields=list_display, force_fields=True).getvalue() , "text/csv")
主要区别是:
1)csv_buffer
是一个内存中的文件对象。没有任何内容写入文件系统。
2)这将处理您在示例代码中显示的简单模型字段'primary_id', 'created_date', 'report_size'
的字段查找。如果您确实需要处理field_names
序列中的可调用名称,则会变得更难。
3)在转换为列表后,它使用单个变量来保存field_names
。它可能会使用list(field_names)
和for field in field_names
而field_names
是一个集合,Python集和字典应该是顺序稳定的,只要不做任何修改,但我发现它更清晰,关于确保订单同步更明确更明确。
4)这将返回cStringIO.StringIO
对象而不是编写器。一旦你写下你想要的一切,作家的工作就完成了。相反,当您在其上调用cStringIO
时,getvalue()
对象应返回缓冲的CSV内容。