2012-08-02 61 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是我发现的保证浮点值不奇怪的唯一方式 - 通过将其更改为定点值。