user2549983
user2549983

Reputation: 31

Django sortable field derived from other fields

Edited with own answer: original question below.

In here it recommends a few approaches, and the simplest one to me is to just add an extra field but override save to update it, then I get standard functionality for free. So my app is now:

#views.py
highest_p2w = Car.objects.filter().order_by('-p2w')[0]
lowest_p2w = Car.objects.filter().order_by('p2w')[0]

.

#models.py
p2w = models.FloatField("Power to weight ratio",editable=False)

def save(self, *args, **kwargs):
    self.p2w = (float(self.bhp) * 1000 ) / float(self.weight)
    super(Car, self).save(*args, **kwargs)

The only disadvantage is that I had to do a save() on any existing records to update the value. But any new records enter the value at save() time.


Original Question

I'd like to have a dynamic value which is calculated from 2 fields returned in Django from the model.

I think I can do this with a method, but I need to be able to sort on it just like the other fields.

#Models.py:
class Car(models.Model):
    weight = models.IntegerField("Weight in KG")
    bhp = models.IntegerField("BHP")

I'd like to have a field called power_to_weight_ratio that just calculates ( self.bhp * 1000 ) / self.weight

As this is a dynamic value, it doesn't need to be stored. BUT it does need to be sortable, as I sorted on all the other fields in the model.

I'd think I could just do something like

power_to_weight = ( self.bhp * 1000 ) / self.weight

but I assume I need to start overriding methods to give me the ability to sort. Django docs don't seem to mention this in the model custom field documentation.

Thanks.

Upvotes: 1

Views: 262

Answers (1)

WeizhongTu
WeizhongTu

Reputation: 6414

I am so glad that I've done it! ^_^ free to enjoy it

I've tried the following that is most similar to satisfy your need (tested sqlite3 database)

admin.py

from django.contrib import admin
from .models import Car

class CarAdmin(admin.ModelAdmin):
    list_display = ('weight','bhp','power_to_weight2',)

    def queryset(self,request):
        return super(CarAdmin,self).queryset(request).extra(select={'ptw':'(CAST((bhp) AS FLOAT))/weight'})

    def power_to_weight2(self,obj):
        return obj.bhp*1000/float(obj.weight)#python 2.x,float not need in python3.x
    power_to_weight2.short_description = 'power_to_weight'
    power_to_weight2.admin_order_field = 'ptw'

admin.site.register(Car,CarAdmin)
  1. about model.objects.extra() see: https://docs.djangoproject.com/en/dev/ref/models/querysets/#extra

  2. When query database, / means you are doing integer division so use CAST AS FLOAT to convert it to float,detail see here: What is wrong with this SQL Server query division calculation?

Upvotes: 1

Related Questions