2017-08-12 1 views
1

Queryset of Project.objects.all()を使用し、ユーザが選択した属性のリストを含むすべてのプロジェクトをフィルタリングしたいと考えています。Django QuerysetフィルタリングでManytomanyをフィルタリングする

class Attribute(models.Model): 
    title = models.CharField(max_length=20) 

class Project(models.Model): 
    title = models.CharField(max_length=30) 
    attributes = models.ManyToManyField(Attribute) 

## For the sake of this example, there are two Projects and two Attributes 
## Project1 is associated to attr1 and attr2 
## Project2 is associated to attr1 

models.py私は、この発見:Django Docs Complex Lookups with Q objectsをし、他のstackoverflowの答えによって、ここに着い:(self.multiselectは、PKSのリストである)

非稼働コード

query = reduce(operator.and_, (Q(attributes__pk=selection) for selection in self.multiselect)) 
return queryset.filter(query) 

ただし、このコードは空のクエリセットを提供します。インタラクティブシェルでいくつかのテストを行い、何がうまくいかないかを調べ始めました。 &プロジェクトと属性間の多対多の関係で動作していないように思え

テスト

queryset = Project.objects.all() 

########## & is not working 
queryset.filter(Q(attributes__pk=1) & Q(attributes__pk=2)) 
# [] 

########## | has no issues 
queryset.filter(Q(attributes__pk=1) | Q(attributes__pk=2)) 
# [<Project: Project1>, <Project: Project2>, <Project: Project1>] 

########## & works on Project but not on Attribute 
queryset.filter(Q(title__contains="Project") & Q(title__contains="1")) 
# [<Project: Project1>] 

。これには理由がありますか、それが正しく動作するようにするコードには簡単な修正がありますか?どんな助けもありがとう。サイドノートとして


、reduce関数は、私がなぜfilterQ&作品を理解していない、まさにそれが必要

########## Reduce does not create an issue 
Q(attributes__pk=1) & Q(attributes__pk=2) 
# <Q: (AND: ('attributes__pk', 1), ('attributes__pk', 2))> 
reduce(operator.and_, [Q(attributes__pk=selection) for selection in [1,2]]) 
# <Q: (AND: ('attributes__pk', 1), ('attributes__pk', 2))> 

答えて

0

戻っています。私は否定を否定することを考えました。それが私にこの解決策をもたらしました。

Project.objects.exclude(~(Q(attributes__pk=1) & Q(attributes__pk=2))) 

除外使うとQ&働いていたとの元のクエリフィルタを否定。

+0

いや:

attrs = Attribute.objects.filter(pk__in=self.multiselect) Photo.objects.filter(attributes__in=attrs).annotate(num_attr=Count('attributes')).filter(num_attr=len(attrs)) 

はこれを参照してください。私はこれの背後にある数学を理解しようとしていますが、望ましい出力が得られるようです。ありがとうございます<3編集:否定によって私の望む出力以外のすべてが得られるので、 'filter'、 'Q'、 '&'のバグがなければならないと思います。望ましい結果。ニースキャッチ^^ – pieisawesome102

+0

あなたを助けてうれしいです。 –

1

あなたが言うように:

########## & is not working 
queryset.filter(Q(attributes__pk=1) & Q(attributes__pk=2)) 

それは次のようになります。Django filter queryset __in for *every* item in list

+0

attributes__inを使用すると、選択された属性のうち__all__を持つプロジェクトではなく、選択された属性の__any__を持つすべてのプロジェクトのリストが表示されます – pieisawesome102

+0

@ pieisawesome102 '' 'annotate(num_attr = Count( 'attributes' ) ''これは、すべての属性が選択されていることを確認します。 – gushitong

関連する問題