【问题标题】:SQLAlchemy using load_only with distinctSQLAlchemy 使用 load_only 和 distinct
【发布时间】:2017-12-04 04:58:19
【问题描述】:

我正在尝试使用与 SQLAlchemy 不同的函数,但它似乎不起作用。我准备了一个小例子,你可以看到我的问题:

#-*- coding: utf-8 -*-
from sqlalchemy import create_engine,Column, Integer
from sqlalchemy.orm import sessionmaker,load_only
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('sqlite:///:memory:')
Session = sessionmaker(bind=engine)
session = Session()
Base = declarative_base()

class my_class(Base):
    __tablename__ = 'my_table'
    id= Column(Integer, primary_key=True)
    data= Column(Integer)

Base.metadata.create_all(engine)

for i in range(10):
    p=my_class()
    p.id=i
    p.data=55
    session.add(p)
session.commit()

s=session.query(my_class).distinct(my_class.data).options(load_only(my_class.data))

print (s)
for a in s.all():
    print (a.id,a.data)

执行此操作,我希望得到这样的输出:

SELECT my_table.data AS my_table_data 
FROM my_table
None 55

但我却得到了这个:

SELECT DISTINCT my_table.id AS my_table_id, my_table.data AS my_table_data 
FROM my_table
0 55
1 55
2 55
3 55
4 55
5 55
6 55
7 55
8 55
9 55

我做错了什么?

【问题讨论】:

    标签: python python-3.x sqlalchemy


    【解决方案1】:

    如果查询完整的 ORM 实体,推迟主键是没有意义的,因为an entity must have an identity so that a unique row can be identified in the database table。因此,尽管您拥有load_only(),但查询包含主键。如果您只需要数据,则应专门查询:

    In [12]: session.query(my_class.data).distinct().all()
    2017-06-30 12:31:49,200 INFO sqlalchemy.engine.base.Engine SELECT DISTINCT my_table.data AS my_table_data 
    FROM my_table
    2017-06-30 12:31:49,200 INFO sqlalchemy.engine.base.Engine ()
    Out[12]: [(55)]
    

    实际上有一个issue where having load_only() did remove the primary key from the select list,它是fixed in 0.9.5

    [orm] [bug] 修改了orm.load_only() 的行为,使得主键列始终添加到“未延迟”列列表中;否则,ORM 无法加载行的标识。显然,可以推迟映射的主键,而 ORM 将失败,这并没有改变。但是由于 load_only 本质上是在说“除了 X 之外的所有东西都推迟”,所以更关键的是 PK 列不属于这种推迟的一部分。

    【讨论】:

    • 但是我需要这个类,所以我可以稍后获取 JSON。
    • 听起来你应该扩展你的问题以更好地描述你真正追求的东西,或者换句话说an XY problem。但无论如何,答案仍然存在:你不能拥有“DISTINCT ON”查询和 ORM 实体,至少不容易。您可以使用 DISTINCT 映射查询,但这是另一回事。最后 ORM 实体必须有一个身份。
    • 所以你没有做错什么,只是你试图做的事情不能用 ORM 来完成。
    • 好吧,我正在创建一个静止的 web 服务,以将应用程序与数据库连接起来,因此通信始终通过 JSON。我将 ORM 放在 WS 和数据库之间,因此将来的任何更改都可能更容易。
    • 重申:一个 ORM 实体对象实例唯一地映射到数据库表中的单行。为此,它需要主键,因此在获取对象实例时不能延迟它。您可能有理由尝试为某些列获取不同的值,但您尚未对其进行描述。当您说session.query(my_class) 时,您会为对象实例创建一个查询,除非稍后with_entities() 调用等修改它。
    猜你喜欢
    • 1970-01-01
    • 2017-01-25
    • 2015-04-25
    • 2018-04-21
    • 2023-04-05
    • 2019-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多