Demian Brecht
Demian Brecht

Reputation: 21368

Using computed fields in admin

I'm trying to use a runtime-computed field in my admin page. This works fine, but I'd like to allow sorting based for that field. Using Django 1.5 (dev), is this possible? I've been scouring the interweb but can't find anything indicating that it is possible.

class Guest(models.Model)
    email = models.CharField(max_length=255)

class Invitation(models.Model)
    guest = models.ForeignKey(Guest)
    created_on = models.DateTimeField(auto_now_add=True)

class GuestAdmin(admin.ModelAdmin):
    list_display = ["email", "latest_invitation_sent_on",]

    def latest_invitation_sent_on(self, o):
        try:
            return o.invitation_set.all().order_by(
                "-created_on")[0].created_on.strftime("%B %d, %Y")
        except IndexError:
            return "N/A"

I'd like to be able to enable sorting by latest_invitation_sent_on. Are there any methods of doing this nicely that I'm unaware of?

Upvotes: 2

Views: 733

Answers (1)

enticedwanderer
enticedwanderer

Reputation: 4346

You should be able to annotate Guests with their latest invitation time and then order_by it (order_by uses the DB to sort and as long as you can provide a valid DB field, table or virtual it should work).

class GuestManager(models.Manager):
    def get_query_set(self):
        return super(GuestManager, self).get_query_set().annotate(latest_invite=Max("invitation_set__created_on"))

class Guest(models.Model)
    email = models.CharField(max_length=255)
    objects = GuestManager()    

class Invitation(models.Model)
    guest = models.ForeignKey(Guest)
    created_on = models.DateTimeField(auto_now_add=True)

class GuestAdmin(admin.ModelAdmin):
    list_display = ["email", "latest_invite",]

If you only need latest_invite annotation once in a while it makes sense to move it to a separate method or even manager.

class GuestManager(models.Manager):
    def by_invitations(self):
        return super(GuestManager, self).get_query_set().annotate(latest_invite=Max("invitation_set__created_on")).order_by('-latest_invite')

>>>  Guest.objects.by_invitations()

Upvotes: 2

Related Questions