Nikita Vlasenko
Nikita Vlasenko

Reputation: 4352

Get models in Django that have all of the values in ManyToMany field (AND-query, no reverse lookups allowed)

I have such a model in Django:

class VariantTag(models.Model):
    saved_variants = models.ManyToManyField('SavedVariant')

I need to get all VariantTag models that have saved_variants ManyToMany field with exact ids, say (250, 251), no more, no less. By the nature of the code that I am dealing with there is no way I can do reverse lookup with _set. So, I am looking for a query (or several queries + additional python code filtering) that will get me there but in such a way:

query = Q(...)
tag_queryset = VariantTag.objects.filter(query)

How is it possible to achieve?

I should probably stress out: supplied saved variants (e.g. (250, 251) should be AND - ed, not OR - ed.

Upvotes: 0

Views: 49

Answers (2)

Nikita Vlasenko
Nikita Vlasenko

Reputation: 4352

So far I was able to achieve AND result by the following code:

tag_ids = VariantTag.objects.filter(variant_tag_type__name=tag_data['tag'],
                                        saved_variants__in=saved_variant_ids).values_list('id', flat=True).distinct()
for tag_id in tag_ids:
    saved_variants = list(VariantTag.objects.get(id=tag_id).saved_variants.all().values_list('id', flat=True))
    if all(s in saved_variant_ids for s in saved_variants) and len(saved_variants) == len(saved_variant_ids):
        return VariantTag.objects.get(id=tag_id)

So, I am doing the following:

  1. Getting the OR - result
  2. Iterating over the resulting ids of the retrieved model and for each one of them getting all of the ids of the ManyToMany field
  3. Checking if all of the obtained ids of the ManyToMany field are in the required ids list (saved_variant_ids)
  4. If yes - get the model by the id: VariantTag.objects.get(id=tag_id)

In my case there will be only one such model that have the required ids in ManyToMany field. If it is not the case for you - just append the ids of the model (in my case tag_id) to a list - then make a query for all of them.

If anyone has more concise way of doing AND ManyToMany query + code, would be interesting to see.

Upvotes: 0

JPG
JPG

Reputation: 88569

Use in lookup

tag_queryset = VariantTag.objects.filter(saved_variants__in=[250,251])

Upvotes: 2

Related Questions