如何从Django QuerySet中获取字段名称,即使它是一个空集?

zpf6vheq  于 2023-05-19  发布在  Go
关注(0)|答案(1)|浏览(329)

Django和Pandas之间的一个很酷的绑定是能够直接从QuerySet构建DataFrame,使用:

queryset = models.A.objects.filter(...).annotate(...)
frame = pd.DataFrame(queryset.values())

只要QuerySet至少返回一条记录,它就能很好地工作。在QuerySet级别上操作很有意思,因为在那里我们可以使用所有注解和本机列。
但是这个方法将返回一个完全空的DataFrame(没有定义列),比如说:

queryset = models.A.objects.filter(id__lt=0).annotate(...)
frame = pd.DataFrame(queryset.values())

DataFrame完全为空:

Empty DataFrame
Columns: []
Index: []

而我们想要的是这样的东西:

Empty DataFrame
Columns: ["id", "key", "prop1", ...]
Index: []

其中保留了列名,以便使该帧能够与其他帧无缝合并。
pandas的方法是在创建DataFrame时使用columns开关强制列名。

queryset = models.A.objects.filter(...)
frame = pd.DataFrame(queryset.values(), columns=queryset.get_fields())

不幸的是,get_fields或类似的对象似乎没有实现,或者乍一看对QuerySet对象来说并不明显。
我已经知道我可以从QuerySet中获取exists()的列名,使用这个脏的:

frame = pd.DataFrame(
    queryset.values(),
    columns=queryset[0].__dict__.keys()
)

但是,实际上它不会对空的QuerySet起作用。
我还知道我可以得到模型列如下:

frame = pd.DataFrame(
    queryset.values(),
    columns=[item.name for item in queryset.model._meta.get_fields()] + [...]
)

但是这样我就错过了QuerySet创建的所有注解列,或者需要手动编码,这是我们想要避免的。
我有一种感觉,不知何故,QuerySet可能知道它应该返回的所有列。至少它应该在查询执行之后知道它,因为空的SQL结果集肯定会包含列名和类型。
所以我的问题是如何从Django QuerySet中获取字段名称,即使它是一个空集?
如果构造有点奇怪或复杂,只要它还允许获取注解列名,这就不是问题。

mwyxok5s

mwyxok5s1#

你可以这样尝试:

fields = [item.name for item in queryset.model._meta.get_fields()] + [item for item in queryset.query.annotations.keys()]

frame = pd.DataFrame(
    queryset.values(*fields),
    columns=fields
)

我在调试queryset对象时发现了这个解决方案。它有一个名为query的属性,指向这个类Query的示例。在Query类中,有一个名为annotations的属性。此属性包含所有注解信息。您可以使用它来获取所有带注解的字段。

相关问题