2012-08-02 57 views
2

我在這個設置中有一個瘋狂的bug。django queryset從postgresql視圖返回錯誤的值

該數據庫是Postgres 9.1,並且是預先存在的(不是由Django管理)。在它存在1個表,然後一些相當簡單的看法,其中一個被稱爲valid_logins_dow_popularity定義:

=>\d+ valid_logins_dow_popularity 
      View "public.valid_logins_dow_popularity" 
    Column |  Type  | Modifiers | Storage | Description 
------------+------------------+-----------+---------+------------- 
logins_avg | double precision |   | plain | 
dow  | double precision |   | plain | 
View definition: 
WITH by_dow AS (
     SELECT valid_logins_over_time.count, date_part('dow'::text, valid_logins_over_time.date) AS dow 
      FROM valid_logins_over_time 
     ) 
SELECT avg(by_dow.count)::double precision AS logins_avg, by_dow.dow 
    FROM by_dow 
    GROUP BY by_dow.dow 
    ORDER BY by_dow.dow; 

在Django的1.4,我定義使用該視圖一個簡單的模型,因爲它的數據源:

class ValidLoginsDowPopularity(models.Model): 
    class Meta: 
     db_table = 'valid_logins_dow_popularity' 
     managed = False 

    logins_avg = models.FloatField(
          db_column='logins_avg') 
    # Day of Week (dow) 
    dow = models.IntegerField(db_column='dow', 
           primary_key=True) 

    def __unicode__(self): 
     return u"%d : " % (self.dow, self.logins_avg) 

當我直接從數據庫中獲取數據,我得到一組數字:

SELECT "valid_logins_dow_popularity"."logins_avg", "valid_logins_dow_popularity"."dow" 
    FROM "valid_logins_dow_popularity"; 

    logins_avg | dow 
------------------+----- 
28.8571428571429 | 0 
95.1428571428571 | 1 
91.4285714285714 | 2 
      89.625 | 3 
82.6666666666667 | 4 
61.4285714285714 | 5 
28.4285714285714 | 6 
(7 rows) 

當我得到的DAT一個通過Django的模型我得到一個有點含糊相關,但不同組數字:

In [1]: from core.models import * 

In [2]: v = ValidLoginsDowPopularity.objects.all() 

In [3]: for i in v: 
    print "logins_avg : %f | dow : %d" % (i.logins_avg, i.dow) 
    ...: 
logins_avg : 25.857143 | dow : 0 
logins_avg : 85.571429 | dow : 1 
logins_avg : 89.571429 | dow : 2 
logins_avg : 86.375000 | dow : 3 
logins_avg : 83.000000 | dow : 4 
logins_avg : 67.000000 | dow : 5 
logins_avg : 28.000000 | dow : 6 

到今天爲止,我已經驗證了Django的產生,當在psql直接運行返回預期輸出的SQL。我同樣嘗試使用一個IntegerField,FloatField和DecimalField作爲login_avg屬性的Django模型 - 都具有相同的但不正確的值。我也寫了一個簡單的測試程序來繞過Django的代碼並確保它不是一個psycopg2問題:

import psycopg2 

def main(): 
    conn_string = "dbname='********' user='*********'" 

    conn = psycopg2.connect(conn_string) 
    cursor = conn.cursor() 

    sql = "select * from valid_logins_dow_popularity" 
    cursor.execute(sql) 

    for rec in cursor.fetchall(): 
     print rec 

if __name__ == '__main__': 
    main() 

,當運行給出正確的過錯,所以psycopg2似乎是在做正確的事:

$ python test_psycopg2.py 
(28.8571428571429, 0.0) 
(95.1428571428571, 1.0) 
(91.4285714285714, 2.0) 
(89.625, 3.0) 
(82.6666666666667, 4.0) 
(61.4285714285714, 5.0) 
(28.4285714285714, 6.0) 

這怎麼可能?任何線索將不勝感激。我可以在哪裏挖掘Django代碼並查看出現問題的地方?我應該用Django項目報告這個問題嗎?

+0

視圖/表中的logins_avg字段的數據庫類型是什麼?我懷疑從那轉換到FloatField類型不能正常工作。 – 2012-08-02 17:08:50

+0

好主意。我已經編輯了這個問題以獲得這些細節,但我也嘗試將login_avg列轉換爲int,將模型更新爲IntegerField,但仍然存在奇數值差異。 – portman 2012-08-02 17:27:35

+0

FloatField應正確映射到「雙精度」...您使用的是什麼python數據庫引擎? postgresql_psycopg2?你也可以嘗試DecimalField而不是FloatField,看看是否改變了任何東西 – 2012-08-02 18:49:17

回答

1

重新定義視圖並將值轉換爲數字而不是double。在Django模型中,您需要一個與Postgres數字匹配的DecimalField(如數字(15,10) - > DecimalField(max_digits = 15,decial_places = 10))。

我從來沒有在Django和數據庫之間使用浮點數運算,並且在其他軟件與數據庫之前也有類似的浮點數奇怪問題。做數字< - > DecimalField是我發現的保證浮點值不奇怪的唯一方式 - 通過將其更改爲定點值。