You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从空Django QuerySet中获取字段名称?

从空Django QuerySet中获取含注解列的字段名

我们经常会从Django QuerySet直接构建Pandas DataFrame,代码示例如下:

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

当QuerySet非空时,这种方式能同时获取原生列和注解列,效果很好。但如果QuerySet是空集合(比如queryset = models.A.objects.filter(id__lt=0).annotate(...)),生成的DataFrame会完全没有列定义:

Empty DataFrame
Columns: []
Index: []

而我们需要的是保留所有列名的空DataFrame,这样才能和其他DataFrame无缝合并:

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

现有方法存在明显不足:

  • 从非空QuerySet的queryset[0].__dict__.keys()提取列名,对空QuerySet无效
  • 通过模型queryset.model._meta.get_fields()获取原生列名,会丢失注解列,手动添加注解列又不符合需求

以下是两种可行的解决方案:

方法一:通过数据库游标获取列元数据

Django执行查询后,即使结果为空,数据库游标也会返回完整的列信息。我们可以直接执行QuerySet对应的SQL,从游标描述中提取列名:

from django.db import connection

def get_queryset_columns(queryset):
    # 获取游标并执行查询
    cursor = connection.cursor()
    sql, params = queryset.query.sql_with_params()
    cursor.execute(sql, params)
    # 从游标描述中提取所有列名
    columns = [col[0] for col in cursor.description]
    cursor.close()
    return columns

# 使用示例
queryset = models.A.objects.filter(id__lt=0).annotate(custom_col=F('id')*2)
columns = get_queryset_columns(queryset)
frame = pd.DataFrame(queryset.values(), columns=columns)

这种方法直接从数据库返回的元数据中获取列名,不管QuerySet是否为空,都能准确拿到原生列和注解列的名称,兼容性和可靠性都很强。

方法二:解析QuerySet的内部查询结构(无SQL执行)

如果不想执行实际查询,可以直接解析QuerySet的query对象,提取字段和注解的别名(适合Django 3.2+版本):

def get_queryset_columns_from_query(queryset):
    columns = []
    # 处理查询中定义的字段和注解
    for col in queryset.query.select:
        # 原生模型字段有name属性
        if hasattr(col, 'name'):
            columns.append(col.name)
        # 注解列有alias属性
        elif hasattr(col, 'alias'):
            columns.append(col.alias)
    # 如果使用了values(*fields),优先取指定的字段
    if queryset.query.values_select:
        columns = list(queryset.query.values_select)
    return columns

# 使用示例
queryset = models.A.objects.filter(id__lt=0).annotate(custom_col=F('id')*2)
columns = get_queryset_columns_from_query(queryset)
frame = pd.DataFrame(queryset.values(), columns=columns)

这种方法不需要和数据库交互,性能更好,但需要注意不同Django版本中query对象的结构可能有变化,需要根据实际版本调整。

内容的提问来源于stack exchange,提问作者jlandercy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 12:52:46