Запрос Django для фильтрации только первых объектов с определенными именами полей

модель

class UserAction(models.Model):
    ACTION_CHOICES = (
        ("LogIn", "Entered"),
        ("LogOut", "Gone Out"),
        ("Away", "Away from Computer"),
        ("Busy", "Busy"),
        ("DoNotDisturb", "Do not disturb"),
        ("Online", "Online and Available"),
    )
    action_name = models.CharField(choices=ACTION_CHOICES, default="LogIn")
    user = models.ForeignKey(Profile, related_name="actions")
    action_time = models.DateTimeField(default=timezone.now(), editable=False)


class Profile(models.Model):
    name = models.CharField(max_length=120)
    is_active = models.BooleanField(default=True)
    date_joined = models.DateTimeField(default=timezone.now())

Мне нужно запросить UserAction таким образом, чтобы получить только последний UserAction каждого пользователя. Мои решения отнимали слишком много времени. Поэтому ищу оптимизированный ответ.

Вы можете аннотировать Profiles с помощью выражения Subquery [Django-doc]:

from django.db.models import OuterRef, Subquery

Profile.objects.annotate(
    last_action=Subquery(
        UserAction.objects.filter(
            user_id=OuterRef('pk')
        ).order_by('-action_time').values('action_name')[:1]
    )
)

У Profile в кверисете будет дополнительный атрибут .last_action с action_name последнего связанного UserAction.


Примечание: [Django-doc]DateTimeField [Django-doc]. имеет auto_now_add=… параметр [Django-doc] для работы с временными метками. Это позволит автоматически присвоить текущее время при создании объекта, и пометит его как нередактируемый (editable=False), так что что оно не будет отображаться в ModelForm по умолчанию.

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