Wiki
sqlalchemy / UsageRecipes / QuickHybrid
QuickHybrid
Declare a @hybrid_property using a decorator that generates a corresponding Column for you. The technique here is to combine the declared_attr
decorator with a hybrid so that you still get the full configurability of hybrid while piggybacking on the usual declarative column assignment.
from sqlalchemy.ext.declarative import declared_attr from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy import Column def mapped_column(*args, **kw): colargs, colkw = args, kw class decorate(declared_attr): def __init__(self, fget, *arg, **kw): super(decorate, self).__init__(fget, *arg, **kw) assert fget.__name__.startswith("_") self.attrname = fget.__name__[1:] self.colname = colname = fget.__name__ @hybrid_property def attrib(self): return fget(self, getattr(self, colname)) @attrib.setter def attrib(self, value): setattr(self, colname, value) @attrib.expression def attrib(cls): return getattr(cls, colname) self.attrib = attrib self.col = Column(self.attrname, *colargs, **colkw) def __get__(desc, self, cls): setattr(cls, desc.attrname, desc.attrib) return desc.col def setter(self, fset): self.attrib.setter(fset) return self def deleter(self, fdel): self.attrib.deleter(fset) return self def expression(self, expr): self.attrib.expression(fset) return self return decorate
Basic usage:
from sqlalchemy import Column, Integer, String, create_engine from sqlalchemy.orm import Session from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class MyClass(Base): __tablename__ = 'mytable' id = Column(Integer, primary_key=True) @mapped_column(String) def _name(self, value): return "The name is: " + value e = create_engine('sqlite://',echo=True) Base.metadata.create_all(e) s = Session(e) s.add(MyClass(name="myname")) s.commit() print s.query(MyClass).first().name
The full capability of @Hybrid is still here, as below where we add a custom setter in:
class MyClass(Base): __tablename__ = 'mytable' id = Column(Integer, primary_key=True) @mapped_column(String) def _name(self, value): return "The name is: " + value @_name.setter def _name(self, value): return value + "is my name"
the test program's output with the above would be The name is: myname is my name
.
Updated