2008-11-06 9 views
8

J'utilise SQLAlchemy 0.5rc, et je voudrais ajouter un filtre automatique à une relation, de sorte que chaque fois qu'il essaye d'aller chercher des enregistrements pour cette relation, il ignore les "distants" s'ils sont marqués comme "logically_deleted" (un champ booléen de la table enfant)Comment ajouter un filtre automatique à une relation avec SQLAlchemy?

Par exemple, si un objet "parent" a une relation "enfants" qui a 3 enregistrements, mais l'un d'entre eux est supprimé logiquement, lorsque je demande " Parent "Je voudrais SQLA à chercher l'objet parent avec seulement deux enfants ..
Comment dois-je faire? En ajoutant une condition "et" au paramètre primaire de la relation? (Par exemple, « Children.parent_id == Parent.id and Children.logically_deleted == False », mais est-il correct d'écrire « et » de cette façon?)

Edit:
J'ai réussi à le faire de cette façon

children = relation("Children", primaryjoin=and_(id == Children.parent_id, Children.logically_deleted==False)) 

, mais est-il un moyen utiliser une chaîne comme primaryjoin à la place?

Répondre

3

La fonction et_() est la bonne façon de faire des conjonctions logiques dans SQLAlchemy, en même temps que l'opérateur &, mais soyez prudent avec ce dernier car il a des règles de précédence surprenantes, c'est-à-dire une plus grande priorité que les opérateurs de comparaison.

Vous pouvez également utiliser une chaîne en tant que jointure primaire avec le constructeur text(), mais cela provoquera une rupture de code avec tout alias de table fourni avec eagerloading et jointures.

Pour la suppression logique, il pourrait être préférable de cartographier toute la classe sur une sélection qui ne tient pas compte des valeurs supprimées:

mapper(Something, select([sometable], sometable.c.deleted == False)) 
+0

Est-ce que cela peut être traduit en utilisant __mapper_args__? Je veux dire que j'utilise déclaratif. – Marconi

+0

J'ai essayé de l'utiliser dans mapper_args, mais je reçois un message d'erreur disant "mapper() a plusieurs valeurs pour l'argument mot clé 'local_table'". Donc j'ai peur que ce soit inutile. –

0

Je ne développe actuellement agains 0.4.something, mais voici comment je vous suggère qu'il:

db.query(Object).filter(Object.first==value).filter(Object.second==False).all() 

Je pense que c'est ce que vous essayez de faire, non?

(Note: écrit dans un navigateur web, pas de code réel!)

+0

Non, je cherchais quelque chose d'automatique .. Je vais clarifier la question :) Merci! – Joril

+0

Pas de soucis. Je pense que je comprends ce que vous essayez de faire, mais surtout lire le code que vous avez fourni! –

6

mais est-il un moyen d'utiliser une chaîne comme primaryjoin à la place?

Vous pouvez utiliser les éléments suivants:

children = relationship("Children", primaryjoin="and_(Parent.id==Children.parent_id, Children.logically_deleted==False)" 

Cela a fonctionné pour moi!

Questions connexes