Django中如何获取抽象类ConnectorModel的关联集合connectormodel_set?
哦,这个问题我之前也碰到过!因为你把ConnectorModel设为了抽象模型(abstract=True),Django不会为抽象模型创建数据库表,它只是作为父类被继承复用字段逻辑,所以反向关联不会自动生成connectormodel_set,只会为每个具体的子类(比如TelegramModel、URLModel)生成对应的反向关联属性(telegrammodel_set、urlmodel_set)。
下面给你两种实用的解决方案:
解决方案1:在ClientModel中自定义方法合并结果
最简单的方式是在ClientModel里写一个方法,手动合并两个子类的查询集:
from itertools import chain from django.db.models import QuerySet class ClientModel(models.Model): account = models.ForeignKey(Account, on_delete=models.CASCADE) def connectormodel_set(self): # 把导入放在方法内,避免循环导入问题 from .models import TelegramModel, URLModel # 合并两个查询集,返回可迭代的结果 return chain(self.telegrammodel_set.all(), self.urlmodel_set.all())
如果需要返回支持Django ORM操作(比如filter、order_by)的QuerySet对象,可以用union,但要确保指定的字段在两个模型中兼容:
def connectormodel_set(self) -> QuerySet: from .models import TelegramModel, URLModel # 选取共同/需要的字段进行合并 telegram_qs = self.telegrammodel_set.all().values('id', 'client_id', 'phone') url_qs = self.urlmodel_set.all().values('id', 'client_id', 'url') return telegram_qs.union(url_qs)
解决方案2:改用多表继承(替代抽象模型)
如果你能接受为ConnectorModel创建独立数据库表,可以把它改成非抽象模型,子类使用多表继承:
class ConnectorModel(models.Model): client = models.ForeignKey(ClientModel, on_delete=models.CASCADE) # 移除abstract=True class TelegramModel(ConnectorModel): phone = models.CharField(max_length=20) class URLModel(ConnectorModel): url = models.URLField(max_length=200) # 修正你原来的字段错误,应该是URLField而非UR
这样Django会自动为ConnectorModel生成表,ClientModel实例也会拥有connectormodel_set属性,你还可以用select_subclasses()获取具体的子类对象:
client = ClientModel.objects.first() all_connectors = client.connectormodel_set.select_subclasses() for connector in all_connectors: if isinstance(connector, TelegramModel): print(connector.phone) elif isinstance(connector, URLModel): print(connector.url)
小提醒
- 方案1的
chain返回的是迭代器,不是QuerySet,无法进行后续ORM操作;如果需要ORM能力优先考虑方案2或union写法。 - 多表继承会额外生成一张表,增加数据库复杂度,需要根据你的业务场景权衡选择。
- 记得修正
URLModel里的字段错误,models.UR是无效的,应该用models.URLField。
内容的提问来源于stack exchange,提问作者Joseph Groot Kormelink
相关产品推荐
相关产品推荐

