Django代理模型返回错误ContentType问题排查请求
问题描述
现有如下Django模型定义:
class Company(models.Model): name = models.CharField(max_length=100) related_companies = models.ManyToManyField('self', symmetrical=True) is_customer = models.BooleanField(default=False) class ClientManager(models.Manager): def get_queryset(self): return super().get_queryset().filter(is_customer=True) class Client(Company): objects = ClientManager() class Meta: proxy = True
执行以下命令行操作:
from django.contrib.contenttypes.models import ContentType # 创建Company实例,is_customer设为True company = Company.objects.create(name='test', is_customer=True) # 获取ContentType,返回Company的类型,符合预期 ContentType.objects.get_for_model(company) # 输出:<ContentType: contacts | company> # 按照文档,传入for_concrete_model=False应该返回Client的ContentType,但实际还是返回Company的 ContentType.objects.get_for_model(company, for_concrete_model=False) # 输出:<ContentType: contacts | company>
疑问:为什么for_concrete_model=False没有返回Client的ContentType?
问题原因与解决方案
核心原因
你创建的company实例是Company类的实例,而非Client类的实例。代理模型本质是同一张数据库表的"视图层",并不会改变实例的实际类型——即使is_customer=True,用Company.objects.create创建的对象依然是Company类型,和Client代理模型没有直接关联。
get_for_model的for_concrete_model=False参数的作用是:当传入的是代理模型类或者代理模型创建的实例时,返回代理模型对应的ContentType,而非其底层的具体模型。但你传入的是Company类的实例,所以该参数不会生效。
正确做法
用代理模型创建实例
如果你想让实例关联到Client的ContentType,需要通过Client的管理器创建对象:client = Client.objects.create(name='test_client', is_customer=True) ContentType.objects.get_for_model(client, for_concrete_model=False) # 输出:<ContentType: contacts | client>直接指定代理模型类获取ContentType
如果你只是想获取Client代理模型的ContentType,不需要实例,直接传入Client类即可:ContentType.objects.get_for_model(Client, for_concrete_model=False) # 输出:<ContentType: contacts | client>
内容的提问来源于stack exchange,提问作者S.D.
相关产品推荐
相关产品推荐

