I have a model called Purchase
, with two fields, User
and amount_spent
.
This is models.py
:
class Purchase(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
amount_spent = models.IntegerField()
created_at = models.DateTimeField(auto_now_add=True)
I want to get the last purchases from a list of users.
On views.py
I have a list with some User
's objects, and I want to get the last purchase for each user in the list. I can't find a way of doing this in a single query, I checked the latest() operator on QuerySets, but it only returns one object.
This is views.py
:
purchases = Purchase.objects.filter(user__in=list_of_users)
# purchases contains all the purchases from users, now I need to get the most recent onces for each user.
I now I could group the purchases
by user and then get the most recent ones, but I was wondering it there is a way of making this as a single query to DB.
CodePudding user response:
try this:
Purchase.objects.filter(user__in=list_of_users).values("user_id", "amount_spent").order_by("-id").distinct("user_id")
CodePudding user response:
You can annotate the User
s with the last_purchase_pk
s and then fetch these and adds that to these users:
from django.db.models import OuterRef, Subquery
users = User.objects.annotate(
last_purchase_pk=Subquery(
purchase.objects.order_by('-created_at')
.filter(user_id=OuterRef('pk'))
.values('pk')[:1]
)
)
purchases = {
p.pk: p
for p in Purchase.objects.filter(
pk__in=[user.last_purchase_pk for user in users]
)
}
for user in users:
user.last_purchase = purchases.get(user.last_purchase_pk)
After this code snippet, the User
objects in users
will all have a last_purchase
attribute that contains the last Purchase
for that user, or None
in case there is no such purchase.