> Now I want to get all objects, which have set tag "food" *and* *have 
> not* set tag "cake".
> 
> This get all objects with tag="food" set (obj1..obj5):
> 
>    Obj.objects.filter(tags__in=[Tags.objects.filter(name='food')])
> 
> This get all objects, which haven't set tag "cake" (obj1..obj3, obj6..obj7):
> 
>    Obj.objects.exclude(tags__in=[Tags.objects.filter(name='cake')])
> 
> When I try to combine DB queries together, I don't get what I expect 
> (obj1..obj3, obj6):


Django's ORM doesn't handle this sort of thing very gracefully, 
so it requires dropping down to a little SQL with .extra() calls.

Something like

  Obj.objects.extra(where=["""
     app_model.id IN (
       SELECT model_id
       FROM app_tags
       WHERE name = ?
     )
     """, ['food']).extra(where["""
     app_model.id NOT IN (
       SELECT model_id
       FROM app_tags
       WHERE name = ?
     )
     """, ['cake'])

it's ugly and hackish, but when things scale up, this is the only 
way to get it to work (I've got several hundred thousand records 
in my app that does logic like this, so I need all the 
speed-boost I can get)

if your tagsets return small collections, you could use 
sets...something like

  food = set(t.obj_id for t in Tags.objects.filter(name='food'))
  cake = set(t.obj_id for t in Tags.objects.filter(name='cake'))
  Obj.objects.filter(id__in=food - cake)

(that last line might need to be "tuple(food-cake)")

but as noted, this doesn't scale well once "food" or "cake" tags 
thousands of things (or maybe even hundreds of things).

-tim





--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to