Reputation: 658
I have a very simple model as below:
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), index=True)
role = db.Column(db.String(64))
and then a simple query that I'm using in my view to filter users by roles:
roles = list(map(str, query_params.get('roles', [])))
User.query.filter(User.role.in_(roles))
Roles start with a capital letter ('Director', 'Manager', etc...) and I want to add a mapping to the column which returns it in lower case.
I thought column_property()
or @hybrid_property
would do the job but I'm either wrong, or I'm making a mistake in the implementation.
I tried these changes:
@hybrid_property
def role_tag(self):
return self.role.lower()
User.query.filter(User.role_tag.in_(roles))
The property indeed returns the lower case value, but it doesn't work in the query raising this exception:
AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with User.profile_role has an attribute 'lower'
I then tried to change the model as such:
role_tag = column_property(role.lower())
which instead raise another exception on the Model directly.
AttributeError: Neither 'Column' object nor 'Comparator' object has an attribute 'lower'
I understand the issue is related to how they operate, if at class or instance level... But in the end I haven't been able to find the correct implementation for my use case.
Upvotes: 0
Views: 482
Reputation: 52937
The solution is to define the behaviour separately for instance and class context, or Python and SQL context:
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), index=True)
role = db.Column(db.String(64))
@hybrid_property
def role_tag(self):
return self.role.lower()
@role_tag.expression
def role_tag(cls):
return db.func.lower(cls.role)
Upvotes: 1