2015-10-02 9 views
7

Ho bisogno di avere un post associato a due utenti. L'autore e il moderatore. Sto cercando senza successo di questo codiceUn oggetto due chiavi esterne per la stessa tabella

class User(UserMixin, db.Model): 
    __tablename__ = 'users' 
    id = db.Column(db.Integer, primary_key=True) 
    ... 
    post = db.relationship('Post', foreign_keys=['posts.id'], backref='post_user', lazy='dynamic') 
    post_blame = db.relationship('Post', foreign_keys=['posts.moderated_by'], backref='post_blame', lazy='dynamic')  

class Post(db.Model): 
    __tablename__ = 'posts' 
    id = db.Column(db.Integer, primary_key=True) 
    ... 
    author_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) 
    moderated_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) 

Errore:

ArgumentError: Column-based expression object expected for argument 'foreign_keys'; got: 'posts.id', type <type 's 
+1

si prega di inviare la piena traceback errore. –

+2

Risolto basato su questa discussione https://www.reddit.com/r/flask/comments/2o4ejl/af_flask_sqlalchemy_two_foreign_keys_referencing/ – anvd

risposta

11

Uno dei problemi qui è che si sta tentando di utilizzare colonne della tabella nel rapporto foreign_keys, piuttosto che gli attributi di classe.

Cioè, invece di utilizzare posts.id, si dovrebbe usare Post.id. (In effetti, per fare riferimento a una colonna della tabella, è necessario utilizzare posts.c.id).

Quindi, è possibile che il codice originale funzionerà se si corregge a:

class User(UserMixin, db.Model): 
    __tablename__ = 'users' 
    id = db.Column(db.Integer, primary_key=True) 
    ... 
    post = db.relationship('Post', foreign_keys='Post.id', backref='post_user', lazy='dynamic') 
    post_blame = db.relationship('Post', foreign_keys='Post.moderated_by', backref='post_blame', lazy='dynamic')  

Se così non fosse, ci poi diverse altre opzioni. Innanzitutto, è possibile stabilire queste relazioni nella classe Post, dove è meno ambiguo per sqlalchemy trovare la relazione di chiave esterna. Qualcosa di simile

class Post(db.Model): 
    __tablename__ = 'posts' 
    id = db.Column(db.Integer, primary_key=True) 
    ... 
    author_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) 
    moderated_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) 
    post_user = db.relationship(User, foreign_keys=author_id, backref='post', lazy='dynamic') 
    post_blame = db.relationship(User, foreign_keys=moderated_by, backref='post_blame', lazy='dynamic')  

nota in questa versione, non abbiamo bisogno per passare il valore foreign_keys come una stringa, possiamo solo fare riferimento direttamente alla colonna di portata.

In alternativa, se si desidera stabilire questi rapporti all'interno utente, potrebbe essere è necessario dare sqlalchemy ulteriori informazioni, utilizzando primaryjoin ... forse qualcosa come:

class User(UserMixin, db.Model): 
    __tablename__ = 'users' 
    id = db.Column(db.Integer, primary_key=True) 
    ... 
    post = db.relationship('Post', primaryjoin='User.id == Post.id', backref='post_user', lazy='dynamic') 
    post_blame = db.relationship('Post', foreign_keys='User.id == Post.moderated_by', backref='post_blame', lazy='dynamic')  
+1

primo esempio, stesso tipo di errore che sto ottenendo (oggetto espressione basato su colonna previsto per argomento 'foreign_keys'). secondo esempio di relazione() ha ottenuto un argomento di parole chiave inattese 'primary_join' – anvd

+2

@anvd primary_join avrebbe dovuto essere un join primario. Ho anche notato che stavi usando i nomi delle tabelle, non i nomi delle classi nei tuoi "foreign_keys" e ho modificato la mia risposta di conseguenza. Fammi sapere come va! – donkopotamus

+3

Non mi interessa davvero la tua taglia, inoltre non mi interessa particolarmente provare a replicare completamente la tua tabella e la struttura del database per aiutarti in un problema ragionevolmente semplice. Sto solo cercando di fornire dei puntatori ... sai, sospetto che tu possa essere ** capace di fare cose come cercare la documentazione **. Ad esempio, una semplice occhiata alla relazione API ti avrebbe detto che "primary_join" doveva essere "primaryjoin" ... – donkopotamus