令人困惑的App Engine Datastore问题(ListProperty)
好的,我在本地和云端的gae上都有相同的python代码。
当我在本地存储一个实体时,ListProperty字段的元素类型是datetime.datetime,在数据存储查看器中显示如下:
2009-01-01 00:00:00,2010-03-10 00:00:00
而当我在云端存储相同的内容时,查看器显示:
[datetime.datetime(2009, 1, 1, 0, 0), datetime.datetime(2010, 3, 9, 0, 0)]
为什么会有不同的表现形式呢?
这本来不太困扰我,只有在我在云端查询这个字段时,查询却找不到匹配的实体(在本地是可以找到的)——这让我觉得可能是这种不同的表现形式导致了问题。我再强调一下,代码是完全一样的。
有没有人能想出这是为什么,以及解决办法呢?
更新:
我的查询如下(使用了过滤器):
from x import y
from datetime import datetime
from google.appengine.ext import db
q = y.EntityType.all().filter('displayDateRange <=',datetime.now()).filter('displayDateRange >=',datetime.now())
usersResult = q.fetch(100)
print `len(usersResult)`
结果应该是1,但实际上是0。
实际上,问题只出在指定值为datetime.datetime的ListProperty上——在云端,StringListProperty的查询是正常的。
我在本地和云端的交互控制台上都尝试了原始过滤器,云端没有返回任何结果。所以我猜这可能是数据存储的问题,一定与存储格式有关——在两个数据存储中,我只有一个实体值,ListProperty看起来是这样的:
2009-01-01 00:00:00,2010-03-09 00:00:00
[datetime.datetime(2009, 1, 1, 0, 0), datetime.datetime(2010, 3, 9, 0, 0)]
分别在本地和云端。
有什么想法吗?
进一步更新
我把datetime.now()替换成了硬编码的datetime对象——现在的过滤器看起来是这样的:
y.EntityType.all().filter('displayDateRange <=',datetime(2009,11,24)).filter('displayDateRange >=',datetime(2009,11,24))
注意,上面的datetime ListProperty范围是从2009年1月1日到2010年3月9日,这应该能返回上面的实体——我在本地开发服务器上尝试了这个完全相同的过滤器,结果是可以的。而在云端,由于datetime.datetime ListProperty的不同表现形式,结果却不行。
注意,这个是根据当前最佳实践来过滤日期范围得来的。
有没有人能想出可能出错的地方?
2 个回答
你看到的问题很明显是在本地情况下进行字符串转换(调用了 __str__
或 __unicode__
),而在云端则显示了数据的表示形式(repr)。不过,这种输出结果的差异不应该是你在云端查询失败的原因。
你具体的查询是什么呢?
更新:在了解了查询后:
我不太明白你为什么要使用这些过滤条件:
.filter('displayDateRange <=',datetime.now()).filter('displayDateRange >=',datetime.now())
这里有两个问题:
你调用了
datetime.now()
两次,这可能会得到不同的结果,导致结果集为空。在一个负载较高的服务器上,多个线程或进程同时运行时,这种情况尤其常见。你可能想用上面的这对过滤条件来检查是否相等。但如果
datetime.now()
返回的时间精度和数据库中存储的时间精度不同,这样的检查就行不通。一般来说,在浮点数和亚秒级时间值的情况下,检查相等性并不是个好主意。
你想通过这样一对过滤条件达到什么目的呢?
简单来说:现在这个问题被归类为应用引擎开发服务器版本的一个错误,并且在生产环境的云数据存储中不再支持。
我在一篇博客文章中详细解释了这个问题,建议你看看第三点。