Commit f759697f by Alex Gaynor

Added support for a custom slugify.

parent dccc744b
......@@ -142,10 +142,10 @@ class _TaggableManager(models.Manager):
name__in=str_tags
)
tag_objs.update(existing)
for new_tag in str_tags - set(t.name for t in existing):
tag_objs.add(self.through.tag_model().objects.create(name=new_tag))
for tag in tag_objs:
self.through.objects.get_or_create(tag=tag, **self._lookup_kwargs())
......
......@@ -2,7 +2,7 @@ import django
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.generic import GenericForeignKey
from django.db import models, IntegrityError, transaction
from django.template.defaultfilters import slugify
from django.template.defaultfilters import slugify as default_slugify
from django.utils.translation import ugettext_lazy as _, ugettext
......@@ -18,7 +18,7 @@ class TagBase(models.Model):
def save(self, *args, **kwargs):
if not self.pk and not self.slug:
self.slug = slug = slugify(self.name)
self.slug = self.slugify(self.name)
if django.VERSION >= (1, 2):
from django.db import router
using = kwargs.get("using") or router.db_for_write(
......@@ -39,11 +39,17 @@ class TagBase(models.Model):
return res
except IntegrityError:
transaction.savepoint_rollback(sid, **trans_kwargs)
i += 1
self.slug = "%s_%d" % (slug, i)
self.slug = self.slugify(self.name, i)
else:
return super(TagBase, self).save(*args, **kwargs)
def slugify(self, tag, i=None):
slug = default_slugify(tag)
if i is not None:
slug += "_%d" % i
return slug
class Tag(TagBase):
class Meta:
verbose_name = _("Tag")
......@@ -137,4 +143,3 @@ class TaggedItem(GenericTaggedItemBase, TaggedItemBase):
class Meta:
verbose_name = _("Tagged Item")
verbose_name_plural = _("Tagged Items")
from django.db import models
from taggit.managers import TaggableManager
from taggit.models import TaggedItemBase, GenericTaggedItemBase, TagBase
from taggit.models import (TaggedItemBase, GenericTaggedItemBase, TaggedItem,
TagBase, Tag)
class Food(models.Model):
......@@ -106,7 +107,7 @@ class OfficialHousePet(OfficialPet):
class Media(models.Model):
tags = TaggableManager()
class Meta:
abstract = True
......@@ -115,3 +116,27 @@ class Photo(Media):
class Movie(Media):
pass
class ArticleTag(Tag):
class Meta:
proxy = True
def slugify(self, tag, i=None):
slug = "category-%s" % tag
if i is not None:
slug += "-%d" % i
return slug
class ArticleTaggedItem(TaggedItem):
class Meta:
proxy = True
# Basically we want to overide the tag ForeignKey to point at the proxy
# inherited ArticleTag so we can get the right slugify, unfortunately I
# can't seem to figure out how to do this, so we're on hold ATM.
class Article(models.Model):
title = models.CharField(max_length=100)
tags = TaggableManager(through=ArticleTaggedItem)
......@@ -12,18 +12,18 @@ from taggit.tests.forms import (FoodForm, DirectFoodForm, CustomPKFoodForm,
from taggit.tests.models import (Food, Pet, HousePet, DirectFood, DirectPet,
DirectHousePet, TaggedPet, CustomPKFood, CustomPKPet, CustomPKHousePet,
TaggedCustomPKPet, OfficialFood, OfficialPet, OfficialHousePet,
OfficialThroughModel, OfficialTag, Photo, Movie)
OfficialThroughModel, OfficialTag, Photo, Movie, Article)
from taggit.utils import parse_tags, edit_string_for_tags
class BaseTaggingTest(object):
def assert_tags_equal(self, qs, tags, sort=True):
got = map(lambda tag: tag.name, qs)
def assert_tags_equal(self, qs, tags, sort=True, attr="name"):
got = map(lambda tag: getattr(tag, attr), qs)
if sort:
got.sort()
tags.sort()
self.assertEqual(got, tags)
def assert_num_queries(self, n, f, *args, **kwargs):
original_DEBUG = settings.DEBUG
settings.DEBUG = True
......@@ -61,6 +61,15 @@ class TagModelTestCase(BaseTaggingTransactionTestCase):
yummy = self.tag_model.objects.create(name="yummy")
apple.tags.add(yummy)
def test_slugify(self):
a = Article.objects.create(title="django-taggit 1.0 Released")
a.tags.add("awesome", "release", "AWESOME")
self.assert_tags_equal(a.tags.all(), [
"category-awesome",
"category-release",
"category-awesome-1"
], attr="slug")
class TagModelDirectTestCase(TagModelTestCase):
food_model = DirectFood
tag_model = Tag
......@@ -113,7 +122,7 @@ class TaggableManagerTestCase(BaseTaggingTestCase):
apple.delete()
self.assert_tags_equal(self.food_model.tags.all(), ["green"])
def test_add_queries(self):
apple = self.food_model.objects.create(name="apple")
# 1 query to see which tags exist
......@@ -121,13 +130,13 @@ class TaggableManagerTestCase(BaseTaggingTestCase):
# + 6 queries to create the intermediary things (including SELECTs, to
# make sure we don't double create.
self.assert_num_queries(10, apple.tags.add, "red", "delicious", "green")
pear = self.food_model.objects.create(name="pear")
# 1 query to see which tags exist
# + 4 queries to create the intermeidary things (including SELECTs, to
# make sure we dont't double create.
self.assert_num_queries(5, pear.tags.add, "green", "delicious")
self.assert_num_queries(0, pear.tags.add)
def test_require_pk(self):
......@@ -245,7 +254,7 @@ class TaggableManagerTestCase(BaseTaggingTestCase):
unicode(self.taggeditem_model.objects.all()[0]),
"ross tagged with president"
)
def test_abstract_subclasses(self):
p = Photo.objects.create()
p.tags.add("outdoors", "pretty")
......@@ -253,7 +262,7 @@ class TaggableManagerTestCase(BaseTaggingTestCase):
p.tags.all(),
["outdoors", "pretty"]
)
m = Movie.objects.create()
m.tags.add("hd")
self.assert_tags_equal(
......@@ -340,9 +349,9 @@ class TaggableFormTestCase(BaseTaggingTestCase):
self.assertEqual(ff.label, 'categories')
self.assertEqual(ff.help_text, u'Add some categories')
self.assertEqual(ff.required, False)
self.assertEqual(ff.clean(""), [])
tm = TaggableManager()
ff = tm.formfield()
self.assertRaises(ValidationError, ff.clean, "")
......
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