Как аннотировать поле информацией из конкретной многотомной сущности?
У меня есть 2 модели и множество отношений между ними, Property и Owners, они примерно следующие:
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('Property', on_delete=models.CASCADE)
current = models.BooleanField()
Как я могу аннотировать новое поле в моем Property.objects.all()
queryset с идентификатором текущего владельца. (возможно, используя .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(propertyowner__current=True).first()
Однако если мы загрузим много Property
, и нам нужно будет найти текущего владельца для каждого Property
, это приведет к большому количеству запросов.
Альтернативой может быть запрос для получения Property
с первичным ключом текущего владельца, затем загрузка всех этих владельцев, и, наконец, присвоение этих владельцев объектам Property
. Таким образом, это выглядит следующим образом:
Мы можем аннотировать QuerySet
первичным ключом текущего владельца, а затем получить их оптом и реализовать логику JOIN в Django:
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
.