2010-09-02 11 views
11

Estoy usando SQLAlchemy, y muchas clases en mi modelo de objetos tienen los mismos dos atributos: id y (número entero & clave principal) y nombre (una cadena). Estoy tratando de evitar declararlos en todas las clases de la siguiente manera:SQLAlchemy: evitando la repetición en la definición de clase de estilo declarativo

class C1(declarative_base()): 
    id = Column(Integer, primary_key = True) 
    name = Column(String) 
    #... 

class C2(declarative_base()): 
    id = Column(Integer, primary_key = True) 
    name = Column(String) 
    #... 

¿Qué es una buena manera de hacerlo? Intenté usar metaclases pero aún no funcionaba.

Respuesta

9

Usted puede factorizar sus atributos comunes en una mixin class, y multiplicar heredarlo junto declarative_base():

from sqlalchemy import Column, Integer, String 
from sqlalchemy.ext.declarative import declarative_base 

class IdNameMixin(object): 
    id = Column(Integer, primary_key=True) 
    name = Column(String) 

class C1(declarative_base(), IdNameMixin): 
    __tablename__ = 'C1' 

class C2(declarative_base(), IdNameMixin): 
    __tablename__ = 'C2' 

print C1.__dict__['id'] is C2.__dict__['id'] 
print C1.__dict__['name'] is C2.__dict__['name'] 

EDITAR: Se podría pensar que esto resultaría en C1 y C2 compartiendo los mismos Column objetos, pero como se indica en SQLAlchemy docs, los objetos de columna son copiados cuando se originan en una clase mixin. He actualizado el ejemplo de código para demostrar este comportamiento.

+0

Desafortunadamente, esto no va a funcionar porque el atributo id se compartiría entonces entre todas las subclases de IdNameMixin. En SQLAlchemy, cada clase debe tener su propia identificación (un objeto recién creado de Columna de clase). – max

+1

Normalmente estarías en lo cierto, pero mira mi respuesta actualizada. – dhaffey

+0

¡Ah, genial! Gracias. Ahora si solo pudiera hacer algo con '' __tablename__', que definitivamente tiene que ser único :) Pero me gusta su enfoque con la clase mixin mejor que la modificación de mi metaclase. – max

1

Creo que lo hice funcionar.

Creé una metaclase que se deriva de DeclarativeMeta, e hice esa metaclase de C1 y C2. En esa nueva metaclase, simplemente dije

def __new__(mcs, name, base, attr): 
    attr['__tablename__'] = name.lower() 
    attr['id'] = Column(Integer, primary_key = True) 
    attr['name'] = Column(String) 
    return super().__new__(mcs, name, base, attr) 

Y parece que funciona bien.

2

¿Podría también utilizar el método de copia de columna? De esta forma, los campos se pueden definir independientemente de las tablas, y los campos que se reutilizan son solo field.copy() - ed.

id = Column(Integer, primary_key = True) 
name = Column(String) 

class C1(declarative_base()): 
    id = id.copy() 
    name = name.copy() 
    #... 

class C2(declarative_base()): 
    id = id.copy() 
    name = name.copy() 
    #... 
+0

Alguien sabe cómo alterar las propiedades de esas columnas en diferentes clases de tabla, entonces? Es decir, si id no es primario en C1, pero es primario en C2, ¿cómo hace una distinción sin la repetición que estamos evitando? – jkmacc

Cuestiones relacionadas