我需要使用平均值执行数据平滑,使用即时创建的非标准group_by变量。我的模型由两个表组成:
class WthrStn(models.Model):
name=models.CharField(max_length=64, error_messages=MOD_ERR_MSGS)
owner_email=models.EmailField('Contact email')
location_city=models.CharField(max_length=32, blank=True)
location_state=models.CharField(max_length=32, blank=True)
...
class WthrData(models.Model):
stn=models.ForeignKey(WthrStn)
date=models.DateField()
time=models.TimeField()
temptr_out=models.DecimalField(max_digits=5, decimal_places=2)
temptr_in=models.DecimalField(max_digits=5, decimal_places=2)
class Meta:
ordering = ['-date','-time']
unique_together = (("date", "time", "stn"),)
WthrData表中的数据是以可变时间增量从xml文件输入的,目前为15或30分钟,但这可能会随着时间的推移而变化。该表中有> 20000条记录。我想提供一个选项来显示平滑到可变时间单位的数据,例如30分钟,1小时,2小时或N小时(60,120,180等分钟)
我使用SQLIte3作为数据库引擎。我测试了下面的sql,证明它非常适合在N分钟持续时间内执行“bins”平滑:
select id, date, time, 24*60*julianday(datetime(date || time))/N jsec, avg(temptr_out)
as temptr_out, avg(temptr_in) as temptr_in, avg(barom_mmhg) as barom_mmhg,
avg(wind_mph) as wind_mph, avg(wind_dir) as wind_dir, avg(humid_pct) as humid_pct,
avg(rain_in) as rain_in, avg(rain_rate) as rain_rate,
datetime(avg(julianday(datetime(date || time)))) as avg_date from wthr_wthrdata where
stn_id=19 group by round(jsec,0) order by stn_id,date,time;
注意我使用SQLite3函数'julianday'创建一个输出变量'jsec',它返回整数部分的天数和小数部分的天数。因此,乘以24 * 60可得到分钟数。除以N分钟的分辨率为我提供了一个很好的“分组”变量,可以补偿原始数据的不同时间增量。
如何在Django中实现这一点?我已经尝试了objects.raw(),但它返回一个RawQuerySet,而不是ViewSet的ViewSet,所以我从html模板中获取错误消息:
</p>
Number of data entries: {{ valid_form|length }}
</p>
我尝试使用标准查询,代码如下:
wthrdta=WthrData.objects.all()
wthrdta.extra(select={'jsec':'24*60*julianday(datetime(date || time))/{}'.format(n)})
wthrdta.extra(select = {'temptr_out':'avg(temptr_out)',
'temptr_in':'avg(temptr_in)',
'barom_mmhg':'avg(barom_mmhg)',
'wind_mph':'avg(wind_mph)',
'wind_dir':'avg(wind_dir)',
'humid_pct':'avg(humid_pct)',
'rain_in':'avg(rain_in)',
'rain_sum_in':'sum(rain_in)',
'rain_rate':'avg(rain_rate)',
'avg_date':'datetime(avg(julianday(datetime(date || time))))'})
请注意,这里我使用的是sql-avg函数,而不是使用django aggregate()或annotate()。这似乎生成了正确的sql代码,但我似乎无法将group_by正确设置为我在顶部创建的jsec数据。
有关如何处理此问题的任何建议?我真正需要的是让QuerySet.raw()方法返回一个QuerySet,或者可以转换为QuerySet而不是RawQuerySet的东西。我找不到一个简单的方法来做到这一点。
答案 0 :(得分:0)
使用我发现的提示,答案很简单 [https://gist.github.com/carymrobbins/8477219][1]
虽然我稍微修改了他的代码。要从RawQuerySet返回QuerySet,我所做的就是添加到我的models.py文件中,就在WthrData类定义的正上方:
class MyManager(models.Manager):
def raw_as_qs(self, raw_query, params=()):
"""Execute a raw query and return a QuerySet. The first column in the
result set must be the id field for the model.
:type raw_query: str | unicode
:type params: tuple[T] | dict[str | unicode, T]
:rtype: django.db.models.query.QuerySet
"""
cursor = connection.cursor()
try:
cursor.execute(raw_query, params)
return self.filter(id__in=(x[0] for x in cursor))
finally:
cursor.close()
然后在我的WthrData类定义中:
class WthrData(models.Model):
objects=MyManager()
......
以及稍后的WthrData类:
def get_smoothWthrData(stn_id,n):
sqlcode='select id, date, time, 24*60*julianday(datetime(date || time))/%s jsec, avg(temptr_out) as temptr_out, avg(temptr_in) as temptr_in, avg(barom_mmhg) as barom_mmhg, avg(wind_mph) as wind_mph, avg(wind_dir) as wind_dir, avg(humid_pct) as humid_pct, avg(rain_in) as rain_in, avg(rain_rate) as rain_rate, datetime(avg(julianday(datetime(date || time)))) as avg_date from wthr_wthrdata where stn_id=%s group by round(jsec,0) order by stn_id,date,time;'
return WthrData.objects.raw_as_qs(sqlcode,[n,stn_id]);
这允许我从经过时间增量平滑的高度填充的WthrData表中获取结果,结果将作为QuerySet而不是RawQuerySet返回