如何从空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
相关产品推荐
相关产品推荐

