Как аннотировать поле информацией из конкретной многотомной сущности?
У меня есть 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.