我在下面有以下模型结构:
class Master(models.Model):
name = models.CharField(max_length=50)
mounting_height = models.DecimalField(max_digits=10,decimal_places=2)
class MLog(models.Model):
date = models.DateField(db_index=True)
time = models.TimeField(db_index=True)
sensor_reading = models.IntegerField()
m_master = models.ForeignKey(Master)
目标是生成一个查询集,该查询集根据Master中的相关数据返回MLog中的所有字段和计算字段(item_height)
使用Django的原始sql:
querySet = MLog.objects.raw('''
SELECT a.id,
date,
time,
sensor_reading,
mounting_height,
(sensor_reading - mounting_height) as item_height
FROM db_mlog a JOIN db_master b
ON a.m_master_id = b.id
''')
如何使用Django的ORM编写代码?
答案 0 :(得分:7)
我可以考虑两种方法来解决这个问题而不依赖raw()
。第一个与@tylerl suggested几乎相同。像这样:
class Master(models.Model):
name = models.CharField(max_length=50)
mounting_height = models.DecimalField(max_digits=10,decimal_places=2)
class MLog(models.Model):
date = models.DateField(db_index=True)
time = models.TimeField(db_index=True)
sensor_reading = models.IntegerField()
m_master = models.ForeignKey(Master)
def _get_item_height(self):
return self.sensor_reading - self.m_master.mounting_height
item_height = property(_get_item_height)
在这种情况下,我正在为名为MLog
的{{1}}定义自定义(派生)属性。此属性计算为实例的item_height
与其相关主实例的mounting_height的差异。有关sensor_reading
here的更多信息。
然后你可以这样做:
property
执行此操作的第二种方法是使用extra()
方法并让数据库为您进行计算。
In [4]: q = MLog.objects.all()
In [5]: q[0]
Out[5]: <MLog: 2010-09-11 8>
In [6]: q[0].item_height
Out[6]: Decimal('-2.00')
您会注意到In [14]: q = MLog.objects.select_related().extra(select =
{'item_height': 'sensor_reading - mounting_height'})
In [16]: q[0]
Out[16]: <MLog: 2010-09-11 8>
In [17]: q[0].item_height
Out[17]: Decimal('-2.00')
的使用。如果没有这个,select_related()
表将不会与查询连接,您将收到错误。
答案 1 :(得分:0)
我总是在应用程序中而不是在数据库中进行计算。
class Thing(models.Model):
foo = models.IntegerField()
bar = models.IntegerField()
@Property
def diff():
def fget(self):
return self.foo - self.bar
def fset(self,value):
self.bar = self.foo - value
然后你可以像对待任何其他字段一样操纵它,并且它可以根据您定义的基础数据执行任何操作。例如:
obj = Thing.objects.all()[0]
print(obj.diff) # prints .foo - .bar
obj.diff = 4 # sets .bar to .foo - 4
顺便说一下,属性只是一个标准的属性装饰器,在这种情况下编码如下(我不记得它来自哪里):
def Property(function):
keys = 'fget', 'fset', 'fdel'
func_locals = {'doc':function.__doc__}
def probeFunc(frame, event, arg):
if event == 'return':
locals = frame.f_locals
func_locals.update(dict((k,locals.get(k)) for k in keys))
sys.settrace(None)
return probeFunc
sys.settrace(probeFunc)
function()
return property(**func_locals)