5

Sto utilizzando l'ereditarietà di tabelle concrete con SQLAlchemy. Nella classe del modello di stile declivo, l'ho configurato correttamente.SQLAlchemy Relazione polimerica con ereditarietà di calcestruzzo

Il mio codice, proprio come:

class Entry(AbstractConcreteBase, db.Model): 
    """Base Class of Entry.""" 

    id = db.Column(db.Integer, primary_key=True, nullable=False) 
    created = db.Column(db.DateTime, nullable=False) 
    post_id = declared_attr(lambda c: db.Column(db.ForeignKey("post.id"))) 
    post = declared_attr(lambda c: db.relationship("Post", lazy="joined")) 

    @declared_attr 
    def __tablename__(cls): 
     return cls.__name__.lower() 

    @declared_attr 
    def __mapper_args__(cls): 
     # configurate subclasses about concrete table inheritance 
     return {'polymorphic_identity': cls.__name__, 
       'concrete': True} if cls.__name__ != "Entry" else {} 

class TextEntry(Entry): 
    """Text and Article Entry.""" 

    text = db.deferred(db.Column(db.Text, nullable=False)) 

class PhotoEntry(Entry): 
    """Photo Entry.""" 

    path = db.deferred(db.Column(db.String(256), nullable=False)) 

Funziona bene durante il test nella shell:

>>> from models.entry import Entry 
>>> 
>>> Entry.query.all() 
[<PhotoEntry 'Title' created by tonyseek>, 
<PhotoEntry 'TITLE 2' created by tonyseek>, 
<PhotoEntry 'Title 3' created by tonyseek>, 
<PhotoEntry 'Title 4' created by tonyseek>, 
<TextEntry 'Title' created by tonyseek>] 

tanto cado in difficoltà durante l'impostazione del rapporto in altri modelli. Ogni voce ha una chiave esterna post_id per unire il modello Post, ma non è stato possibile definire il riferimento posteriore in Post. Che non può funzionare:

class Post(db.Model): 
    """An Post.""" 

    id = db.Column(db.Integer, primary_key=True, nullable=False) 
    description = db.Column(db.Unicode(140), nullable=False) 
    entries = db.relationship(Entry, lazy="dynamic") 

ha sollevato un'eccezione e detta:

InvalidRequestError: One or more mappers failed to initialize - can't proceed with initialization of other mappers. Original exception was: Class 'models.entry.Entry' is not mapped.

Evidente il Entry è una classe astratta, che non poteva essere mappato a un vero esistere tavolo. Il documento nel sito ufficiale ha un esempio ma la sua classe base non è astratta. Ora, come dovrei fare per impostare la relazione polimorfica con un modello astratto?

risposta

7

Ho trovato la ragione del problema e la sua soluzione.

In base al documento del sito Web ufficiale di sqlalchemy, la classe astratta potrebbe essere una classe mappata, poiché la funzione polymorphic_union potrebbe creare una tabella virtuale.

Sto usando il modello di stile declivo, non costruire il mappatore a mano, quindi la tabella virtuale pjoin non dovrebbe essere creata a mano. La classe base AbstractConcreteBase ha un metodo __delcare_last__ per creare la funzione pjoin con la funzione polymorphic_union, ma verrebbe chiamata durante l'attivazione dell'evento after_configured.

Il rapporto con Entry in Post sarebbe creata dopo la classe Post essere generata, in questo tempo l'evento after_configured non attivati, così __delcare_last__ funzione non hanno creato la tabella virtuale pjoin e mappati in Entry. Quindi l'eccezione "Class" models.entry.Entry "non è mappata." sarà sollevato.

Ora, io refactoring del modello di Post, lasciarlo creare la relazione con Entry in __delcare_last__ funzione, allora sarà successo a causa dell'evento attivato e il mappato Entry.

mia nuova classe implementata in questo modo:

class Post(db.Model): 
    """An Post.""" 

    id = db.Column(db.Integer, primary_key=True, nullable=False) 
    description = db.Column(db.Unicode(140), nullable=False) 

    @classmethod 
    def __declare_last__(cls): 
     cls.entries = db.relationship(Entry, viewonly=True) 

    def attach_entries(self, entries): 
     """Attach Entries To This Post. 

     Example: 
      >>> post = Post("An Interesting News", "Wow !!!") 
      >>> text_entry = TextEntry(*t_args) 
      >>> photo_entry = PhotoEntry(*p_args) 
      >>> post.attach_entries([text_entry, photo_entry]) 
      >>> len(post.entries) 
      2 
      >>> db.session.commit() 
      >>> 
     """ 
     for entry in entries: 
      self.entries.append(entry) 
      entry.post = self 
      db.session.add(entry) 
Problemi correlati