Rico
Rico

Reputation: 6042

Django filter __contains=queryset?

I'm using Django 1.4.3 w/ Python 2.7 on Ubuntu 13.04. I've run into a problem and can't seem to find a solution.

I have a series of related models (through FK) and I need to filter through them in a complex way.

Suppose I have a model Car that has Parts. I can get all the parts as car.parts_set. Each part has a M2M field excluded_price to Price, with related_name='excluded_prices'.

If I create a new part I need to add prices to the part's excluded_price where each price has excluded_parts for every other part related to that car. I'm trying to create a filter to help me find these prices.

Essentially I want something like this:

parts_set = [part for part in car.parts_set.exclude(pk=new_part.pk)]
Price.objects.filter(excluded_parts__contains=parts_set)

Effectively I want to find all prices where the excluded_parts is a super set of the specific car parts (excluding the new part, obviously).

I've found a nifty way to do this if the "parts_set" were a series of strings.

parts_set = [Q(excluded_parts__contains=part) for part in car.parts_set.exclude(pk=new_part.pk)]
Price.objects.filter(reduce(operator.and_, parts_set))

Unfortunately __contains only works for strings with an SQL statement of LIKE.

Are there any features in Django's ORM that support a __contains type filter that treats the value as an object rather than a string?

Upvotes: 1

Views: 5475

Answers (1)

Peter DeGlopper
Peter DeGlopper

Reputation: 37319

If I follow your question correctly, you can do this by iteratively building up constraints on the queryset:

parts_set = car.parts_set.exclude(pk=new_part.pk)
price_qs = Price.objects.all()
for part in parts_set:
    price_qs = price_qs.filter(excluded_parts=part)

This will require that the prices in the final queryset have all parts from the parts_set result in their excluded_parts field. They can have other parts as well. price_qs should end up returning your desired results:

all prices where the excluded_parts is a super set of the specific car parts

I don't know of a better way to construct a query requiring that a many-to-many field must contain multiple specific values.

Upvotes: 1

Related Questions