Commit e1bbfa6c by Alex Gaynor

Fixed #31. Corrected exclude(tags__in=['foo']).

parent 7568a6ae
...@@ -49,6 +49,7 @@ class TaggableManager(object): ...@@ -49,6 +49,7 @@ class TaggableManager(object):
self.db_column = None self.db_column = None
self.choices = None self.choices = None
self.serialize = False self.serialize = False
self.null = True
self.creation_counter = models.Field.creation_counter self.creation_counter = models.Field.creation_counter
models.Field.creation_counter += 1 models.Field.creation_counter += 1
...@@ -71,22 +72,33 @@ class TaggableManager(object): ...@@ -71,22 +72,33 @@ class TaggableManager(object):
getattr(instance, self.name).set(*value) getattr(instance, self.name).set(*value)
def get_prep_lookup(self, lookup_type, value): def get_prep_lookup(self, lookup_type, value):
if lookup_type != "in": if lookup_type not in ["in", "isnull"]:
raise ValueError("You can't do lookups other than \"in\" on Tags") # Users really shouldn't do "isnull" lookups, again: the ORM can,
if all(isinstance(v, Tag) for v in value): # you can't.
qs = self.through.objects.filter(tag__in=value) raise ValueError("You can't do lookups other than \"in\" on Tags: "
elif all(isinstance(v, basestring) for v in value): "__%s=%s" % (lookup_type, value))
qs = self.through.objects.filter(tag__name__in=value)
elif all(isinstance(v, (int, long)) for v in value): if hasattr(value, 'prepare'):
# This one is really ackward, just don't do it. The ORM does it return value.prepare()
# for deletes, but no one else gets to. if hasattr(value, '_prepare'):
return value return value._prepare()
else:
# Fucking flip-floppers. if lookup_type == "in":
raise ValueError("You can't combine Tag objects and strings. '%s' was provided." % value) if all(isinstance(v, Tag) for v in value):
value = self.through.objects.filter(tag__in=value)
elif all(isinstance(v, basestring) for v in value):
value = self.through.objects.filter(tag__name__in=value)
elif all(isinstance(v, (int, long)) for v in value):
# This one is really ackward, just don't do it. The ORM does
# it for deletes, but no one else gets to.
return value
else:
# Fucking flip-floppers.
raise ValueError("You can't combine Tag objects and strings. '%s' "
"was provided." % value)
if hasattr(models.Field, "get_prep_lookup"): if hasattr(models.Field, "get_prep_lookup"):
return models.Field().get_prep_lookup(lookup_type, qs) return models.Field().get_prep_lookup(lookup_type, value)
return models.Field().get_db_prep_lookup(lookup_type, qs) return models.Field().get_db_prep_lookup(lookup_type, value)
if django.VERSION < (1, 2): if django.VERSION < (1, 2):
get_db_prep_lookup = get_prep_lookup get_db_prep_lookup = get_prep_lookup
......
...@@ -137,6 +137,18 @@ class TaggableManagerTestCase(BaseTaggingTestCase): ...@@ -137,6 +137,18 @@ class TaggableManagerTestCase(BaseTaggingTestCase):
map(lambda o: o.pk, self.pet_model.objects.filter(tags__in=["fuzzy"])), map(lambda o: o.pk, self.pet_model.objects.filter(tags__in=["fuzzy"])),
[kitty.pk, cat.pk] [kitty.pk, cat.pk]
) )
def test_exclude(self):
apple = self.food_model.objects.create(name="apple")
apple.tags.add("red", "green", "delicious")
pear = self.food_model.objects.create(name="pear")
pear.tags.add("green", "delicious")
self.assertEqual(
map(lambda o: o.pk, self.food_model.objects.exclude(tags__in=["red"])),
[pear.pk],
)
def test_similarity_by_tag(self): def test_similarity_by_tag(self):
"""Test that pears are more similar to apples than watermelons""" """Test that pears are more similar to apples than watermelons"""
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment