Commit 543471cd by Alex Gaynor

Merge remote branch 'origin/master'

parents 377bb478 18566407
......@@ -12,7 +12,7 @@ class TagWidget(forms.TextInput):
class TagField(forms.CharField):
widget = TagWidget
def clean(self, value):
try:
return parse_tags(value)
......
from django.contrib.contenttypes.generic import GenericRelation
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.db.models.fields.related import ManyToManyRel
from django.db.models.fields.related import ManyToManyRel, RelatedField
from django.db.models.related import RelatedObject
from django.utils.translation import ugettext_lazy as _
from taggit.forms import TagField
from taggit.models import Tag, TaggedItem, GenericTaggedItemBase
from taggit.models import TaggedItem, GenericTaggedItemBase
from taggit.utils import require_instance_manager
......@@ -35,7 +35,7 @@ class TaggableRel(ManyToManyRel):
self.through = None
class TaggableManager(object):
class TaggableManager(RelatedField):
def __init__(self, verbose_name=_("Tags"), through=None):
self.use_gfk = through is None or issubclass(through, GenericTaggedItemBase)
self.through = through or TaggedItem
......@@ -71,12 +71,6 @@ class TaggableManager(object):
def save_form_data(self, instance, value):
getattr(instance, self.name).set(*value)
def get_prep_lookup(self, lookup_type, value):
return models.Field().get_prep_lookup(lookup_type, value)
def get_db_prep_lookup(self, *args, **kwargs):
return models.Field().get_db_prep_lookup(*args, **kwargs)
def formfield(self, form_class=TagField, **kwargs):
defaults = {
......@@ -121,13 +115,13 @@ class TaggableManager(object):
class _TaggableManager(models.Manager):
def __init__(self, through):
self.through = through
def get_query_set(self):
return self.through.tags_for(self.model, self.instance)
def _lookup_kwargs(self):
return self.through.lookup_kwargs(self.instance)
@require_instance_manager
def add(self, *tags):
for tag in tags:
......@@ -163,7 +157,7 @@ class _TaggableManager(models.Manager):
qs = qs.exclude(**lookup_kwargs)
qs = qs.filter(tag__in=self.all())
qs = qs.order_by('-n')
# TODO: This all feels like a bit of a hack.
items = {}
if len(lookup_keys) == 1:
......
......@@ -9,13 +9,13 @@ from django.utils.translation import ugettext_lazy as _, ugettext
class TagBase(models.Model):
name = models.CharField(verbose_name=_('Name'), max_length=100)
slug = models.SlugField(verbose_name=_('Slug'), unique=True, max_length=100)
def __unicode__(self):
return self.name
class Meta:
abstract = True
def save(self, *args, **kwargs):
if not self.pk and not self.slug:
self.slug = slug = slugify(self.name)
......@@ -57,7 +57,7 @@ class ItemBase(models.Model):
"object": self.content_object,
"tag": self.tag
}
class Meta:
abstract = True
......@@ -81,7 +81,7 @@ class TaggedItemBase(ItemBase):
tag = models.ForeignKey(Tag, related_name="%(class)s_items")
else:
tag = models.ForeignKey(Tag, related_name="%(app_label)s_%(class)s_items")
class Meta:
abstract = True
......@@ -114,7 +114,7 @@ class GenericTaggedItemBase(ItemBase):
class Meta:
abstract=True
@classmethod
def lookup_kwargs(cls, instance):
return {
......
......@@ -6,17 +6,17 @@ from taggit.models import TaggedItemBase, GenericTaggedItemBase, TagBase
class Food(models.Model):
name = models.CharField(max_length=50)
tags = TaggableManager()
def __unicode__(self):
return self.name
class Pet(models.Model):
name = models.CharField(max_length=50)
tags = TaggableManager()
def __unicode__(self):
return self.name
......@@ -41,7 +41,7 @@ class DirectPet(models.Model):
name = models.CharField(max_length=50)
tags = TaggableManager(through=TaggedPet)
def __unicode__(self):
return self.name
......@@ -61,7 +61,7 @@ class CustomPKFood(models.Model):
name = models.CharField(max_length=50, primary_key=True)
tags = TaggableManager(through=TaggedCustomPKFood)
def __unicode__(self):
return self.name
......@@ -69,7 +69,7 @@ class CustomPKPet(models.Model):
name = models.CharField(max_length=50, primary_key=True)
tags = TaggableManager(through=TaggedCustomPKPet)
def __unicode__(self):
return self.name
......@@ -88,7 +88,7 @@ class OfficialFood(models.Model):
name = models.CharField(max_length=50)
tags = TaggableManager(through=OfficialThroughModel)
def __unicode__(self):
return self.name
......@@ -96,7 +96,7 @@ class OfficialPet(models.Model):
name = models.CharField(max_length=50)
tags = TaggableManager(through=OfficialThroughModel)
def __unicode__(self):
return self.name
......
......@@ -7,7 +7,7 @@ from taggit.tests.forms import (FoodForm, DirectFoodForm, CustomPKFoodForm,
OfficialFoodForm)
from taggit.tests.models import (Food, Pet, HousePet, DirectFood, DirectPet,
DirectHousePet, TaggedPet, CustomPKFood, CustomPKPet, CustomPKHousePet,
TaggedCustomPKPet, OfficialFood, OfficialPet, OfficialHousePet,
TaggedCustomPKPet, OfficialFood, OfficialPet, OfficialHousePet,
OfficialThroughModel, OfficialTag)
from taggit.utils import parse_tags, edit_string_for_tags
......@@ -34,11 +34,11 @@ class TagModelTestCase(BaseTaggingTransactionTestCase):
def test_unique_slug(self):
apple = self.food_model.objects.create(name="apple")
apple.tags.add("Red", "red")
def test_update(self):
special = self.tag_model.objects.create(name="special")
special.save()
def test_add(self):
apple = self.food_model.objects.create(name="apple")
yummy = self.tag_model.objects.create(name="yummy")
......@@ -62,7 +62,7 @@ class TaggableManagerTestCase(BaseTaggingTestCase):
housepet_model = HousePet
taggeditem_model = TaggedItem
tag_model = Tag
def test_add_tag(self):
apple = self.food_model.objects.create(name="apple")
self.assertEqual(list(apple.tags.all()), [])
......@@ -93,14 +93,14 @@ class TaggableManagerTestCase(BaseTaggingTestCase):
tag = self.tag_model.objects.create(name="delicious")
apple.tags.add(tag)
self.assert_tags_equal(apple.tags.all(), ["red", "delicious"])
apple.delete()
self.assert_tags_equal(self.food_model.tags.all(), ["green"])
def test_require_pk(self):
food_instance = self.food_model()
self.assertRaises(ValueError, lambda: food_instance.tags.all())
def test_delete_obj(self):
apple = self.food_model.objects.create(name="apple")
apple.tags.add("red")
......@@ -109,24 +109,24 @@ class TaggableManagerTestCase(BaseTaggingTestCase):
strawberry.tags.add("red")
apple.delete()
self.assert_tags_equal(strawberry.tags.all(), ["red"])
def test_delete_bulk(self):
apple = self.food_model.objects.create(name="apple")
kitty = self.pet_model.objects.create(pk=apple.pk, name="kitty")
apple.tags.add("red", "delicious", "fruit")
kitty.tags.add("feline")
self.food_model.objects.all().delete()
self.assert_tags_equal(kitty.tags.all(), ["feline"])
def test_lookup_by_tag(self):
apple = self.food_model.objects.create(name="apple")
apple.tags.add("red", "green")
pear = self.food_model.objects.create(name="pear")
pear.tags.add("green")
self.assertEqual(
list(self.food_model.objects.filter(tags__name__in=["red"])),
[apple]
......@@ -146,25 +146,25 @@ class TaggableManagerTestCase(BaseTaggingTestCase):
)
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__in=[tag])), [dog])
cat = self.housepet_model.objects.create(name="cat", trained=True)
cat.tags.add("fuzzy")
self.assertEqual(
map(lambda o: o.pk, self.pet_model.objects.filter(tags__name__in=["fuzzy"])),
[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")
guava = self.food_model.objects.create(name="guava")
self.assertEqual(
map(lambda o: o.pk, self.food_model.objects.exclude(tags__name__in=["red"])),
[pear.pk, guava.pk],
......@@ -202,12 +202,12 @@ class TaggableManagerTestCase(BaseTaggingTestCase):
self.tag_model.objects.filter(**lookup_kwargs),
['scary']
)
def test_taggeditem_unicode(self):
ross = self.pet_model.objects.create(name="ross")
# I keep Ross Perot for a pet, what's it to you?
ross.tags.add("president")
self.assertEqual(
unicode(self.taggeditem_model.objects.all()[0]),
"ross tagged with president"
......@@ -237,16 +237,16 @@ class TaggableManagerOfficialTestCase(TaggableManagerTestCase):
housepet_model = OfficialHousePet
taggeditem_model = OfficialThroughModel
tag_model = OfficialTag
def test_extra_fields(self):
self.tag_model.objects.create(name="red")
self.tag_model.objects.create(name="delicious", official=True)
apple = self.food_model.objects.create(name="apple")
apple.tags.add("delicious", "red")
pear = self.food_model.objects.create(name="Pear")
pear.tags.add("delicious")
self.assertEqual(
map(lambda o: o.pk, self.food_model.objects.filter(tags__official=False)),
[apple.pk],
......@@ -256,7 +256,7 @@ class TaggableManagerOfficialTestCase(TaggableManagerTestCase):
class TaggableFormTestCase(BaseTaggingTestCase):
form_class = FoodForm
food_model = Food
def test_form(self):
self.assertEqual(self.form_class.base_fields.keys(), ['name', 'tags'])
......@@ -271,11 +271,11 @@ class TaggableFormTestCase(BaseTaggingTestCase):
apple = self.food_model.objects.get(name='apple')
self.assert_tags_equal(apple.tags.all(), ['green', 'red', 'yummy', 'delicious'])
self.assertEqual(self.food_model.objects.count(), 1)
f = self.form_class({"name": "raspberry"})
raspberry = f.save()
self.assert_tags_equal(raspberry.tags.all(), [])
f = self.form_class(instance=apple)
self.assertEqual(str(f), """<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" value="apple" maxlength="50" /></td></tr>\n<tr><th><label for="id_tags">Tags:</label></th><td><input type="text" name="tags" value="delicious, green, red, yummy" id="id_tags" /><br />A comma-separated list of tags.</td></tr>""")
......@@ -287,7 +287,7 @@ class TaggableFormTestCase(BaseTaggingTestCase):
f = self.form_class(instance=apple)
self.assertEqual(str(f), """<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" value="apple" maxlength="50" /></td></tr>\n<tr><th><label for="id_tags">Tags:</label></th><td><input type="text" name="tags" value="&quot;has space&quot;, &quot;has,comma&quot;, delicious, green, red, yummy" id="id_tags" /><br />A comma-separated list of tags.</td></tr>""")
class TaggableFormDirectTestCase(TaggableFormTestCase):
form_class = DirectFoodForm
food_model = DirectFood
......@@ -315,18 +315,18 @@ class TagStringParseTestCase(UnitTestCase):
self.assertEqual(parse_tags('one two'), [u'one', u'two'])
self.assertEqual(parse_tags('one two three'), [u'one', u'three', u'two'])
self.assertEqual(parse_tags('one one two two'), [u'one', u'two'])
def test_with_comma_delimited_multiple_words(self):
"""
Test with comma-delimited multiple words.
An unquoted comma in the input will trigger this.
"""
"""
self.assertEqual(parse_tags(',one'), [u'one'])
self.assertEqual(parse_tags(',one two'), [u'one two'])
self.assertEqual(parse_tags(',one two three'), [u'one two three'])
self.assertEqual(parse_tags('a-one, a-two and a-three'),
[u'a-one', u'a-two and a-three'])
def test_with_double_quoted_multiple_words(self):
"""
Test with double-quoted multiple words.
......@@ -338,19 +338,19 @@ class TagStringParseTestCase(UnitTestCase):
self.assertEqual(parse_tags('"one two"'), [u'one two'])
self.assertEqual(parse_tags('a-one "a-two and a-three"'),
[u'a-one', u'a-two and a-three'])
def test_with_no_loose_commas(self):
"""
Test with no loose commas -- split on spaces.
"""
self.assertEqual(parse_tags('one two "thr,ee"'), [u'one', u'thr,ee', u'two'])
def test_with_loose_commas(self):
"""
Loose commas - split on commas
"""
self.assertEqual(parse_tags('"one", two three'), [u'one', u'two three'])
def test_tags_with_double_quotes_can_contain_commas(self):
"""
Double quotes can contain commas
......@@ -359,7 +359,7 @@ class TagStringParseTestCase(UnitTestCase):
[u'a-one', u'a-two, and a-three'])
self.assertEqual(parse_tags('"two", one, one, two, "one"'),
[u'one', u'two'])
def test_with_naughty_input(self):
"""
Test with naughty input.
......
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