2014-10-16 93 views
1

我需要使用平均值執行數據平滑,並使用動態創建的非標準group_by變量。我的模型包含兩個表:在專門查詢中設置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表中的數據是從可變時間增量,目前15或30分鐘的XML文件中輸入,但可能會發生變化,並隨時間而改變。該表中有> 20000條記錄。我想提供一個選項來顯示平滑到可變時間單位的數據,例如30分鐘,1,2或N小時(60,120,180等分鐘)

我正在使用SQLIte3作爲數據庫引擎。我測試了以下SQL,這被證明是相當足夠的,以在N-分鐘持續時間的「倉」進行平滑:

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; 

注我創建一個輸出變量「jsec」使用SQLite3的函數「儒略日」,它返回整數部分的天數和小數部分的天數。所以,乘以24 * 60給我的分鐘數。以N分鐘分辨率劃分給我一個很好的'group by'變量,補償原始數據的不同時間增量。

我該如何在Django中實現?我曾嘗試objects.raw(),但返回RawQuerySet,不是一個QuerySet的看法,所以我從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-平均功能,而不是使用Django的骨料(中)或註釋()。這似乎生成正確的SQL代碼,但我似乎無法正確設置我的jsec數據在頂部創建的group_by。

有關如何解決此問題的任何建議?我真正需要的是讓QuerySet.raw()方法返回一個QuerySet,或者一些可以轉換爲QuerySet而不是RawQuerySet的東西。我找不到一個簡單的方法來做到這一點。

回答

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表搶的結果,結果回來的查詢集,而不是RawQuerySet