Аннотирование в django с использованием поля из другой модели

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

models.py:

class Node(model.Model):
    text = models.CharField(max_length=100, verbose_name=_('Text'))
    perimeter_ID = models.CharField(max_length=100, verbose_name=_('Perimeter_ID'))
    pos_x = models.FloatField(verbose_name=_('Position X'))
    pos_y = models.FloatField(verbose_name=_('Position Y'))
    class Meta:
        ordering = ['pk']


class Routes(models.Model):
    from_id = models.ForeignKey(Node, on_delete=models.PROTECT, verbose_name=_('From'), related_name='transport_from')
    to_id = models.ForeignKey(Node, on_delete=models.PROTECT, verbose_name=_('To'), related_name='transport_to')
    n_box = models.FloatField(verbose_name=_('Number of boxes'))
    day = models.CharField(max_length=10, verbose_name=_('day'))

    class Meta:
        ordering = ['from_id__id', 'to_id__id']
   

В моих представлениях, я сначала фильтрую по дням, так как запрос будет что-то вроде filter/?day=20220103, а затем я хочу узнать сумму ящиков, когда from_id и perimeter_id одинаковы (perimeter_id узла, соответствующего to_id). Таким образом, мне нужно как-то установить связь между узлом to_id и его perimeter_id.

views.py:

class sumByPerimeterListAPIView(ListAPIView):
    queryset = Routes.objects.all()
    filter_backends = [DjangoFilterBackend]
    filter_fields = {
        'day': ["in", "exact"],
    }
    def get(self, request, **kwargs):
        queryset = self.get_queryset()
        filter_queryset = self.filter_queryset(queryset)
        values = filter_queryset.values('from_id')\ # TODO: INCLUDE  perimeter_id OF to_id
            .annotate(n_box=Sum('n_box'))
        return Response(values)

Я читал о subquery и OuterRef в Django, также в следующей ссылке: Django 1.11 Annotating a Subquery Aggregate. Но эти примеры не подходят для меня, так как мне не нужно аннотировать поле perimeter_id. Мне нужно агрегировать по from_id (модель Routes) и perimeter_id (модель Node) и аннотировать по n_box.

Чтобы получить аннотацию с условием, попробуйте использовать оператор case when внутри аннотации:

Ниже приведен пример этого

from django.db.models import Count, Case, When, IntegerField
Article.objects.annotate(
    numviews=Count(Case(
        When(readership__what_time__lt=treshold, then=1),
        output_field=IntegerField(),
    ))
)

В вашем случае вы должны изменить следующую строку следующим образом:

values = filter_queryset.annotate(n_box=Sum(When(Case (from_id=from_id.perimeter_ID, then=n_box), n_box=DecimalField())
            

Попробуйте сделать что-то подобное, используя when, case и then.

Надеюсь, это решит ваши проблемы с кондиционированием.

Кроме того, ознакомьтесь с выражениями F. Они очень полезны, когда речь идет об обусловливании.

Вернуться на верх