Custom sorting by custom field in Django

In my application, I have defined a custom field to represent a physical quantity using the quantities package .

class AmountField(models.CharField):
    def __init__(self, *args, **kwargs):

    def to_python(self, value):


Essentially the way it works is it extends CharField to store the value as a string in the database

"12 min"


and presents it as a magnitude object when using the field in the model

array(12) * min


Then, in the model, it is used as such:

class MyModel(models.Model):
    group = models.CharField()
    amount = AmountField()

    class Meta:
        ordering = ['group', 'amount']


My problem is that these fields are not sorted by count, but instead by row.

So, if I have some objects that contain something like

  • {"group": "A", "amount": "12 min"}
  • {"group": "A", "amount": "20 min"}
  • {"group": "A", "amount": "2 min"}
  • {"group": "B", "amount": "20 min"}
  • {"group": "B", "amount": "1 hr"}

they end up sorted something like this:

>>> MyModel.objects.all()
[{A, 12 min}, {A, 2 min}, {A, 20 min}, {B, 1 hr}, {B, 20 min}]


essentially alphabetical.

Can I provide my custom AmountField comparison method so that it compares python value instead of DB value?


source to share

3 answers

I think there is no way to sort it as numbers. I mean not an efficient way, as I believe Django allows sorting by a computed field somehow, but you need to compute all the keys for that. So try to find a way to store numbers as numbers in the database. Maybe store the quantity as an integer and add a method or property to convert it to a quantity object? Something like that:

class MyModel(models.Model):
    group = models.CharField()
    amount = models.IntegerField()  # or PositiveIntegerField

    class Meta:
        ordering = ['group', 'amount']

    def amountAsQuantityObject(self):
        return create_quantities_value(self.amount)

    # or as a property
    quantity_object = property(amountAsQuantityObject)




Could you store it with leading zeros in the database?

eg. "02 minutes"

This way it will sort correctly and when you parse it again, the leading zeros shouldn't matter.



I'll go with a completely different approach.

Instead of having a custom field to store what really are units of time, why not just store units of time?

For example 02 minutes should only be 02. You can store as an integer, or I think there is a TimeField that will allow you to store units in units of time.

You obviously want it to display so that the person can correctly understand what 02 really means 2 minutes, so just write your own filter in your form to deal with the minuses or the hours or whatever you might want to add to end.

This would have other advantages. Let's say you wanted to add all those units of time that you had earlier. This will require some string handling and change that part of the string to whatever has add or under or similar methods.