Странности аннотации ArragAgg. Это ошибка или особенность?
Краткая постановка проблемы. Добавление аннотации ArrayAgg (расширения Postgres) умножает значения других аннотаций, но не всегда
Детали. Учитывая эти модели:
class MemDesc( models.Model):
class Meta:
verbose_name = "Item Description"
... lots of data fields (Char and Integer fields)
class MemStockLineManager( models.Manager):
def get_queryset(self):
# always fetch related descriptions!
return super().get_queryset().select_related('desc', 'allocated_to')
class MemStockLine( models.Model):
class Meta:
verbose_name="Stock Line"
# managers. first is default
objects=MemStockLineManager()
desc = models.ForeignKey( MemDesc, models.PROTECT, related_name='stock')
... data fields ...
class ProductCode( models.Model):
class Meta:
unique_together=[('code','customer'), ('customer', 'description')]
customer = models.ForeignKey( 'customers.Customer', models.CASCADE, null=True, blank=True, )
description = models.ForeignKey( MemDesc, models.CASCADE, )
code = models.CharField( max_length = 20)
Я не думаю, что MemStockLineManager
имеет значение, но я включил его на всякий случай.
Может ли кто-нибудь объяснить эти результаты? Это, как и ожидалось:
>>> from django.db.models import Q,F, Sum, Count
>>> from django.db.models.functions import Coalesce
>>> from django.contrib.postgres.aggregates import StringAgg, ArrayAgg
>>> qsx = MemDesc.objects.all().annotate( stocklines= Coalesce( Count('stock__qty'), 0),
... stocklevel= Coalesce( Sum('stock__qty'), 0))
>>> qs1 = qsx.filter(pk=140); o = list(qs1)[0]; o.stocklines
11
>>> o.stock.count()
11
Добавьте аннотацию ArrayAgg, аннотация stocklines
удваивается.
>>> qsx = MemDesc.objects.all().annotate( stocklines= Coalesce( Count('stock__qty'), 0),
... stocklevel= Coalesce( Sum('stock__qty'), 0) ,
... partnumbers=ArrayAgg('productcode__code', distinct=True))
>>> qs1 = qsx.filter(pk=140); o = list(qs1)[0]; o.stocklines
22
>>> o.stock.count()
11
>>> o.partnumbers
['Anybody001', 'TEST0001']
но, похоже, только когда аннотация массива является множественной:
>>> qs1 = qsx.filter(pk=168); o = list(qs1)[0]; o.stocklines
4
>>> o.stock.count()
4
>>> o.partnumbers
[None]
>>> qs1 = qsx.filter(pk=128); o = list(qs1)[0]; o.stocklines
2
>>> o.stock.count()
2
>>> o.partnumbers
['Foo123']
Есть ли способ обойти это? Я пытаюсь избежать проблемы N+1, которая возникает, если у меня нет всех этих аннотаций и мне приходится делать запрос для каждой строки/объекта в том, что фактически является ListView.