quick query one many in_ how guide python sqlalchemy

query - sqlalchemy python



sqlalchemy Mueve las columnas de la mezcla al final (4)

Descubrí que podía establecer el orden de la columna (en la última posición) en el Mixin usando:

@declared_attr def notes(cls): col = sa.Column(sa.String(4000) , nullable=False, default='''') # get highest column order of all Column objects of this class. last_position = max([value._creation_order for key, value in vars(cls).items() if isinstance(value, Column)]) col._creation_order = last_position + 0.5 return col class Service(Base, NotesMixin): __tablename__ = "service" service_id = sa.Column(sa.Integer, primary_key=True) name = sa.Column(sa.String(255), nullable=False, index=True, unique=True)

Para establecer el orden de las columnas en función de la ubicación de otra columna (similar a

alter table `some_table` modify `some_colum` `some_type` after `some_other_column;

vea https://stackoverflow.com/a/3822219/488331 )

Puedes usar:

@declared_attr def notes(cls): col = sa.Column(sa.String(4000) , nullable=False, default='''') col._creation_order = cls.some_other_column._creation_order + 0.5 return col

NOTA: Si usas + 1 terminas 2 columnas atrás. Realmente no entiendo por qué puedes usar un decimal.

Para establecer el orden de las columnas en función de la ubicación de la primera columna (haga esto siempre la cuarta columna), puede hacer:

@declared_attr def notes(cls): col = sa.Column(sa.String(4000) , nullable=False, default='''') # get lowest column order of all Column objects of this class. start_position = min([value._creation_order for key, value in vars(cls).items() if isinstance(value, Column)]) col._creation_order = start_position + 3.5 return col

Tengo un modelo sqlalchemy, donde la mayoría de todas las tablas / objetos tienen un campo de notas. Así que para intentar seguir el principio DRY, moví el campo a una clase mixta.

class NotesMixin(object): notes = sa.Column(sa.String(4000) , nullable=False, default='''') class Service(Base, NotesMixin): __tablename__ = "service" service_id = sa.Column(sa.Integer, primary_key=True) name = sa.Column(sa.String(255), nullable=False, index=True, unique=True) class Datacenter(Base, NotesMixin): __tablename__ = "datacenter" datacenter_id = sa.Column(sa.Integer, primary_key=True) name = sa.Column(sa.String(255), nullable=False, index=True, unique=True) class Network(Base, NotesMixin, StatusMixin): __tablename__ = "network" network_id = sa.Column(sa.Integer, primary_key=True) etc...

Ahora la columna de notas es la primera columna en el modelo / db. Sé que no afecta la funcionalidad de mi aplicación, pero me irrita un poco ver las notas antes de la identificación, etc. ¿Alguna forma de moverla al final?


Encontró una solución más limpia:

Utilice el decorador sqlalchemy.ext.declarative.declared_attr en sqlalchemy 0.6.5 ( sqlalchemy.util.classproperty en sqlalchemy <= 0.6.4)

class NotesMixin(object): @declared_attr def notes(cls): return sa.Column(sa.String(4000) , nullable=False, default='''')

Según los documentos, esto es "para las columnas que tienen claves externas, así como para la variedad de construcciones de nivel de asignador que requieren un contexto de destino explícito". Si bien este no es el caso aquí en sentido estricto, lo hace llamando al método (y creando la columna) cuando se construye la subclase, evitando así la necesidad de hacer una copia. Lo que significa que la columna de mezcla vendrá al final. Probablemente una mejor solución que hackear _creation_order ...


La respuesta fácil: solo cree las tablas de la base de datos, en lugar de hacer que sqlalchemy lo haga con metadata.create_all() .

Si no lo encuentra aceptable, me temo que esto requeriría un cambio (pequeño) en sqlalchemy.ext.declarative , o tendría que crear su propia metaclase y pasarla a declarative_base() con la palabra clave metaclass argumento. Esa clase se utilizará en lugar del DeclarativeMeta predeterminado.

Explicación: sqlalchemy usa el orden de creación de las propiedades de la columna, que almacena en el atributo "privado" ._creation_order (generado cuando se llama a la Columna ()). La extensión declarativa hace columnas de mezcla creando una copia del objeto de columna de su clase de mezcla, y agregando eso a la clase. El ._creation_order de esta copia se establece en el mismo valor que la propiedad original de la clase mixin. Por supuesto, como la clase mixin se crea primero, sus propiedades de columna tendrán un orden de creación inferior al de la subclase.

Por lo tanto, para que su solicitud sea posible, se debe asignar un nuevo orden de creación cuando se realice la copia, en lugar de tomar el original. Puedes intentar crear tu propia metaclase en base a esta explicación y usarla. Pero también puedes intentar preguntar a los desarrolladores de sqlalchemy. ¿Quizás están dispuestos a aceptar esto como una solicitud de error / característica? Al menos, parece un cambio menor (una línea), que no tendría ningún otro efecto que el cambio que solicitas (que posiblemente sea mejor también).


También se puede cambiar el orden de las columnas en la compilación CREAR TABLA (aquí ejemplificada para el dialecto postgresql ):

from sqlalchemy.schema import CreateTable from sqlalchemy.ext.compiler import compiles @compiles(CreateTable, ''postgresql'') def _compile_create_table(element, compiler, **kwargs): element.columns = element.columns[::-1] # reverse order of columns return compiler.visit_create_table(element)

Esto luego funciona con metadata.create_all() .