2010-09-02 3 views
11

Sto utilizzando SQLAlchemy e molte classi nel mio modello a oggetti hanno gli stessi due attributi: id e (numero intero & chiave primaria) e nome (una stringa). Sto cercando di evitare dichiarandoli in ogni classe in questo modo:SQLAlchemy: evitare la ripetizione nella definizione della classe di stile dichiarativa

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) 
    #... 

Che cosa è un buon modo per farlo? Ho provato ad usare le metaclassi ma non ha funzionato ancora.

risposta

9

Si potrebbe scomporre i tuoi attributi comuni in una mixin class, e moltiplicare ereditare fianco 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'] 

EDIT: Si potrebbe pensare che questo si tradurrebbe in C1 e C2 condividendo gli stessi Column oggetti, ma come indicato nella SQLAlchemy docs, oggetti colonna sono copiati quando proveniente da una classe intermedia. Ho aggiornato il codice di esempio per dimostrare questo comportamento.

+0

Purtroppo, questo non è andare a lavorare perché l'attributo id sarebbe poi essere condiviso tra tutti i sottoclassi di IdNameMixin. In SQLAlchemy, ogni classe deve avere il proprio id (un oggetto appena creato della colonna della classe). – max

+1

Normalmente si sarebbe corretto, ma vedere la mia risposta aggiornata. – dhaffey

+0

Ah molto bello !! Grazie. Ora, se solo potessi fare qualcosa per il '__tablename__', che sicuramente deve essere unico :) Ma mi piace il tuo approccio con la classe di mixin migliore della mia modifica al metaclass. – max

1

Penso che ho avuto di lavorare.

ho creato un metaclasse che deriva da DeclarativeMeta, e fatto si che la metaclasse di C1 e C2. In quel nuovo metaclass, ho semplicemente detto

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) 

E sembra funzionare bene.

2

Potrebbe anche utilizzare il metodo copia della colonna? In questo modo, i campi possono essere definiti in modo indipendente di tavoli, e quei campi che vengono riutilizzati sono 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

Qualcuno sa come modificare le proprietà di queste colonne in diverse classi di tabelle, quindi? Cioè, se id non è primario in C1, ma è primario in C2, come si fa a fare quella distinzione senza la ripetizione che stiamo evitando? – jkmacc

Problemi correlati