Commit c32c2ce3 by Alex Gaynor

Fix all the remaining bugs

parent 515106b7
...@@ -8,7 +8,7 @@ from django.db.models.query_utils import QueryWrapper ...@@ -8,7 +8,7 @@ from django.db.models.query_utils import QueryWrapper
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from taggit.forms import TagField from taggit.forms import TagField
from taggit.models import Tag, TaggedItem from taggit.models import Tag, TaggedItem, GenericTaggedItemBase
from taggit.utils import require_instance_manager from taggit.utils import require_instance_manager
...@@ -39,7 +39,7 @@ class TaggableRel(ManyToManyRel): ...@@ -39,7 +39,7 @@ class TaggableRel(ManyToManyRel):
class TaggableManager(object): class TaggableManager(object):
def __init__(self, verbose_name=_("Tags"), through=None): def __init__(self, verbose_name=_("Tags"), through=None):
self.use_gfk = through is None self.use_gfk = through is None or issubclass(through, GenericTaggedItemBase)
self.through = through or TaggedItem self.through = through or TaggedItem
self.rel = TaggableRel(to=self.through._meta.get_field("tag").rel.to) self.rel = TaggableRel(to=self.through._meta.get_field("tag").rel.to)
self.verbose_name = verbose_name self.verbose_name = verbose_name
...@@ -134,7 +134,7 @@ class _TaggableManager(models.Manager): ...@@ -134,7 +134,7 @@ class _TaggableManager(models.Manager):
def add(self, *tags): def add(self, *tags):
for tag in tags: for tag in tags:
if not isinstance(tag, Tag): if not isinstance(tag, Tag):
tag, _ = Tag.objects.get_or_create(name=tag) tag, _ = self.through.tag_model().objects.get_or_create(name=tag)
self.through.objects.get_or_create(tag=tag, **self._lookup_kwargs()) self.through.objects.get_or_create(tag=tag, **self._lookup_kwargs())
@require_instance_manager @require_instance_manager
......
...@@ -62,6 +62,10 @@ class ItemBase(models.Model): ...@@ -62,6 +62,10 @@ class ItemBase(models.Model):
abstract = True abstract = True
@classmethod @classmethod
def tag_model(cls):
return cls._meta.get_field_by_name("tag")[0].rel.to
@classmethod
def tag_relname(cls): def tag_relname(cls):
return cls._meta.get_field_by_name('tag')[0].rel.related_name return cls._meta.get_field_by_name('tag')[0].rel.related_name
...@@ -110,7 +114,7 @@ class GenericTaggedItemBase(ItemBase): ...@@ -110,7 +114,7 @@ class GenericTaggedItemBase(ItemBase):
class Meta: class Meta:
abstract=True abstract=True
@classmethod @classmethod
def lookup_kwargs(cls, instance): def lookup_kwargs(cls, instance):
return { return {
...@@ -121,14 +125,12 @@ class GenericTaggedItemBase(ItemBase): ...@@ -121,14 +125,12 @@ class GenericTaggedItemBase(ItemBase):
@classmethod @classmethod
def tags_for(cls, model, instance=None): def tags_for(cls, model, instance=None):
ct = ContentType.objects.get_for_model(model) ct = ContentType.objects.get_for_model(model)
kwargs = {
"%s__content_type" % cls.tag_relname(): ct
}
if instance is not None: if instance is not None:
return Tag.objects.filter(**{ kwargs["%s__object_id" % cls.tag_relname()] = instance.pk
'%s__object_id' % cls.tag_relname(): instance.pk, return cls.tag_model().objects.filter(**kwargs).distinct()
'%s__content_type' % cls.tag_relname(): ct
})
return Tag.objects.filter(**{
'%s__content_type' % cls.tag_relname(): ct
}).distinct()
class TaggedItem(GenericTaggedItemBase, TaggedItemBase): class TaggedItem(GenericTaggedItemBase, TaggedItemBase):
......
from django import forms from django import forms
from taggit.tests.models import Food, DirectFood, CustomPKFood from taggit.tests.models import Food, DirectFood, CustomPKFood, OfficialFood
class FoodForm(forms.ModelForm): class FoodForm(forms.ModelForm):
...@@ -14,3 +14,7 @@ class DirectFoodForm(forms.ModelForm): ...@@ -14,3 +14,7 @@ class DirectFoodForm(forms.ModelForm):
class CustomPKFoodForm(forms.ModelForm): class CustomPKFoodForm(forms.ModelForm):
class Meta: class Meta:
model = CustomPKFood model = CustomPKFood
class OfficialFoodForm(forms.ModelForm):
class Meta:
model = OfficialFood
...@@ -85,7 +85,7 @@ class OfficialThroughModel(GenericTaggedItemBase): ...@@ -85,7 +85,7 @@ class OfficialThroughModel(GenericTaggedItemBase):
tag = models.ForeignKey(OfficialTag, related_name="tagged_items") tag = models.ForeignKey(OfficialTag, related_name="tagged_items")
class OfficialFood(models.Model): class OfficialFood(models.Model):
name = models.CharField(max_length=50, primary_key=True) name = models.CharField(max_length=50)
tags = TaggableManager(through=OfficialThroughModel) tags = TaggableManager(through=OfficialThroughModel)
...@@ -93,13 +93,13 @@ class OfficialFood(models.Model): ...@@ -93,13 +93,13 @@ class OfficialFood(models.Model):
return self.name return self.name
class OfficialPet(models.Model): class OfficialPet(models.Model):
name = models.CharField(max_length=50, primary_key=True) name = models.CharField(max_length=50)
tags = TaggableManager(through=OfficialThroughModel) tags = TaggableManager(through=OfficialThroughModel)
def __unicode__(self): def __unicode__(self):
return self.name return self.name
class OfficialHousePet(CustomPKPet): class OfficialHousePet(OfficialPet):
trained = models.BooleanField() trained = models.BooleanField()
...@@ -3,11 +3,12 @@ from unittest import TestCase as UnitTestCase ...@@ -3,11 +3,12 @@ from unittest import TestCase as UnitTestCase
from django.test import TestCase, TransactionTestCase from django.test import TestCase, TransactionTestCase
from taggit.models import Tag, TaggedItem from taggit.models import Tag, TaggedItem
from taggit.tests.forms import FoodForm, DirectFoodForm, CustomPKFoodForm from taggit.tests.forms import (FoodForm, DirectFoodForm, CustomPKFoodForm,
OfficialFoodForm)
from taggit.tests.models import (Food, Pet, HousePet, DirectFood, DirectPet, from taggit.tests.models import (Food, Pet, HousePet, DirectFood, DirectPet,
DirectHousePet, TaggedPet, CustomPKFood, CustomPKPet, CustomPKHousePet, DirectHousePet, TaggedPet, CustomPKFood, CustomPKPet, CustomPKHousePet,
TaggedCustomPKPet, OfficialFood, OfficialPet, OfficialHousePet, TaggedCustomPKPet, OfficialFood, OfficialPet, OfficialHousePet,
OfficialThroughModel) OfficialThroughModel, OfficialTag)
from taggit.utils import parse_tags, edit_string_for_tags from taggit.utils import parse_tags, edit_string_for_tags
...@@ -45,6 +46,7 @@ class TaggableManagerTestCase(BaseTaggingTestCase): ...@@ -45,6 +46,7 @@ class TaggableManagerTestCase(BaseTaggingTestCase):
pet_model = Pet pet_model = Pet
housepet_model = HousePet housepet_model = HousePet
taggeditem_model = TaggedItem taggeditem_model = TaggedItem
tag_model = Tag
def test_add_tag(self): def test_add_tag(self):
apple = self.food_model.objects.create(name="apple") apple = self.food_model.objects.create(name="apple")
...@@ -73,7 +75,7 @@ class TaggableManagerTestCase(BaseTaggingTestCase): ...@@ -73,7 +75,7 @@ class TaggableManagerTestCase(BaseTaggingTestCase):
apple.tags.remove('green') apple.tags.remove('green')
self.assert_tags_equal(apple.tags.all(), ['red']) self.assert_tags_equal(apple.tags.all(), ['red'])
self.assert_tags_equal(self.food_model.tags.all(), ['green', 'red']) self.assert_tags_equal(self.food_model.tags.all(), ['green', 'red'])
tag = Tag.objects.create(name="delicious") tag = self.tag_model.objects.create(name="delicious")
apple.tags.add(tag) apple.tags.add(tag)
self.assert_tags_equal(apple.tags.all(), ["red", "delicious"]) self.assert_tags_equal(apple.tags.all(), ["red", "delicious"])
...@@ -128,12 +130,12 @@ class TaggableManagerTestCase(BaseTaggingTestCase): ...@@ -128,12 +130,12 @@ class TaggableManagerTestCase(BaseTaggingTestCase):
[apple] [apple]
) )
tag = Tag.objects.get(name="woof") tag = self.tag_model.objects.get(name="woof")
self.assertEqual(list(self.pet_model.objects.filter(tags__name__in=[tag])), [dog]) self.assertEqual(list(self.pet_model.objects.filter(tags__name__in=[tag])), [dog])
cat = self.housepet_model.objects.create(name="cat", trained=True) cat = self.housepet_model.objects.create(name="cat", trained=True)
cat.tags.add("fuzzy") cat.tags.add("fuzzy")
self.assertEqual( self.assertEqual(
map(lambda o: o.pk, self.pet_model.objects.filter(tags__name__in=["fuzzy"])), map(lambda o: o.pk, self.pet_model.objects.filter(tags__name__in=["fuzzy"])),
[kitty.pk, cat.pk] [kitty.pk, cat.pk]
...@@ -219,6 +221,7 @@ class TaggableManagerOfficialTestCase(TaggableManagerTestCase): ...@@ -219,6 +221,7 @@ class TaggableManagerOfficialTestCase(TaggableManagerTestCase):
pet_model = OfficialPet pet_model = OfficialPet
housepet_model = OfficialHousePet housepet_model = OfficialHousePet
taggeditem_model = OfficialThroughModel taggeditem_model = OfficialThroughModel
tag_model = OfficialTag
class TaggableFormTestCase(BaseTaggingTestCase): class TaggableFormTestCase(BaseTaggingTestCase):
...@@ -260,6 +263,10 @@ class TaggableFormCustomPKTestCase(TaggableFormTestCase): ...@@ -260,6 +263,10 @@ class TaggableFormCustomPKTestCase(TaggableFormTestCase):
form_class = CustomPKFoodForm form_class = CustomPKFoodForm
food_model = CustomPKFood food_model = CustomPKFood
class TaggableFormOfficialTestCase(TaggableFormTestCase):
form_class = OfficialFoodForm
food_model = OfficialFood
class TagStringParseTestCase(UnitTestCase): class TagStringParseTestCase(UnitTestCase):
""" """
......
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