我有一个模型,它具有计算两个字段之间差异的功能 例如:
Class MyModel(models.Model):
fieldA = models.FloatField()
fieldB = models.FloatField()
def delta(self):
return self.fieldA - self.fieldB
我想在GenericView中使用此模型。我可以使用函数delta作为extraContext,但也喜欢在模板中包含所有Delta结果的总和,在这种情况下我必须再次进行聚合,因为delta不是DB Field,也不是模型字段我不能使用它在一个聚合函数中。
如何做到这一点?
答案 0 :(得分:3)
你试过吗?
Class MyModel(models.Model):
fieldA = models.FloatField()
fieldB = models.FloatField()
def __delta(self):
return self.fieldA - self.fieldB
delta = property(__delta)
答案 1 :(得分:2)
执行此操作的一种方法是创建Manager并使用原始SQL查询定义函数。使用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
几乎来自Django Documentation的复制粘贴 然后我们可以在泛型视图的extra-context字典中使用manager函数。并且在不必要地访问数据库的情况下进行代数运算。
更好的解决方案是使用自定义Manager创建自己的QuerySet类。这允许链接过滤器并将任何计算值作为QuerySet属性返回。几乎直接来自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(MyModelQuerySet, 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
答案 2 :(得分:1)
这怎么可行?聚合在数据库中完成,但您的计算显然是在Python中。
你也必须在Python中做总结:
aggregated_delta = sum([m.delta() for m in MyModel.objects.all()])
答案 3 :(得分:1)
好的,首先你的代码应该有自己,因为你想要计算每一行的增量。
def delta(self):
return self.fieldA - self.fieldB
关于您的问题,无法从django函数聚合。有三种方法可以实现您的目标:
在Python中进行聚合。缺点:从数据库下载所有数据。
绕过Django ORM,手动执行SQL查询(这会使您的代码特定于数据库)。
在数据库中为增量创建另一个字段,并在保存时更新它(如果您想要特定于数据库,则使用触发器进行更新)。
答案 4 :(得分:1)
对于你想要的东西,只需在模型中添加一个新方法,然后在DB上进行聚合,然后计算两个总和之间的差值。像这样:
class MyModel(models.Model):
fielda = ...
fieldb = ...
def delta(self):
return self.fielda-fieldb
def aggregate_delta(self):
return MyModel.objects.aggregate(Sum('fielda')) - MyModel.objects.aggregate(Sum('fieldb'))