Django аннотировать значение поля из другой модели

#python #django #django-rest-framework

#python #django #django-rest-framework

Вопрос:

Я хочу аннотировать набор запросов MyModel значением из другой модели истории. Мои модели следующие:

 class Stage(models.Model):
    name = models.CharField()


class History(models.Model):
    mymodel = models.ForeignKey(
        MyModel,
        on_delete=models.CASCADE,
    )
    stage = models.ForeignKey(
        Stage,
        on_delete=models.DO_NOTHING
     )
    created_at = models.DateTimeField(
        auto_now_add=True
    )

class MyModel(models.Model):
    id = models.AutoField(
        primary_key=True,
    )
    ...
  

Приблизительная операция, которую я хотел бы выполнить в наборе представлений (order_by Мне нужно получить последний этап):

 class MyModelViewSet(viewsets.ModelViewSet):
    ...
    def get_queryset(self):
        qs = super(MyModelViewSet, self).get_queryset()
        qs = qs.annotate(last_stage_name=Value(
            History.objects.filter(mymodel__id=F('id')).order_by('-created_at')[0].stage.name,
            output_field=CharField()))
  

Но я получаю один и тот же этап для всех объектов из первого объекта вместо последнего этапа каждого объекта, поэтому логика работы неверна. Я полагаю, я должен избавиться от History.objects.filter, но не могу найти подходящее решение.

Ответ №1:

Вы можете работать с Subquery выражением [Django-doc]:

 from django.db.models import OuterRef, Subquery

class MyModelViewSet(viewsets.ModelViewSet):
    
    # …
    
    def get_queryset(self):
        return super().get_queryset().annotate(
            last_stage_name=Subquery(
                History.objects.filter(
                    mymodel_id=OuterRef('pk')
                ).order_by('-created_at').values('stage__name')[:1]
            )
        )  

Комментарии:

1. большое спасибо, это работает! Мне нужно больше узнать о подзапросе