Почему возникает ошибка Complex aggregates require an alias?
Я работаю над Django, где у меня есть две модели Gigs и Orders и я вычисляю среднее время выполнения заказа каждого концерта.
В модели order у меня есть два поля order start time (которое я отправляю всякий раз, когда продавец принимает заказ) и order completed time (которое я отправляю, когда продавец доставил заказ).
Но проблема в том, что если у меня есть данные в таблице Orders, связанные с каким-то концертом, и я извлекаю концерт, то все работает отлично, но если я пытаюсь извлечь концерт, на который еще нет заказов (в таблице orders нет записи/поля, содержащего этот товар/гиг), то это дает мне следующую ошибку
Сложные агрегаты требуют псевдонима
Models.py
class Gigs(models.Model):
title = models.CharField(max_length=255)
category = models.ForeignKey(Categories , on_delete=models.CASCADE)
images = models.ImageField(blank=True, null = True, upload_to= upload_path)
price = models.DecimalField(max_digits=6, decimal_places=2)
details = models.TextField()
seller = models.ForeignKey(User,default=None, on_delete=models.CASCADE)
@property
def average_completionTime(self):
if getattr(self, '_average_completionTime', None):
return self._average_completionTime
return self.gig.aggregate(Avg(F('orderCompletedTime') - F('orderStartTime')))
class Orders(models.Model):
buyer = models.ForeignKey(User,default=None, on_delete=models.CASCADE,related_name='buyer_id')
seller = models.ForeignKey(User,default=None, on_delete=models.CASCADE,related_name='seller_id')
item = models.ForeignKey(Gigs,default=None, on_delete=models.CASCADE,related_name='gig')
payment_method= models.CharField(max_length=10)
address = models.CharField(max_length=255)
mobile = models.CharField(max_length=13,default=None)
quantity = models.SmallIntegerField(default=1)
status = models.CharField(max_length=13,default='new order')
orderStartTime = models.DateTimeField(default=timezone.now)
orderCompletedTime = models.DateTimeField(default=timezone.now)
isCompleted = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
Views.py
class RetrieveGigsAPI(GenericAPIView, RetrieveModelMixin):
def get_queryset(self):
return Gigs.objects.annotate(
_average_completionTime=Avg(
ExpressionWrapper(F('gig__orderCompletedTime') - F('gig__orderStartTime'), output_field=DurationField()),
filter=Q(gig__isCompleted=True),
)
)
serializer_class = GigsSerializerWithAvgTime
permission_classes = (AllowAny,)
def get(self, request , *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
Serializers.py
class GigsSerializerWithAvgTime(serializers.ModelSerializer):
average_completionTime = serializers.SerializerMethodField()
def get_average_completionTime(self, obj):
return obj.average_completionTime
class Meta:
model = Gigs
fields = ['id','title','category','price','details','seller','images','average_completionTime']
Пример
например, если у нас есть следующие данные в таблице orders, где item является внешним ключом от таблицы gigs
Теперь, если я извлекаю концерт 22, он работает хорошо и дает мне все поля в Api, включая среднее время завершения, но если я хочу получить концерт 23 или любой другой, он дает мне ошибку
но я хочу, чтобы он возвращал все остальные поля и среднее время завершения : null
полный трекбек ошибки
Как отметил @Iain Shelvington, вы можете задать имя агрегату следующим образом, чтобы устранить ошибку:
return self.gig.aggregate(average_completion=Avg(F('orderCompletedTime') - F('orderStartTime')))['average_completion']
# ^^^ Add this
Дополнительно, поскольку в get_queryset
потенциально уже может быть вычисленное значение, можно попробовать изменить getattr
на hasattr
и просто вернуть:
@property
def average_completionTime(self):
if hasattr(self, '_average_completionTime'):
return self._average_completionTime
return self.gig.aggregate(
average_completion=Avg(F('orderCompletedTime') - F('orderStartTime'))
)['average_completion']
Это проверка того, что _average_completionTime
уже вычислено для экземпляра концерта, чтобы не вычислять его снова.