Djangoフィルター多対多を含む


90

多対多の関係で多数のオブジェクトをフィルタリングしようとしています。trigger_rolesフィールドに複数のエントリが含まれている可能性があるため、containsフィルタを試しました。しかし、それは文字列で使用するように設計されているので、この関係をどのようにフィルタリングするかはほとんど無力です(values_list()atmは無視できます)。

この関数は、ユーザープロファイルに添付されています。

def getVisiblePackages(self):
    visiblePackages = {}   
    for product in self.products.all():
        moduleDict = {}
        for module in product.module_set.all():
            pkgList = []
            involvedStatus = module.workflow_set.filter(trigger_roles__contains=self.role.id,allowed=True).values_list('current_state', flat=True)

私のワークフローモデルは次のようになります(簡略化):

class Workflow(models.Model):
    module = models.ForeignKey(Module)
    current_state = models.ForeignKey(Status)
    next_state = models.ForeignKey(Status)
    allowed = models.BooleanField(default=False)
    involved_roles = models.ManyToManyField(Role, blank=True, null=True)
    trigger_roles = models.ManyToManyField(Role, blank=True, null=True)

解決策は静かで単純かもしれませんが、私の脳は私に教えてくれません。

ご協力いただきありがとうございます。

回答:


110

次のようなことを試しましたか?

module.workflow_set.filter(trigger_roles__in=[self.role], allowed=True)

またはself.role.id、がpkのリストでない場合:

module.workflow_set.filter(trigger_roles__id__exact=self.role.id, allowed=True)

1
それはうまくいかないようです。self.role.idは1つのintであり、trigger_rolesはそれらのリストであるため、containsのように反転する必要がありますが、containsは文字列専用です。
Grave_Jumper 2010

8
2番目の例機能するはずです。の値がself.role.idトリガーロールの1つである場合、そのフィルターは、トリガーロールの1つがの値であるすべてのワークフローをプルする必要がありますself.role.id。基本的に、これは「含む」関数とまったく同じように動作します。私たち全員が何かを逃していない限り。
ジョーダンライター2010

@Jordan Reiter:「contains」はSQLで「like」に変換されますが、これはOPが望んでいるものではなく、彼はすでにこれを指摘していると思いますが、「exact」は「=」または「is」に変換されます。ここでのアイデア。
mouad 2010

@Grave_Jumper:ここ(djangoproject.com/documentation/models/many_to_many)を見てください。多対多フィールドで作業するときの例を見つけることができます。私の答えがそうでない場合は、これが役立つことを願っています:)
mouad 2010

1
aww ..申し訳ありませんが、2番目のソリューションは静かにうまく機能します:)私の側に少し設定ミスがありました。みんなありがとうこれは私の日を救った
;

19

これを実現するための最も簡単なアプローチは、のインスタンス全体(IDではなく)で等しいかどうかをチェックすることManyToManyFieldです。インスタンスが多対多の関係の中にあるかどうかがわかります。例:

module.workflow_set.filter(trigger_roles=self.role, allowed=True)

7

これは古い質問だと思いますが、OPは彼が探していた答えをまったく得られなかったようです。比較したいManyToManyFieldsのセットが2つある場合、トリックは__in、ではなく演算子を使用することcontainsです。したがって、たとえば、フィールドeventgroupsに多対多から「グループ」への「イベント」モデルがあり、ユーザーモデルが(明らかに)グループにアタッチされている場合、次のようにクエリを実行できます。

Event.objects.filter(eventgroups__in=u.groups.all())


4

最初の例では、特異点はほぼ正しいです。あなたはそれがリストであることを確認する必要があります。2番目の例では、をチェックtrigger_roles__id__exactする方が良い解決策です。

module.workflow_set.filter(trigger_roles__in=[self.role.id],allowed=True)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.