'Flask-SQLAlchemy .like() method raises NotImplementedError

I am having trouble building a Flask-SQLAlchemy query with a like() method, which should build a query using the the SQL LIKE statement.

According the SQLAlchemy docs the like method can be called on a column like this:

select([sometable]).where(sometable.c.column.like("%foobar%")) 

I have a ModelClass that subclasses the Flask-SQLAlchemy db.Model class. Defined like this:

class ModelClass(db.Model):
    # Some other columns ... 
    field1 = db.Column(db.Integer(), db.ForeignKey('my_other_class.id'))
    rel1 = db.relationship("MyOtherClass", foreign_keys=[field1])

I then have a loop where I am building up filters dynamically. Outside the loop I use these filters to filter a query. The inside of my loop, slightly modified, looks like this:

search_term = '%{}%'.format(search_string)
my_filter = getattr(ModelClass, field_string).like(search_term)

This raises an error at the line with the like method:

NotImplementedError: <function like_op at 0x101c06668>

It raises this error for any text string. The Python docs for a NotImplementedError say:

This exception is derived from RuntimeError. In user defined base classes, abstract methods should raise this exception when they require derived classes to override the method.

This isn't an AttributeError, so I think the like method exists, but something else is wrong and I'm not sure what.

Update

Now that I'm looking more closely at the model definition I think the problem might be that I'm doing this on a relationship and not a Column type.

I saw that type(getattr(ModelClass, field_string)) gives:

<sqlalchemy.orm.attributes.InstrumentedAttribute object at 0x102018090>

Since this is not a Column type I looked at the values for field_string and saw that one of the values being passed was actually rel1.

So I guess that's the "answer" but I'm still confused why calling .like() on rel1 didn't raise an AttributeError.



Solution 1:[1]

As @ACV said, calling methods such as like(), is_(), is_not(), etc. on relationship attributes raises NotImplementedError. So, to workaround this problem, I called the method directly on the real column attribute instead of the relationship. E.g. if I have the following two attributes in a Model:

user_id = db.Column(db.Integer, db.ForeignKey('user.id', ondelete='CASCADE'), index=True)
user = db.relationship(
    'User', backref=db.backref('readings', lazy='dynamic', cascade='all, delete-orphan'))

I did the following query to filter the instances whose attribute user IS NOT NULL. (Note that I'm using MyModel.user_id instead of MyModel.user to successfully run the query):

MyModel.query.filter(MyModel.user_id.is_not(None))

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Caumons