Skip to main content
 首页 » 编程设计

python之ndb 没有按日期正确查询

2025年05月04日13dflying

我正在对 Expense 模型的方法进行单元测试。模型的相关部分如下所示:

class Expense(ndb.Model): 
 
    user = ndb.KeyProperty(User, required=True) 
    timestamp = ndb.DateTimeProperty(required=True) 
    ... 
 
    @staticmethod 
    def new(user, amount, comment, description, timestamp): 
        """creates a new expense and stores it. It returns the Expense instance""" 
        ... validation ... 
        exp = Expense(user=user, timestamp=timestamp, ...) 
        exp.put() 
        return exp 
 
    @staticmethod 
    def list(user, from_date=None, to_date=None): 
        ...   
        query = Expense.query(Expense.user == user) 
        if from_date is not None: 
            if not isinstance(from_date, datetime.datetime): 
                raise ValueError("from_date must be a datetime.datetime instance") 
            query.filter(Expense.timestamp >= from_date) 
        if to_date is not None: 
            if not isinstance(to_date, datetime.datetime): 
                raise ValueError("to_date must be a datetime.datetime instance") 
            query.filter(Expense.timestamp <= to_date) 
        query.order(- Expense.timestamp) 
        return query 

我有以下单元测试来测试 Expense.list:

测试的前 4 行创建了 Expense 模型实例的实例。

  • 2013 年 1 月 3 日
  • 2013 年 11 月 1 日
  • 2013 年 11 月 2 日
  • 2014 年 1 月 1 日

为您节省一些水平滚动的主页。

def test_list_expenses_filter_by_date(user): 
    expense1 = Expense.new(user=user, amount=200.12, description="a netbook", comment="", timestamp=datetime.datetime(year=2013, month=1, day=3, hour=12, minute=30)) 
    expense2 = Expense.new(user=user, amount=1.0, description="A can of coke", comment="Really cheap!",timestamp=datetime.datetime(year=2013, month=11, day=1, hour=12, minute=30)) 
    expense3 = Expense.new(user=user, amount=3.05, description="A burger", comment="Tasty!", timestamp=datetime.datetime(year=2013, month=11, day=2, hour=12)) 
    expense4 = Expense.new(user=user, amount=0.30, description="Toilet visit", comment="I normally don't pay for these things, but it was urgent.", timestamp=datetime.datetime(year=2014, month=1, day=1, hour=1, minute=15)) 
 
    from_date = datetime.datetime(year=2013, month=5, day=1) 
    to_date = datetime.datetime(year=2013, month=12, day=31) 
    exps  = Expense.list(user=user, from_date=from_date, to_date=to_date) 
    for expense in exps: 
        assert from_date <= expense.timestamp <= to_date 

但是当我从 pytest 运行这个测试时,我在下一行得到了一个 AssertionError,正如 pytest 所显示的:

assert datetime.datetime(2013, 5, 1, 0, 0) <= datetime.datetime(2013, 1, 3, 12, 30) 

E + 其中 datetime.datetime(2013, 1, 3, 12, 30) = Expense(key=Key('Expense', 5066549580791808), amount=200.12, comment=u'', desc...tamp= datetime.datetime(2013, 1, 3, 12, 30), user=Key('User', 5629499534213120)).timestamp

那么,为什么我的 Expense.list 方法会返回数据超出范围的实例?

我已经在 App Engine 测试台和请求处理程序中尝试过此操作,在浏览器中查看输出,因此它不是数据存储 stub 中的错误。

我也尝试过以不同的方式构建查询。我没有重复调用 Query.filter,而是将过滤器表达式添加到列表中,将该列表作为 *args 传递给 ndb.AND 并将其传递到单个 Query.filter 但这也不起作用。

我已经排除了 ndb 中存在错误的可能性。以下测试通过:

def test_ndb_date(): 
    from google.appengine.ext import ndb 
 
    class Time(ndb.Model): 
        timestamp = ndb.DateTimeProperty(required=True) 
 
    t1 = Time(timestamp=datetime.datetime.now() - datetime.timedelta(days=365)) 
    t2 = Time(timestamp=datetime.datetime.now()) 
    t3 = Time(timestamp=datetime.datetime.now() + datetime.timedelta(days=365)) 
    ndb.put_multi([t1, t2, t3]) 
    from_date = datetime.datetime.now() - datetime.timedelta(days=1) 
    to_date = datetime.datetime.now() + datetime.timedelta(days = 1) 
    result = Time.query(Time.timestamp <= from_date, Time.timestamp >= to_date).fetch() 
    for time in result: 
        assert from_date <= time.timestamp >= to_date 

请您参考如下方法:

我误解了 Query.filter 的工作原理。它不会改变当前的 Query 实例,而是返回一个新实例。