【问题标题】:Two sqlalchemy queries return the same result even though they have different filters两个 sqlalchemy 查询返回相同的结果,即使它们具有不同的过滤器
【发布时间】:2014-03-06 17:24:35
【问题描述】:

假设我有 2 个类:Foo 和 Bar。假设一个 Foo 可以有许多条(通过 foo.Bars)。 Bar 有一个 end_date 来指示 bar 何时结束。未结束的小节默认设置为“9999-12-31”。

我在下面编写了两个查询来获得一个 Foo 但使用不同的条形过滤器,这样第一个查询就会给我没有结束的条形;第二个给了我已经结束的酒吧。

   today = date.today().strftime("%Y-%m-%d")

   current = session.query(Foo)\
                        .join(Bar)\
                        .filter(
                            and_(
                                 Foo.code=='MY_STRING',
                                 Bar.end_date >= today,
                                 )
                        )\
                        .options(contains_eager('Bars'))\
                        .one()

   previous = session.query(Foo)\
                        .join(Bar)\
                        .filter(
                            and_(
                                 Foo.code=='MY_STRING',
                                 Bar.end_date < today,
                                 )
                        )\
                        .options(contains_eager('Bars'))\
                        .one()

由于某些原因,previous.Bars 与 current.Bars 相同,即使我们已过滤条形以使其不同(至少这是我的尝试)。例如。 current.Bars 返回 [bar1, bar2, bar3]previous.Bars 返回 [bar1, bar2, bar3]

如果我切换两个查询(即将previous 放在current 之前),则当前的Bars 与previous.Bars 相同。例如。 current.Bars 返回[bar4, bar5, bar6]previous.Bars 返回[bar4, bar5, bar6]

请注意,我 100% 确定 previous.Bars 中的基础数据应该与 current.Bars 不同。 IE。我应该得到[bar4, bar5, bar6]previous.Bars[bar1, bar2, bar3]current.Bars

有人可以解释为什么我得到相同的结果吗?我该如何解决这个问题?我意识到最好只有一个查询。

提前致谢!

PS 我使用的是 0.8 版

【问题讨论】:

  • 你使用的是什么版本的 SQLAlchemy?
  • @Drewness 我使用的是 0.8 版

标签: python sqlalchemy


【解决方案1】:

问题行是.options(contains_eager('Bars'))。它基本上告诉sqlachemy,对于每个加载的foo,该查询包含all Bars。因此,当您访问 foo.Bars 时,它不再查询数据库,因为它已从 join 中获取那些(过滤)条并假定它们是完整的 foo.Bars 关系。 下次运行查询时,sqlalchemy 会意识到对象 Foo 已经加载(包括它的关系 Bars)并且基本上返回它当前在会话(内存)中的内容。

您可以通过在执行previous 的查询之前使用session.expunge(current) 从会话中删除对象来解决此问题,以便sqlalchemy 将完全重新加载它,但您必须小心使用current之后的实例,因为它不再是会话的一部分。

更好:因为无论如何你都需要两边,所以只需在 python 端轻松地进行这种分离:

today = datetime.datetime.today()#.strftime("%Y-%m-%d")
foo = (session.query(Foo)
        .options(joinedload(Foo.Bars))
        .filter(Foo.code=='MY_STRING')
        .one()
        )
prev_bars = [bar for bar in foo.Bars if bar.end_date < today]
curr_bars = [bar for bar in foo.Bars if bar.end_date >=today]
print foo
print prev_bars
print curr_bars

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-20
    • 1970-01-01
    相关资源
    最近更新 更多