Django аннотирует условное значение

Допустим, у меня есть такая модель:

class modelA(models.model):
    name = models.Charfield()

class modelB(models.model):
    model_A = models.ForeignKey('modelA', on_delete=models.CASCADE)
    value = models.IntegerField()

class modelC(models.model):
    model_A = models.ForeignKey('modelA', on_delete=models.CASCADE)
    value = models.IntegerField()

Как я могу аннотировать запрос, чтобы получить что-то вроде этого :

q = modelA.objects.all().annotate(value= # IF THERE IS modelC exist with related modelA THEN modelC.value ELSE modelB.value #)

modelA может иметь несколько объектов modelB и modelC, но поскольку вы спрашиваете о существовании любой из моделей, я предположу, что может быть только одна из них, и возьму только первое значение. Сначала нужно аннотировать связанные значения с помощью Subquery, а затем оценить value с помощью sql switch-case:

from django.db.models import Case, When, Subquery, OuterRef, IntegerField


modelc_objects = modelC.objects.filter(model_A_id=OuterRef('pk'))
modelb_objects = modelB.objects.filter(model_A_id=OuterRef('pk'))

q = modelA.objects.all().annotate(
    c_value=Subquery(modelc_objects.values('value')[:1]),
    b_value=Subquery(modelb_objects.values('value')[:1]),
    value=Case(
        When(c_value__isnull=False, then=F('c_value')),
        When(b_value__isnull=False, then=F('b_value')),
        default=F('c_value'),
        output_field=IntegerField()
    )
)

Аннотируйте запрос значением из каждой связанной модели, я использовал Max здесь, чтобы получить наибольшее значение из каждого отношения, поскольку неясно, как вы обрабатываете несколько связанных строк одной и той же модели. Затем используйте функцию базы данных Coalesce для получения первого ненулевого значения из этих предыдущих аннотаций

modelA.objects.annotate(
    max_b=Max('modelb__value'), 
    max_c=Max('modelc__value')
).annotate(
    value=Coalesce('max_c', 'max_b')
)
Вернуться на верх