如何使用来自特定多对多实体的信息来注释字段?

How to annotate a field with information from a specific manytomany entity?

我有 2 个模型,然后 属性 和所有者之间存在多对多关系,它们大致如下:

class Property(models.Model):
    name = models.CharField(max_length=50)
    owners = models.ManyToManyField('Owner', through='PropertyOwner')
    ...

class Owner(models.Model):
    name = models.CharField("Owner's name", max_length=50)
    ...

class PropertyOwner(models.Model):
    property = models.ForeignKey('Property', on_delete=models.CASCADE)
    owner = models.ForeignKey('Owner', on_delete=models.CASCADE)
    current = models.BooleanField()

如何使用当前所有者的 ID 注释我的 Property.objects.all() 查询集中的新字段。 (也许使用 .first()

一个简单的方法是创建一个 属性,它将进行查询(根据 Property)以获取当前所有者。因此看起来像:

class Property(models.Model):
    name = models.CharField(max_length=50)
    owners = models.ManyToManyField('Owner', through='PropertyOwner')

    @property
    def current_owner(self):
        return self.owners.filter(<strong>propertyowner__current=True</strong>).first()

如果我们加载很多 Property,并且我们需要为每个 Property 找到当前所有者,这将导致很多查询。

另一种方法可能是查询以当前所有者的主键获取 Propertys,然后加载所有这些所有者,最后将这些所有者分配给 Property 对象.因此看起来像:

我们可以用当前所有者的主键注解QuerySet,然后批量获取这些并在Django中实现JOIN逻辑:

from operator import attrgetter

properties = list(Property.objects.filter(
    propertyowner__current=True
).annotate(
    current_owner_id=F('owners__pk')
))

owners = set(map(attrgetter('current_owner_id'), properties))
owners = {
    owner.pk: owner
    for owner in Owner.objects.filter(pk__in=owners)
}

for property in properties:
    property.current_owner = owners.get(property.current_owner_id)

在此代码片段之后,properties 是具有额外属性的 Property 对象的列表:.current_owner 这是当前拥有者的 Owner 对象Property.