2017-11-18 2 views
0

Wie ist es möglich, einem Modell, das dieses Mixin erbt, zusätzliche Indizes hinzuzufügen, wenn man es mit einem Index mischt? Mit einem Indexnamen wie idx__TABLENAME__COLUMN kann das Mixin nicht den TABLENAME für sich selbst erhalten. Wenn für das Mixin eine __tablename__ angegeben wird, treten doppelte Indexnamen auf.Vererben und Hinzufügen von Indizes von sqlalchemy mixins

Beispielcode folgt.

import sqlalchemy as sql 
from sqlalchemy import Column, Index, String, Integer 
from sqlalchemy.ext.declarative import declared_attr, declarative_base 


Base = declarative_base() 

class MixinOwner(object): 
    id = Column('id', Integer, primary_key=True) 
    owner = Column('owner', String) 

    @declared_attr 
    def __table_args__(cls): 
     return (Index('idx__%s__owner' % cls.__tablename__, 'owner'),) 


class Letter(MixinOwner, Base): 
    __tablename__ = 'letter' 
    a = Column('a', String) 
    b = Column('b', String) 

    @declared_attr 
    def __table_args__(cls): 
     mixin_indexes = list(MixinOwner.__table_args__) # <--- Error (MixinOwner does not have attribute __tablename__) 
     mixin_indexes.extend([ 
      Index('idx__letter__a', 'a'), 
      Index('idx__letter__b', 'b'), 
     ]) 
     return tuple(mixin_indexes) 


class Word(MixinOwner, Base): 
    __tablename__ = 'word' 
    apple = Column('apple', String) 
    banana = Column('banana', String) 

    @declared_attr 
    def __table_args__(cls): 
     mixin_indexes = list(MixinOwner.__table_args__) 
     mixin_indexes.extend([ 
      Index('idx__word__apple', 'apple'), 
      Index('idx__word__banana', 'banana'), 
     ]) 
     return tuple(mixin_indexes) 




engine = sqlalchemy.create_engine('sqlite:///:memory:') 
engine.connect() 

Base.metadata.bind = engine 
Base.metadata.create_all() 

Session = sqlalchemy.orm.sessionmaker(bind=engine) 
session = Session() 

Antwort

0

Um Indizes von Mixins Sie müssen integrieren super verwenden, um die Methoden der Basisklassen im Rahmen der Unterklasse zugreifen. Zusätzlich zu diesem Fix, der die ursprüngliche Frage, die ich gestellt habe, löst, gibt es eine andere Frage - wie man Indizes von mehreren Mixins nicht nur einem einbaut (wie es in der ursprünglichen Frage eingerichtet wurde). Der folgende Code erläutert dieses größere Problem ebenfalls. Die Lösung besteht darin, über die MRO zu iterieren und die __table_args__ für jede Basisklasse mit dem Kontext des Modells zu erfassen.

import sqlalchemy as sql 
from sqlalchemy import Column, Index, String, Integer, Date 
from sqlalchemy.ext.declarative import declared_attr, declarative_base 


Base = declarative_base() 

class MixinOwner(object): 
    id = Column('id', Integer, primary_key=True) 
    owner = Column('owner', String) 

    @declared_attr 
    def __table_args__(cls): 
     return (Index('idx__%s__owner' % cls.__tablename__, 'owner'),) 

class MixinDate(object): 
    date = Column('date', Date) 

    @declared_attr 
    def __table_args__(cls): 
     return (Index('idx__%s__date' % cls.__tablename__, 'date'),) 



# single mixin inheritance (original question) -- use super(cls, cls) 
class Word(MixinOwner, Base): 
    __tablename__ = 'word' 
    apple = Column('apple', String) 
    banana = Column('banana', String) 

    @declared_attr 
    def __table_args__(cls): 
     mixin_indexes = list((super(cls, cls).__table_args__)) 
     mixin_indexes.extend([ 
      Index('idx__word__apple', 'apple'), 
      Index('idx__word__banana', 'banana'), 
     ]) 
     return tuple(mixin_indexes) 


# multiple mixin iheritance (not in original question) 
# iterate through __mro__ and aggregate __table_args__ from each base 
class Letter(MixinOwner, MixinDate, Base): 
    __tablename__ = 'letter' 
    a = Column('a', String) 
    b = Column('b', String) 

    @declared_attr 
    def __table_args__(cls): 
     mixin_indexes = [] 
     for base_class in cls.__mro__: 
      try: 
       mixin_indexes.extend(super(base_class, cls).__table_args__) 
      except AttributeError: 
       pass 
     mixin_indexes.extend([ 
      Index('idx__letter__a', 'a'), 
      Index('idx__letter__b', 'b'), 
     ]) 
     return tuple(mixin_indexes) 




engine = sql.create_engine('sqlite:///:memory:') 
engine.connect() 

Base.metadata.bind = engine 
Base.metadata.create_all() 

Session = sql.orm.sessionmaker(bind=engine) 
session = Session() 
Verwandte Themen