One way to do this is to create a Manager and defines a function with the raw SQL query. Create the model object attaching the new calculated field referencing to the model class with self.model
Class MyModel(models.Model):
fieldA = models.FloatField()
fieldB = models.FloatField()
objects = MyModelManager() #Binds the manager to the model
Class MyModelManager(models.Manager):
def ReturnDelta(self):
from django.db import connection
cursor = connection.cursor()
cursor.execute = """SELECT fieldA, fieldB, fieldA-fieldB as delta
from MyModel_table"""
result_list = []
for row in cursor.fetchall():
p = self.model(fieldA=row[0], fieldB[1]) #access the model associated w/ the manager
p.delta = row[2] #adds the new field to the queryset
result_list.append(p)
return result_list
Almost a copy-paste from Django Documentation
Then we can use the manager function in the extra-context dictionary of the generic view. and do algebraic operations without hitting the database unnecessarily.
A better solution is create your own QuerySet class with a custom Manager. This allows to chain filters and return any computed value as a QuerySet attribute. Is taken almost directly from this snippet
class CustomManager(models.Manager):
'''
An general purpose manager which allows to filter a queryset
and chain filters
"Constructor": CustomManager(CustomQuerySetClass)
'''
def __init__(self, qs_class=models.query.QuerySet):
super(CustomManager,self).__init__()
self.queryset_class = qs_class
def get_query_set(self):
return self.queryset_class(self.model)
def __getattr__(self, attr, *args):
try:
return getattr(self.__class__, attr, *args)
except AttributeError:
return getattr(self.get_query_set(), attr, *args)
class MyModelQuerySet(models.query.QuerySet):
'''
A very specific queryset designed to return a computed value (this
time a sum of all rows values)
'''
def filter(self, *args, **kwargs):
qs = super(GuiaQuerySet, self).filter(*args,**kwargs)
sum=0
for row in qs:
sum += row.delta #use a callback to prevent from caching
setattr(qs, 'sum',sum)
return qs
class MyModel(models.Model):
objects = CustomManager() #Binds the manager to the model
fieldA = models.FloatField()
fieldB = models.FloatField()
def delta(self):
return self.fieldA - self.fieldB