Django queryset get exact manytomany lookup [dupli

2019-01-08 23:38发布

问题:

This question already has an answer here:

  • How to do many-to-many Django query to find book with 2 given authors? 3 answers

I have a pk list of instances of Tag model, say

pk_list = [10, 6, 3]

I have another model with m2m field of tags and an instance that contains exactly 3 tags (of above pks).

class Node(models.Model):
    ...
    tags = models.ManyToManyField(Tag, related_name='nodes')

I'd like to retrieve a Node that contains exact set of tags as specified in my pk_list. When I do

Node.objects.filter(tags__in=pk_list)

it returns a list of three same instances

[<Node: My node title>, <Node: My node title>, <Node: My node title>]

Calling .get() doesn't work cause it have to return a single instance, obviously.

So, how do I retrieve a single instance? I must note that if my pk_list was different eg. [10, 6] or [10, 6, 3, 7] then I must receive nothing. I need an exact matching.

Thanks

回答1:

One approach is to use chain of filters:

node_query = Node.objects.all()
pk_list = [10, 6, 3]

for pk in pk_list:
    node_query = node_query.filter(tags=pk)

Now node_query will match node, that has at least three tags with pk 10, 6, 3. To exact matching of three tags:

UPDATE: Thanks to @janos and @Adrián López, the correct answer is:

from django.db.models import Count

pk_list = [10, 6, 3]
node_query = Node.objects.annotate(count=Count('tags')).filter(count=len(pk_list))

for pk in pk_list:
    node_query = node_query.filter(tags__pk=pk)