Skip to content

Commit

Permalink
generate slug from title and chomp off enough space
Browse files Browse the repository at this point in the history
for the counter suffix when handling collisions.
handles pyvideo#249
  • Loading branch information
codersquid committed Sep 5, 2014
1 parent 7675726 commit 3dc51e9
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 14 deletions.
22 changes: 11 additions & 11 deletions src/richard/videos/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@


def generate_unique_slug(obj, slug_from, slug_field='slug'):
text = getattr(obj, slug_from)[:49]
root_text = text
""" generate slug with trailing counts to prevent name collision """

max_length = obj._meta.get_field(slug_field).max_length

text = getattr(obj, slug_from)[:max_length]
base_slug = slugify(text_type(text))
slug = base_slug

for i in range(100):
slug = slugify(text_type(text))
try:
d = {slug_field: slug}
obj.__class__.objects.get(**d)
except obj.__class__.DoesNotExist:
if not obj.__class__.objects.filter(**{slug_field: slug}).exists():
return slug

ending = u'-%s' % i
text = root_text + ending
suffix = text_type(i)
slug = u'{}-{}'.format(base_slug[:max_length - len(suffix) - 1], suffix)

raise ValueError('No valid slugs available.')

2 changes: 1 addition & 1 deletion tests/test_videos/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ def test_post_video(self):

vid = Video.objects.get(title=data['title'])
assert vid.title == data['title']
assert vid.slug == u'creating-delicious-apis-for-django-apps-since-201'
assert vid.slug == u'creating-delicious-apis-for-django-apps-since-2010'
assert list(vid.speakers.values_list('name', flat=True)) == ['Guido']
assert (
sorted(vid.tags.values_list('tag', flat=True)) ==
Expand Down
20 changes: 18 additions & 2 deletions tests/test_videos/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.

from django.test import TestCase
import pytest

from . import factories
from richard.videos.utils import generate_unique_slug
Expand All @@ -32,8 +33,10 @@ def test_slug_creation(self):

def test_unique_slug(self):
"""Generate unique slug using incrementing ending."""
# These all have the same title, so they get increasingly
# lame slugs.
# These all have the same title, so subsequent videos get
# a trailing count on the slug

# This title is short! We want to check this so we don't chomp everything
factories.VideoFactory.create_batch(title=u'Foo', size=5)

v2 = factories.VideoFactory.build(title=u'Foo')
Expand All @@ -42,6 +45,19 @@ def test_unique_slug(self):
u'foo-4'
)

def test_max_length_slug(self):
# this is 51 characters long! We want to make sure we don't barf on lengthy titles
title = u'Creating delicious APIs for Django apps since 2010.'
factories.VideoFactory.create_batch(title=title, size=99)

v2 = factories.VideoFactory.create(title=title)
assert (
v2.slug == u'creating-delicious-apis-for-django-apps-since-2-98'
)
# now that we've created 100 duplicates, we've run out of slugs.
with pytest.raises(ValueError):
factories.VideoFactory.create(title=title)

def test_unicode_title(self):
v = factories.VideoFactory.build(title=u'Nebenläufige Programme mit Python')
assert (
Expand Down

0 comments on commit 3dc51e9

Please sign in to comment.