Аннотирование в 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. Они очень полезны, когда речь идет об обусловливании.