djangoat
djangoat

Reputation: 485

Filter not working on hybrid property

I am implementing SQLAlchemy ORM in a small blog app I am creating (as a learning exercise to Alchemy). I have stumbled upon something I am not sure of - I think I know an approach, but it may be too long winded to be the "best" one. One table / object has a "title" column. I want to be able to create a slug type string from this. I looked at hybrid properties and it seemed to do the trick.

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()

This works fine for a retrieval of the value:

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

However when I try to use a filter on this property:

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

I get this error:

>>> 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' 

Does this mean I should create a custom Comparator? Seems a lot of work, for what would be a one line in most sql. Basically, is my whole approach flawed?

Upvotes: 6

Views: 3463

Answers (1)

Vladimir Iliev
Vladimir Iliev

Reputation: 241

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 doesn't understand the Python code in the hybrid_property-decorated function, so it cannot convert it to a native SQL query. That's why you need to provide it in such a way that SQLAlchemy can understand it, like defined in the expression property, which SQLAlchemy can turn into an SQL query.

Upvotes: 6

Related Questions