过滤不适用于混合属性

时间:2014-04-03 09:34:21

标签: sqlalchemy

我正在我正在创建的一个小博客应用程序中实现SQLAlchemy ORM(作为Alchemy的学习练习)。 我偶然发现了一些我不确定的事情 - 我认为我知道一种方法,但它可能太长,以至于成为“最好的”。一个表/对象具有“标题”列。我希望能够从中创建一个slug类型的字符串。我看着hybrid properties,似乎就是这个伎俩。

class Post(Base):
    __tablename__ = 'posts'
    id = Column(Integer, primary_key=True)
    title = Column(String)

    @hybrid_property
    def slug(self):
        return self.title.replace(" ", "-").lower()


    def __repr__(self):
        return "<Post(id='%s', title='%s', slug='%s')>" % (
            self.id, self.title, self.slug)

post = Post(title="Hello World")
session.add(post)
session.commit()

这适用于检索值:

>>> p = session.query(Post).filter(Post.title=='Hello World')
>>> p 
>>> <Post(id='1', title='Hello World', slug='hello-world')>    

但是,当我尝试在此属性上使用过滤器时:

>>> p = session.query(Post).filter(Post.slug=='hello-world')  

我收到此错误:

>>> File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/attributes.py", line 270, in __ge
tattr__
key)
AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with
Post.title has an attribute 'replace' 

这是否意味着我应该创建一个custom Comparator?看起来很多工作,对于大多数sql中的一行来说。基本上,我的整个方法是否有缺陷?

1 个答案:

答案 0 :(得分:5)

from sqlalchemy import func

...

class Post(Base):

    ...


    @hybrid_property
    def slug(self):
        return self.title.replace(" ", "-").lower()

    @slug.expression
    def slug(cls):
        return func.lower(func.replace(cls.title, " ", "-"))

    ...

SQLAlchemy不了解hybrid_property-decorated函数中的Python代码,因此无法将其转换为本机SQL查询。这就是为什么你需要以SQLAlchemy可以理解它的方式提供它,就像在Expression属性中定义的那样,SQLAlchemy可以将它变成SQL查询。