Question

I want to have sorting functionality for custom model field in django admin.

The code is similar to

class MyModel(models.Model):

    first_name = models.CharField()
    last_name = models.CharField()

    def most_recent_mailing_date(self):
        """ Return the most recent mailing date """
        mailingHistories = self.mailinghistory_set.all()

        if len(mailingHistories) != 0:
            today = datetime.date.today()
            mostRecentHistory = None
            diff = -1

            for mailingHistory in mailingHistories:

                if mailingHistory.mailing_date < today and (diff == -1 or (today - mailingHistory.mailing_date) < diff):

                    mostRecentHistory = mailingHistory
                    diff = today - mostRecentHistory.mailing_date

            if mostRecentHistory is None:
                return "No Mailing History"
            else:
                return mostRecentHistory.mailing_date
        else:
            return "No Mailing History"


    most_recent_mailing_date.admin_order_field = 'self.most_recent_mailing_date'

The field I want to order is most_recent_mailing_date. It is a custom field. Is it possible?

Thanks in advance!

Était-ce utile?

La solution

I don't think that's possible. From the docs:

You have four possible values that can be used in list_display:

....

A string representing an attribute on the model. This behaves almost the same as the callable, but self in this context is the model instance. Here’s a full model example:

from django.db import models from django.contrib import admin

class Person(models.Model):
    name = models.CharField(max_length=50)
    birthday = models.DateField()

    def decade_born_in(self):
        return self.birthday.strftime('%Y')[:3] + "0's"
    decade_born_in.short_description = 'Birth decade'

class PersonAdmin(admin.ModelAdmin):
    list_display = ('name', 'decade_born_in')

Thus, your field is the fourth option. However:

A few special cases to note about list_display:

...

Usually, elements of list_display that aren’t actual database fields can’t be used in sorting (because Django does all the sorting at the database level).

...(goes on to describe exception that doesn't apply here).

Thus, you can only sort on actual database fields.

Autres conseils

You can't use Django's order_by since it is applied at the database level. The database does not know anything about your python methods and properties.

However, You can do the ordering in Python

objects = MyModel.objects.all()
sorted(objects, key=lambda k: k.most_recent_mailing_date())

If you want reverse ordering,

objects = MyModel.objects.all()
sorted(objects, key=lambda k: k.most_recent_mailing_date(), reverse=True)

Advice

  • I think you should be consistent on your return type. If there are no mailing history, you can return some old date instead of returning a string.

  • I think you should consider using the @property decorator on your most_recent_mailing_date() so you can simply refer to it as instance.most_recent_mailing_date. This will make it somehow consistent on how you refer to your actual model fields.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top