【问题标题】:Django/Jinja2 : Generate (data for) CSV via template syntaxDjango/Jinja2:通过模板语法生成(数据)CSV
【发布时间】:2013-02-21 21:49:17
【问题描述】:

我想使用类似模板的语法为 CSV 文件(或任何合理的导出格式)生成数据,以访问我的 django 对象的字段。例如,输出字段的规范可能是:

employee.id
employee.manager.first_name
employee.user.last_login
employee.contact.phone_number

字段的指定语法与我在 Django 或 Jinja2 模板中使用的语法相同。

我也希望能够像在 django/jinja 模板中一样使用过滤器:

employee.user.last_login|date:"c"

鉴于此规范和对象列表,我想从我的对象中生成数据行。然后我可以从这些数据中生成 CSV、XML 等。

我开始写一些东西来做这个,但它很快变得复杂,我想我可能可以使用一些现有的 Django/Jinja2 模板引擎。

有什么东西可以让我通过 Django/Jinja2 语法访问我的对象吗?

【问题讨论】:

  • 你的问题超级不清楚。 “允许我通过 Django 语法访问我的对象的东西”?嗯,除了说“employee.id”?什么?
  • 或者你不知道什么是查询集?
  • 我知道什么是查询集,而且我手头有一个查询集。我不确定如何澄清 - 我想通过 django/jinja 语法指定我感兴趣的字段,并使用它从我的查询集中生成数据。
  • 只是...循环查询集中的每个结果并完全按照您正在做的事情。对不起,我真的很困惑对哪一部分感到困惑。

标签: python django csv jinja2


【解决方案1】:

首先,使用csv 模块以外的任何技术生成 CSV 数据不会为您赢得很多朋友;这是完成这项工作的正确工具。

使用该模块生成输出最方便的方法是使用writer.writerows(),它采用嵌套列表(或者更确切地说,是序列的迭代器)。生成器是准确表达这一点的好方法:

def csv_spec(queryset):
    for employee in queryset:
        yield (
            employee.id,
            employee.manager.first_name,
            employee.user.last_login,
            employee.contact.phone_number)

w = csv.writer(outfile)
w.writerows(csv_spec(something))

编辑:所以您说您想要模板之类的东西,原因与我们使用模板的原因相同,但生成的是 CSV 而不是文本。您可以要求 jinja 解析和处理它在其中的各种表达式 没有完整模板的占位符。

假设我们有一些数据:

>>> from collections import namedtuple
>>> from datetime import datetime
>>> Employee = namedtuple('Employee', 'id manager user contact')
>>> Person = namedtuple('Person', 'first_name last_name')
>>> Account = namedtuple('Account', 'username password last_login')
>>> Contact = namedtuple('Contact', 'phone_number email')
>>> data = [
...     Employee(0, Person('Alice', 'Brown'),
...              Account('abrown', 'secret', datetime(2013, 3, 3)),
...              Contact('5551234', 'abrown@example.com')),
...     Employee(1, Person('Bob', 'Jones'),
...              Account('bjones', 'safe', datetime(2013, 3, 3)),
...              Contact('5555678', 'bjones@example.com')),
...     Employee(2, Person('Carol', 'Smith'),
...              Account('csmith', 'hidden', datetime(2013, 3, 3)),
...              Contact('5559012', 'csmith@example.com'))]

和一个模板(你可以很容易地从文件中读取它)

>>> import StringIO
>>> template = StringIO.StringIO('''employee.id
... employee.manager.first_name
... employee.user.last_login
... employee.contact.phone_number''')

要使用表达式编译器,您需要一个环境;不需要任何选项 指定:

>>> import jinja2
>>> env = jinja2.Environment()
>>> template_filter = map(env.compile_expression, template)

正如我提到的,使用 csv 模块:

>>> import csv
>>> import sys
>>> writer = csv.writer(sys.stdout)

最后,通过编译后的表达式,我们可以遍历数据,一行“行”在 一次,对于每一行,应用每个表达式

>>> writer.writerows([[field(employee=row) for field in template_filter]
...                   for row in data])
0,Alice,2013-03-03 00:00:00,5551234
1,Bob,2013-03-03 00:00:00,5555678
2,Carol,2013-03-03 00:00:00,5559012

【讨论】:

  • 谢谢 TokenMacGuy,这正是我想要做的,但是我输出的项目列表(以及顺序)在编程时是未知的——也就是说,你在yield 部分由用户在运行时定义。我正在寻找的是一种完全按照您在此处显示的内容的方法,但是使用最终用户定义的进入产量部分的项目(例如,通过在文本文件中指定它们)。
【解决方案2】:

Django 文档是一个很好的资源 - http://docs.python.org/2/library/csv.html

您只需要知道python中用于访问对象属性的点表示法。

【讨论】:

  • 然而,一件坏事是他们忘记使用.writerows而只使用.wrtiterow
猜你喜欢
  • 1970-01-01
  • 2018-05-22
  • 2022-01-12
  • 2020-05-27
  • 1970-01-01
  • 1970-01-01
  • 2021-09-28
  • 1970-01-01
  • 2011-06-15
相关资源
最近更新 更多