2016-12-27 4 views
0

Lasst uns sagen, dass wir mehrere sqlalchemy Modelle für Kataloge haben:Automatisieren sqlalchemy deklarative Modellerstellung

from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy import Column, Integer 
from sqlalchemy.orm import relationship 
Base = declarative_base() 

class Plane(Base): 
    __tablename__ = 'Plane' 
    plane_id = Column(Integer, primary_key=True) 

class Car(Base): 
    __tablename__ = 'Car' 
    car_id = Column(Integer, primary_key=True) 

Jetzt für den Import/Export-Zwecke wollen wir diese externen IDs beziehen. Also für Plane würden wir schreiben:

class PlaneID(Base): 
    issuer = Column(String(32), primary_key=True) 
    external_id = Column(String(16), primary_key=True) 

    plane_id = Column(Integer, ForeignKey(Plane.plane_id)) 
    plane = relationship(Plane, backref='external_ids') 

A CarID Modell in genau der gleichen Art und Weise definiert werden würde.

Welche Möglichkeiten gibt es, diesen Prozess zu automatisieren?

Vielleicht könnten wir eine Mixin, Fabrik, Dekorateur oder Meta-Klasse verwenden. Wie würden wir dann die dynamisch benannten Spalten erzeugen? Es wäre gut, wenn Sie den generierten Modellen bei Bedarf weitere Spalten hinzufügen könnten. Zum Beispiel:

class CarID(ExternalID): 
    valid_from = Column(Date) 

Antwort

1

können Sie DeclarativeMeta Unterklasse - die Metaklasse in declarative_base Funktion:

from sqlalchemy.ext.declarative import DeclarativeMeta, declarative_base 
from sqlalchemy import Column, Integer, String, ForeignKey 
from sqlalchemy.orm import relationship 

class ExternalObject(DeclarativeMeta): 
    def __new__(mcs, name, bases, attributes): 
     if 'issuer' not in attributes: 
      attributes['issuer'] = Column(String(32), primary_key=True) 
     if 'external_id' not in attributes: 
      attributes['external_id'] = Column(String(16), primary_key=True) 
     if name[-2:] == 'ID': 
      ext_cls_name = name[:-2] 
      attr_rel = ext_cls_name.lower() 
      attr_id = '%s_id' % attr_rel 
      if attr_rel in attributes or attr_id in attributes: 
       # Some code here in case 'car' or 'car_id' attribute is defined in new class 
       pass 
      attributes[attr_id] = Column(Integer, ForeignKey('%s.%s' % (ext_cls_name, attr_id))) 
      attributes[attr_rel] = relationship(ext_cls_name, backref='external_ids') 
     new_cls = super().__new__(mcs, name, bases, attributes) 
     return new_cls 

ExternalID = declarative_base(metaclass=ExternalObject) 

Danach können Sie Unterklasse von ExternalID und fügen Sie eine weitere Attribute wie Sie haben für CarID erstellen können.

+0

Also müsste ich dann alle meine Modelle auf 'ExternalID' basieren, oder? – bodo

+0

@canaaerus Ja, das ist richtig. –

Verwandte Themen