The point of hybrid attributes is to allow you to construct a property
that can be evaluated against an instance (in which case it is "normal
python"), or against a class (in which case it needs to return an SQL
expression). *Sometimes* the same python code can work in both
contexts, but only if it is a very simple expression.
Here's your example:
@hybrid_property
def is_id_valid(self):
# some logic here
if
self.id % 3 == 0:
return True
else:
return False
If you had already retrieved an instance of GeneralBeqReq from the
database, you could access its "is_id_valid property" and it would
work as expected, because "
self.id" would be a normal python integer.
But if you try to access it from the class (ie.
GeneralBeqReq.is_id_valid), it won't do what you expect. "self" will
actually be the class, GeneralBeqReq. "
self.id" will be a special
SQLAlchemy "InstrumentedAttribute" object. It happens that
InstrumentedAttributes do support the % operator, returning an SQL
expression object, so "
self.id % 3 == 0" will actually return an SQL
expression. But using it inside an "if" statement doesn't make any
sense - you're checking the boolean value of the SQL expression
object, not the result of evaluating it against any particular row. So
GeneralBeqReq.is_id_valid is just going to return a constant (either
True or False, not sure which).
You'd need to add an alternative definition of the is_id_valid
property which returns an SQL expression:
https://docs.sqlalchemy.org/en/14/orm/extensions/hybrid.html#defining-expression-behavior-distinct-from-attribute-behavior
If you can't express your validation function as an SQL expression,
you can't pass it to Query. You'd have to postprocess the query
results in python instead, like this:
a = session.query(GeneralBeqReq)\
.filter(GeneralBeqReq.c.BeqReqStatus == 1)\
.all()
a = [obj for obj in a if obj.is_id_valid]
Simon
> To view this discussion on the web visit
https://groups.google.com/d/msgid/sqlalchemy/271604e6-8365-434a-8b5a-d37095c88549n%40googlegroups.com.