How to get list of related object in annotion when using Greatest function in django models

Viewed 31

I am having two models, a User model and a Payment model and there is on to many relationship between them. User has multiple Payments. What I am trying to achieve is sorting the User model as per the Payment's created_at field.

I am trying to modify the Queryset and then I'll be using the annotated field latest_tran for sorting.

def get_queryset(self, request):
    qs = super(ClubbedPaymentAdmin, self).get_queryset(request)
    qs = qs.annotate(
        latest_tran=Greatest(Payment.objects.filter(user=F('id')).values_list('created_at', flat=True)))
    return qs

But I am having below error.

Greatest must take at least two expressions

So it seems like I am making a mistake when evaluating the list of Payments. Or may be like I am taking a wrong approach. Any help would be much appreciated. Thank you.

Edit

I am using the default User model for users which are there in django

My Payment model looks like this -

class Payment(models.Model):
    amount = models.FloatField('Points', max_length=10)
    purchase_token = models.TextField(max_length=250)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    note = models.TextField(max_length=1000, default=None, blank=True)
    created_at = models.DateTimeField('Transaction Date')
    updated_at = models.DateTimeField('Updated at', auto_now=True)
2 Answers

Greatest does not take the maximum, it takes the largest of the different parameters, so Greatest('foo', 'bar') will take the largest of the foo and bar column.

What you need is Max [Django-doc]. You can make use of the name separated by an underscore, so:

from django.db.models import Max

def get_queryset(self, *args, **kwargs):
    return super().get_queryset(*args, **kwargs).annotate(
        latest_tran=Max('payment__created_at')
    )

Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

Something like this, using the Max(...) ?

from django.db.models import Max


def get_queryset(self, request):
    qs = super(ClubbedPaymentAdmin, self).get_queryset(request)
    qs = qs.annotate(latest_tran=Max('payment__created_at'))
    return qs
Related