繁体   English   中英

SQLAlchemy:如何为列的析取创建混合属性?

[英]SQLAlchemy: How can I create a hybrid property for the disjunction of columns?

我有一个User类,其中存储了一个“ first_name”列和一个“ alias”列来描述一个人的名字和昵称。 我希望能够查询此类以通过first_name或别名查找用户,因此我这样编写了此类:

from sqlalchemy import Column, Integer, String, create_engine, orm
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.hybrid import hybrid_property


engine = create_engine('sqlite:///:memory:')
Base = declarative_base()
Session = orm.sessionmaker(engine)


class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    first_name = Column(String(64))
    alias = Column(String(64), nullable=True)

    @hybrid_property
    def name(self):
        return self.alias or self.first_name

    def __repr__(self):
        return 'User("{}" a.k.a. "{}")'.format(self.first_name, self.alias)


if __name__ == "__main__":
    Base.metadata.create_all(engine)

这几乎可行。 我可以通过用户的名字搜索他们。 但是我无法通过别名搜索用户。

>>> session = Session()
>>> user = User(first_name="Edward", alias="Ed")
>>> session.add(user)
>>> session.flush()
>>> session.query(User).filter_by(name="Edward").first()
User("Edward" a.k.a. "Ed")
>>> session.query(User).filter_by(name="Ed").first()
>>>

这是有道理的-按name生成的表达式不是我想要的。

>>> print session.query(User).filter_by(name="Ed")
SELECT "user".id AS user_id, "user".first_name AS user_first_name, "user".alias AS user_alias
FROM "user"
WHERE "user".first_name = :first_name_1

有关混合属性SQLAlchemy文档似乎建议解决方案是使用hybrid_property.expression()更改生成的表达式。 但是,我看不到返回什么表达式是有意义的。

我的第一个想法是返回某种OR

from sqlalchemy.sql import or_

@name.expression
def name(cls):
    return or_(cls.first_name, cls.alias)

但是它生成的表达式可以预料是错误的:

SELECT "user".id AS user_id, "user".first_name AS user_first_name, "user".alias AS user_alias
FROM "user"
WHERE ("user".first_name OR "user".alias) = :param_1

我该如何进行这项工作?

经过更多的研究和实验,结果证明该解决方案在“ 构建自定义比较器 ”部分中进行了描述。 您可以使用Comparator对象来实现自定义比较:

class Either(Comparator):
    def __init__(self, left, right):
        self.left = left
        self.right = right

    def __eq__(self, other):
        return or_(other == self.left, other == self.right)


class User(Base):
    # ...

    @name.comparator
    def name(self):
        return Either(self.first_name, self.alias)

哪个按预期工作:

>>> user
User("Edward" a.k.a. "Ed")
>>> print session.query(User).filter_by(name="Edward")
SELECT "user".id AS user_id, "user".first_name AS user_first_name, "user".alias AS user_alias
FROM "user"
WHERE "user".first_name = :first_name_1 OR "user".alias = :alias_1
>>> print session.query(User).filter_by(name="Edward").first()
User("Edward" a.k.a. "Ed")
>>> print session.query(User).filter_by(name="Ed").first()
User("Edward" a.k.a. "Ed")

我认为通过研究“ 混合值对象 ”,这里还有更多的空间可改进,但是,它仍然在逃避我。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM