Запрос Django с order by, distinct и limit на Postgresql

у меня есть следующие :

class Product(models.Model):
    name = models.CharField(max_length=255)

class Action(models.Model):
    product = models.ForeignKey(Product)
    created_at = models.DateTimeField(auto_now_add=True)

Я хотел бы получить 10 самых последних действий, заказанных created_at DESC с различными продуктами.

следующее близко к результату, но все равно пропускает заказ:

Action.objects.all().order_by('product_id').distinct('product_id')[:10]

2 ответов


ваше решение кажется, что оно пытается сделать слишком много. Это также приведет к 2 отдельным SQL-запросам. Это будет работать нормально и только с одним запросом:

action_ids = Action.objects.order_by('product_id', '-created_at')\
    .distinct('product_id').values_list('id', flat=True)

result = Action.objects.filter(id__in=action_ids)\
    .order_by('-created_at')[:10]

EDIT: это решение работает, но Росс лоте чище

это то, как я, наконец, сделал это, используя Агрегация Django:

from django.db.models import Max

actions_id = Action.objects.all().values('product_id') \
    .annotate(action_id=Max('id')) \
    .order_by('-action_id')[:10] \
    .values_list('action_id', flat=True)

result = Action.objects.filter(id__in=actions_id).order_by('-created_at')

установка values('product_id') у нас группы по on product_id.

С annotate() можно использовать order_by только на полях, используемых в values() или annotate(). Поскольку для каждого действия created_at поле автоматически устанавливается в настоящее время, заказ on created_at это то же самое, что заказ на id, используя annotate(action_id=Max('id')).order_by('-action_id') это правильный путь.

наконец, нам просто нужно нарезать наш запрос [:10]

надеюсь, что это помогает.