-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
QuickHybrid
Mike Bayer edited this page Feb 20, 2014
·
2 revisions
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.
#!python
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:
#!python
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:
#!python
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
.