The sqlalchemy hybrid_property can not be set during initialization, invalid keyword argument?

Question:

I have a class of a sqlalchemy model like this:

from sqlalchemy.ext.hybrid import hybrid_property

class Connection(Model):

    name = dbColumn(db.String, nullable=False)
    provider = db.Column(db.String, nullable=True)
    version = db.Column(db.Integer, nullable=True)
    _connection_status = db.Column('connection_status',db.String, nullable=True)

    @hybrid_property
    def connection_status(self) -> str:
        if not self._connection_status:
            self._connection_status="Connection_Not_Set"
        return self._status

    @connection_status.setter
    def connection_status(self, connection_status: str):
        self._connection_status = connection_status

if I try to create a new object:

connection=Connection(name="Connection1", status="Initialized")

I get an error 'connection_status' is an invalid keyword argument.

So this appears if I try to set it during initialization. If I set it after the object is created I get no errors, for example:

connection=Connection(name="Connection1")
connection.connection_status="Initialized"

this works.

Why is the hybrid property not recognized during initialization?

Asked By: KZiovas

||

Answers:

So it seems that the problem is described here in this discussion. Essentially because the hybrid_property is used in a class (sqlalchemy table) level to create SQL queries the getter must have logic that can be directly converted to SQL statements. If someone wishes to have more complex logic like the if statement in my example there need to be two different methods one to be used in class level for sql queries with sqlalchemy query in it and one to be used in Python level. The method for the class level needs an .expression decorator.

In my case above I would have to use a case sqlalchemy statement as described in the attached link. For example

@connection_status.expression
def connection_status(cls):
    return case((cls._connection_status.is_(None),"Connection_Not_Set"),else_=cls._connection_status)

For more information on how to format case statements in sqlalchemy see here

Answered By: KZiovas