Hi folks,

Django is missing a not_equal lookup type for database queries.  I know 
this has been requested before and that the usual response is to use exclude 
or ~Q.  While that works for a lot of use cases, I have a natural use case 
that I haven't seen discussed and that seems to escape easy implementation 
with the existing queryset implementation.  (I already posted to the 
django-users group and nobody was able to give a satisfactory answer.  If 
there is an easy answer, one using a single query, please let me know.)

Example: suppose we have the following models:

class Bundle(Model)
  items = ManyToManyField("Item")

class Item(Model)
  pass

(So one item can belong to many Bundles and one Bundle can have many Items.)

The query: I want to select all Bundles whose items are contained in an 
array special_items.  (Think of special_items as being relatively small and 
the set of all possible items as large.)  

Example: Suppose the database contains Items item1, item2, item3 (possibly 
among many other items) and that special_items = [item1, item2].  Suppose 
also the following Bundles exist in the database:
1. Bundle containing item1
2. Bundle containing item2
3. Bundle containing item1, item2
4. Bundle containing item2, item3
5. Bundle containing item1, item2, item3

So the query should return bundles 1, 2, 3 but exclude bundles 4, 5 because 
they contain item3, which is not a special item.

Queries that don't work:
- Bundle.exclude(items__in=special_items) which returns no bundles
- Bundle.filter(items__in=special_items) which returns bundles 1,2,3,4,5
- Bundle.exclude(~Q(items__in=special_items)) which returns 1,2,3,4,5

One work-around that does work is 
Bundle.exclude(items__in=not_special_items) where not_special_items contains 
all possible items that are not in special_items.  But clearly this is 
impractical/unusable if the set of possible items is infinite or very large.

On the other hand, if we had a not_equal (or even better, a not_in) 
operator, we could do the query as follows:
Bundle.exclude(items__not_in=special_items)
Bundle.filter(~Q(items__not_equal=special_items[0]) & 
~Q(items__not_equal=special_items[1]) & ...)
(The latter should be OK because in typical use cases special_items is a 
small set.)

Note: I did try to implement this as a custom lookup, but I guess because 
it's spanning a relationship you can't use the regular custom lookup API. 
If there is an easy way to add this as a custom lookup I'd appreciate some 
guidance.

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/24bfac80-c102-404a-9b91-c35059545742%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to