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