为何model._meta.get_fields()返回意外关联列名?如何规避?
问题:Django模型_meta.get_fields()返回反向关联字段,如何只获取实际数据库字段?
模型代码
class User(AbstractUser): pass class Medium(models.Model): researcher = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True, related_name="medium_researcher") old_medium_name = models.CharField(max_length=20, null=True, blank=True) class Uptake(models.Model): material_quality = models.CharField(max_length=20, null=True, blank=True) medium = models.ForeignKey(Medium, on_delete=models.CASCADE, blank=True, null=True, related_name="uptake_medium")
字段获取代码及问题
from database.models import Medium MODEL_HEADERS=[f.name for f in Medium._meta.get_fields()] MODEL_HEADERS # 输出:['uptake_medium', 'id', 'researcher', 'old_medium_name']
疑问:uptake_medium是Uptake模型中定义的ForeignKey关联字段,仅属于Uptake模型,后台管理和SQLite数据库中都看不到该列,为什么_meta.get_fields()会返回它?如何只获取Medium模型的实际数据库字段?
解答
原因说明
_meta.get_fields()默认会返回模型的所有关联字段,包括正向关联和反向关联。uptake_medium是Uptake模型中medium字段指定的related_name,Django ORM会自动为Medium模型创建这个反向关联的虚拟字段,用于从Medium实例快速关联到对应的Uptake实例。这个字段仅存在于ORM层面,不会在数据库中生成实际列,因此后台管理和数据库里都看不到它。
解决方案
要只获取模型对应数据库中实际存在的字段,有两种简单的过滤方式:
方式一:过滤concrete属性为True的字段
concrete属性为True的字段,就是数据库中会生成实际列的字段,反向关联字段的该属性为False,直接过滤即可:
from database.models import Medium MODEL_HEADERS = [f.name for f in Medium._meta.get_fields() if f.concrete] # 输出:['id', 'researcher', 'old_medium_name']
方式二:结合get_fields()参数+属性过滤
如果需要排除父类继承的字段(比如从models.Model继承的id),可以添加include_parents=False参数再过滤:
from database.models import Medium MODEL_HEADERS = [ f.name for f in Medium._meta.get_fields(include_parents=False, include_hidden=False) if f.concrete ] # 输出:['researcher', 'old_medium_name']
内容的提问来源于stack exchange,提问作者Rivered
相关产品推荐
相关产品推荐

