python - many - sqlalchemy query
Metaclass personalizado para crear propiedades hÃbridas en SQLAlchemy (1)
No es necesario utilizar metaclases para una clase mapeada SQLAlchemy ya que suministramos muchos eventos para agregar características a las clases a medida que se crean y / o mapean. mapper_configured podría ser bueno aquí, que si tienes 0.8 puedes aplicar a MyBase
directamente:
@event.listens_for(MyBase, ''mapper_configured'')
def get_special_columns(mapper, cls):
for attrname in dir(cls):
val = getattr(cls, attrname)
if isinstance(val, SpecialColumn):
name1, name2 = "_%s_1" % attrname, "_%s_2" % attrname
setattr(cls, name1, Column(...))
setattr(cls, name2, Column(...))
@hybrid_property
def myhybrid(self):
return getattr(self, name1), getattr(self, name2)
@myhybrid.setter
def myhybrid(self, value):
setattr(self, name1, value[0])
setattr(self, name2, value[1])
setattr(cls, attrname, myhybrid)
tenga en cuenta que setattr () es la mejor manera de ir aquí, simple y al grano.
Quiero crear una interfaz personalizada sobre SQLAlchemy para que algunas propiedades híbridas predefinidas sean compatibles de forma transparente.
Específicamente, quiero crear una clase SpecialColumn
y una metaclase para que cuando un usuario agregue SpecialColumn
como un atributo de una clase, mi metaclass personalizada reemplace ese atributo con dos SQLAlchemy Column
y agregue una propiedad híbrida que obtenga y establezca esas dos columnas como una tupla Aquí está mi enfoque hasta ahora:
Primero, definí mi tipo de columna especial:
class SpecialColumn(object):
pass
Luego, definí una metaclase heredando de DeclarativeMeta que escanea la clase para las instancias de SpecialColumn
y las reemplaza con dos Column
y una propiedad híbrida (definida como un cierre):
class MyDeclarativeMeta(DeclarativeMeta):
def __new__(cls, name, bases, attrs):
for name, col in attrs.items():
if isinstance(col, SpecialColumn):
# Replacing the column
del attrs[name]
col1_name = ''_{0}_1''.format(name)
col2_name = ''_{0}_2''.format(name)
attrs[col1_name] = Column(...)
attrs[col2_name] = Column(...)
# Adding the hybrid property
def getter(self):
return (getattr(self, col1_name), getattr(self, col2_name))
attrs[name] = hybrid_property(getter)
Y finalmente construí una instancia de declarative_base
con ella, y dejé que el usuario definiera las clases con la nueva base:
MyBase = declarative_base(metaclass=MyDeclarativeMeta)
class MyClass(MyBase):
col1 = SpecialColumn()
col2 = Column(...)
Ahora para mis preguntas: En primer lugar, ¿es correcto mi enfoque? En segundo lugar, ¿cómo puedo usar la metaclase para agregar el colocador? ¿Sería correcto hacer lo siguiente?
def setter(self, (v1, v2)):
setattr(self, col1_name, v1)
setattr(self, col2_name, v2)
Y luego simplemente haz attrs[name].setter(setter)
?