SQLALCHEMY 中查询一直返回空的问题

来源:互联网 发布:大乐透算法必中5红 编辑:程序博客网 时间:2024/06/12 01:41

问题描述

HabitQuestion表有个last_answer_time字段,默认是null,就是要做它的筛选过滤。
一开始使用代码如下:

base_query = base_query.filter(HabitQuestion.last_answer_time.isnot(None)).order_by(HabitQuestion.last_answer_time.desc()))

其中last_answer_time是个默认值是None的参数,运行测试用例的时候报错,说 isnot方法在datetime.datetime里面没找到。可这完全是参考官方文档写的代码。于是改成如下代码,可以运行了。

base_query = base_query.filter(HabitQuestion.last_answer_time != None).order_by(desc(text("last_answer_time")))

但有意思的是,2个测试用例代码,1个测试用例中last_answer_time字段全设置为None,另一个测试用例中last_answer_time字段全设置为有效值,单独运行的时候,都pass了,当合在一起运行的时候,出错,返回什么也没有查到!(每个测试用例都会在执行前做清空数据库的操作,所以不会是脏数据造成),通过str(base_query)打印执行sql命令,发现,单独执行的时候,生成的sql语句where那块正常,但合并执行的时候,那个语句的过滤变成了
WHERE 0 = 1
这明明是根本什么都不选择的意思呀!!!

猜测1:是否是对None的支持不好

于是改数据库字段,last_answer_time变成一个time的int值,默认是0,再次查询,发现打印的sql语句中还是有 0 = 1,所以不是。

猜测2: 原sqlalchemy语句写法有误,让SqlAlchemy引擎认为where查询无效,变为 0 = 1 的查询语句

直觉上否定了这个,因为用例单独执行的时候是ok的,否则,应该一直出错。

猜测3:之前的操作对数据库的查询还是存在影响?

时间冲突?资源未释放?

用例执行之前,加了2秒的等待,问题依旧。否认这个方向。

执行冲突,有顺序依赖?

通过

    tests = unittest.TestLoader().discover('tests', pattern="test_*questions.py")    unittest.TextTestRunner(verbosity=2).run(tests)

将命令拆成两组,1个是test_get_answered_questions.py, 另一个是 test_get_questions.py,发现,如果 test_get_answered_questions.py 先执行,就会有 WHERE 0 = 1 的语句出现,但如果顺序倒过来,所有用例pass。

看来,是某个用例的执行的确对之后的用例产生了影响,那为什么会有影响?
后来通过查看代码,对 last_answer_time 有一个赋值不对。应该是

 question.last_answer_time = datetime.datetime.now()

结果写成了

 HabitQuestion.last_answer_time = datetime.datetime.now()

那为什么这样会让SQL的语句变为 WHERE 0 = 1 呢?原因是,原来 last_answer_time 的定义是

    last_answer_time = db.Column(db.DateTime)

这是一个数据库Column。执行了赋值之后,对于SQLAlchemy而言,HabitQuestion.last_answer_time 不再是有效的数据库表column,无法针对其进行过滤,所以,返回不了任何有效数据,就采用 WHERE 0 = 1,表示没有任何数据可以返回。

后记

属于活久见的测试bug,和以前写linux下ide硬盘驱动,堆栈溢出导致系统会重启到window ce上一个德行。在查找这个问题上,花费的时间比写功能代码还要多。不过还是有收获的。

在一开始 HabitQuestion.last_answer_time.isnot(None) 不可用,其实就是因为 HabitQuestion.last_answer_time 被重新赋值为datetime类型,所以找不到 isnot() 的方法,这个预警自己没有注意。问题修正后,改成isnot的方式使用,完全正常。

其实,对于SqlAlchemy而言,当filter的字段明显不是有效db.Column的情况下,是否直接返回异常更好?毕竟,还是有可能用户手贱写错,然后发现任何和这个字段有关的查询,返回都是空。这种恶心的问题,代码扫描都很难发现。这次算是领教了。

0 0
原创粉丝点击