2010-05-29 5 views
4

J'ai une mise en page wiki db avec Page et Revisions. Chaque Révision a un page_id référençant la Page, une relation page à la page référencée; chaque page a une relation all_revisions avec toutes ses révisions. Jusqu'ici si commun.SQLAlchemy - relation limitée sur plus que la clé étrangère

Mais je veux implémenter différentes époques pour les pages: Si une page a été supprimée et est recréée, les nouvelles révisions ont un nouveau epoch. Pour aider à trouver les révisions correctes, chaque page a un champ current_epoch. Maintenant, je veux fournir une relation revisions sur la page qui contient seulement ses révisions, mais seulement celles où les époques correspondent.

C'est ce que j'ai essayé:

revisions = relationship('Revision', 
    primaryjoin = and_(
     'Page.id == Revision.page_id', 
     'Page.current_epoch == Revision.epoch', 
    ), 
    foreign_keys=['Page.id', 'Page.current_epoch'] 
) 

Full code (vous pouvez exécuter qu'il en est)

Cependant cela soulève toujours ArgumentError: Impossible de déterminer le sens de la relation pour la condition primaryjoin .. ", j'ai essayé tout ce que je venais à l'esprit, cela n'a pas fonctionné.

Qu'est-ce que je fais mal? Est-ce une mauvaise approche pour faire cela, comment cela pourrait-il être fait autrement qu'avec une relation?

Répondre

4

Essayez d'installer relation après les deux classes sont créées:

Page.revisions = relationship(
    'Revision', 
    primaryjoin = (Page.id==Revision.page_id) & \ 
        (Page.current_epoch==Revision.epoch), 
    foreign_keys=[Page.id, Page.current_epoch], 
    uselist=True, 
) 

BTW, votre test est incorrect: revisions charges de propriété des données de base de données alors que vous ne les avez pas ajouté à la session.

Mise à jour: Le problème dans votre code est que le paramètre primaryjoin n'est pas chaîne, donc it's not evaluated. L'utilisation de la chaîne dans primaryjoin fonctionne très bien:

class Page(Base): 
    # [skipped] 
    revisions = relationship(
     'Revision', 
     primaryjoin = '(Page.id==Revision.page_id) & '\ 
         '(Page.current_epoch==Revision.epoch)', 
     foreign_keys=[id, current_epoch], 
     uselist=True, 
    ) 
+0

Merci! C'est ce qu'il a fait. Je n'ai pas tout à travailler dans la vraie application, mais cela fonctionne dans la petite démo, donc au moins ce problème spécifique est résolu maintenant. @BTW: Ah, j'ai oublié ça parce que nous avons une méthode init spéciale qui fait l'ajout automatiquement. [Mise à jour, code de travail] (http://paste.pocoo.org/show/220827/). – Marian

+0

Une idée de pourquoi l'ajouter après cela corrige cela? Je pensais que la notation de chaîne est destinée à éviter de telles choses? (Et, quand évalue-t-il ces chaînes si ce n'est après que les deux classes aient été créées?) – Marian

+1

J'ai ajouté une explication et un exemple avec l'expression appropriée dans la chaîne. –

Questions connexes