Вычислить сумму элементов в наборе запросов date_range, если соответствует foreign_key_id, и пропустить остальное

#python #django #django-models

#python #django #django-модели

Вопрос:

У меня есть 100 тысяч записей в день, и я использую их для вывода в API (у меня есть ограничение и смещение по умолчанию). Я хочу вычислить значения в моем наборе запросов, если у них есть общий owner_id, и оставить остальное как есть, если нет общего владельца для дельты даты

То, что я делаю сейчас, но не выглядит правильным (он правильно вычисляет некоторые данные, но по какой-то причине некоторые данные также увеличиваются, чего не должно было быть)

    TrendData.objects.filter(owner__trend_type__mnemonic='posts').filter(
            date_trend__date__range=[date_from, date_to]).values('owner__name').annotate(
            views=(Sum('views') / date_delta),
            views_u=(Sum('views_u') / date_delta),
            likes=(Sum('likes') / date_delta),
            shares=(Sum('shares') / date_delta),
            interaction_rate=(
                    Sum('interaction_rate') / date_delta),
        )
date_delta = date_to - date_from  #<- integer
 

мои модели:

 class Owner(models.Model):
    class Meta:
        verbose_name_plural = 'objects'

    TREND_OWNERS = Choices('group', 'user')

    link = models.CharField(max_length=255)
    name = models.CharField(max_length=255)
    owner_type = models.CharField(choices=TREND_OWNERS, max_length=50)
    trend_type = models.ForeignKey(TrendType, on_delete=models.CASCADE)

    def __str__(self):
        return f'{self.link}[{self.trend_type}]'

class TrendData(models.Model):

    class Meta:
        verbose_name_plural = 'Trends'

    owner = models.ForeignKey(Owner, on_delete=models.CASCADE)
    views = models.IntegerField()
    views_u = models.IntegerField()
    likes = models.IntegerField()
    shares = models.IntegerField()
    interaction_rate = models.DecimalField(max_digits=20, decimal_places=10)
    mean_age = models.IntegerField()
    source = models.ForeignKey(TrendSource, on_delete=models.CASCADE)
    date_trend = models.DateTimeField()

 

Исходная родительская модель в этом случае на самом деле не помогает, это csv-файл, из которого были загружены данные, поэтому мы никогда не ссылаемся на него.

Я хочу, возможно ли вычислить сумму, views, views_u, likes, shares, interaction_rate если owner выполняется для обоих дней (скажем, с 01.01.19 по 10.01.2019), и если в оба дня есть 2 владельца, вычислите сумму, если не пропустите, и оставьте ее как простой набор запросов без суммирования ВСЕХ значений в нем, еслизатем вычислите и оставьте остальное как есть. Я могу сделать это с помощью python, но я думаю, что это можно сделать в django ORM

Ответ №1:

Django ORM предоставляет условные выражения для выполнения такого рода аннотаций на основе условий. Вы можете использовать Case для аннотирования на Sum основе упомянутого вами условия.

 TrendData.objects.filter(owner__trend_type__mnemonic='posts').annotate(
    views=Sum(
         Case(
            When("Your condition here", then=F('views')),
            default=0,
            output_field=IntegerField(),
         )
     )
     ...
)