This commit is contained in:
JensDiemer 2012-08-06 12:23:31 +02:00
parent a9d7ec1b83
commit eb40096ebf
4 changed files with 143 additions and 76 deletions

11
README
View file

@ -39,7 +39,7 @@ B. Test & contribute to django-uuslug: (for developers)
Unicode Test Example
=====================
from uuslug import uuslug as slugify
from uuslug import slugify
s = "This is a test ---"
r = slugify(s)
@ -63,7 +63,7 @@ Uniqueness Test Example
Override your object's save method with something like this (models.py)
from django.db import models
from uuslug import uuslug as slugify
from uuslug import uuslug
class CoolSlug(models.Model):
name = models.CharField(max_length=100)
@ -73,9 +73,14 @@ class CoolSlug(models.Model):
return self.name
def save(self, *args, **kwargs):
self.slug = slugify(self.name, instance=self)
self.slug = uuslug(self.name, instance=self)
super(CoolSlug, self).save(*args, **kwargs)
You can specify the start number, e.g.: the second slug should start with "-2" instead of "-1":
self.slug = uuslug(self.name, instance=self, start_no=2)
Test:
=====

View file

@ -18,7 +18,7 @@ pkg_resources.require("Unidecode")
from unidecode import unidecode
# only allow the import of our public APIs (UU-SLUG = Uniqure & Unicode Slug)
__all__ = ['uuslug']
__all__ = ['slugify', 'uuslug']
# character entity reference
@ -34,46 +34,10 @@ REPLACE1_REXP = re.compile(r'[\']+')
REPLACE2_REXP = re.compile(r'[^-a-z0-9]+')
REMOVE_REXP = re.compile('-{2,}')
def uuslug(s, entities=True, decimal=True, hexadecimal=True,
instance=None, slug_field='slug', filter_dict=None):
"""This method tries a little harder than django's django.template.defaultfilters.slugify.
Parameters
----------
s : string
Explanation
entities: boolean, optional
Explanation
decimal : boolean, optional
Explanation
hexadecimal : boolean, optional
Explanation
instance : Model object or None, optional
Explanation
slug_field : string, optional
Explanation
filter_dict : dictionary, optional
Explanation
Returns
-------
slug : string
Explanation
Examples
--------
Example usage in save method for model:
import uuslug as slugify
self.slug = slugify(self.name, instance=self)
Notes
-----
From http://www.djangosnippets.org/snippets/369/
def slugify(s, entities=True, decimal=True, hexadecimal=True):
"""
make a slug from the given string
"""
if type(s) != UnicodeType:
s = unicode(s, 'utf-8', 'ignore')
@ -110,19 +74,62 @@ def uuslug(s, entities=True, decimal=True, hexadecimal=True,
#remove redundant -
s = REMOVE_REXP.sub('-', s).strip('-')
slug = s
if instance:
def get_query():
if hasattr(instance, 'objects'):
raise Exception("Error: you must pass an instance to uuslug, not a model.")
query = instance.__class__.objects.filter(**{slug_field: slug})
if filter_dict:
query = query.filter(**filter_dict)
if instance.pk:
query = query.exclude(pk=instance.pk)
return query
counter = 1
while get_query():
slug = "%s-%s" % (s, counter)
counter += 1
return slug
return s
def uuslug(s, instance, entities=True, decimal=True, hexadecimal=True,
slug_field='slug', filter_dict=None, start_no=1):
"""This method tries a little harder than django's django.template.defaultfilters.slugify.
Parameters
----------
s : string
Explanation
entities: boolean, optional
Explanation
decimal : boolean, optional
Explanation
hexadecimal : boolean, optional
Explanation
instance : Model object or None, optional
Explanation
slug_field : string, optional
Explanation
filter_dict : dictionary, optional
Explanation
Returns
-------
slug : string
Explanation
Examples
--------
Example usage in save method for model:
import uuslug as slugify
self.slug = slugify(self.name, instance=self)
Notes
-----
From http://www.djangosnippets.org/snippets/369/
"""
if hasattr(instance, 'objects'):
raise Exception("Error: you must pass an instance to uuslug, not a model.")
queryset = instance.__class__.objects.all()#.only("pk", slug_field)
if filter_dict:
queryset = queryset.filter(**filter_dict)
if instance.pk:
queryset = queryset.exclude(pk=instance.pk)
slug1 = slugify(s, entities=entities, decimal=decimal, hexadecimal=hexadecimal)
slug2 = slug1
counter = start_no
while queryset.filter(**{slug_field: slug2}).exists():
slug2 = "%s-%s" % (slug1, counter)
counter += 1
return slug2

View file

@ -3,17 +3,30 @@ import os
# create a database table only in unit test mode
if os.environ['DJANGO_SETTINGS_MODULE'] == 'uuslug.testsettings':
from django.db import models
from uuslug import uuslug as slugify
from uuslug import uuslug
class CoolSlug(models.Model):
name = models.CharField(max_length=100)
slug = models.CharField(max_length=200)
def __unicode__(self):
return self.name
def save(self, *args, **kwargs):
self.slug = slugify(self.name, instance=self)
self.slug = uuslug(self.name, instance=self)
super(CoolSlug, self).save(*args, **kwargs)
class AnotherSlug(models.Model):
name = models.CharField(max_length=100)
slug = models.CharField(max_length=200)
def __unicode__(self):
return self.name
def save(self, *args, **kwargs):
self.slug = uuslug(self.name, instance=self, start_no=2)
super(AnotherSlug, self).save(*args, **kwargs)

View file

@ -1,9 +1,19 @@
# -*- coding: utf-8 -*-
# coding: utf-8
"""Unit tests for uslug"""
from django.test import TestCase
from django.db import models, connection
from django.template import Context, Template
from uuslug.models import CoolSlug
from uuslug import uuslug as slugify
from django.test import TestCase
from django.db import connections, DEFAULT_DB_ALIAS, reset_queries
from django.core.signals import request_started
# http://pypi.python.org/pypi/django-tools/
#from django_tools.unittest_utils.print_sql import PrintQueries
from uuslug.models import CoolSlug, AnotherSlug
from uuslug import slugify
class SlugUnicodeTestCase(TestCase):
"""Tests for Slug - Unicode"""
@ -25,19 +35,51 @@ class SlugUnicodeTestCase(TestCase):
r = slugify(s)
self.assertEquals(r, "ying-shi-ma")
class SlugUniqueTestCase(TestCase):
"""Tests for Slug - Unique"""
def test_manager(self):
name = "john"
c = CoolSlug.objects.create(name=name)
c.save()
self.assertEquals(c.slug, name)
c1 = CoolSlug.objects.create(name=name)
c1.save()
self.assertEquals(c1.slug, name+"-1")
#with PrintQueries("create first john"): # display the SQL queries
with self.assertNumQueries(2):
# 1. query: SELECT test, if slug 'john' exists
# 2. query: INSERT values
obj = CoolSlug.objects.create(name=name)
self.assertEquals(obj.slug, "john")
#with PrintQueries("create second john"): # display the SQL queries
with self.assertNumQueries(3):
# 1. query: SELECT test, if slug 'john' exists
# 2. query: SELECT test, if slug 'john-1' exists
# 3. query: INSERT values
obj = CoolSlug.objects.create(name=name)
self.assertEquals(obj.slug, "john-1")
def test_start_no(self):
name = 'Foo Bar'#'C\'est déjà l\'été.'
#with PrintQueries("create first 'Foo Bar'"): # display the SQL queries
with self.assertNumQueries(2):
# 1. query: SELECT test, if slug 'foo-bar' exists
# 2. query: INSERT values
obj = AnotherSlug.objects.create(name=name)
self.assertEquals(obj.slug, "foo-bar")
#with PrintQueries("create second 'Foo Bar'"): # display the SQL queries
with self.assertNumQueries(3):
# 1. query: SELECT test, if slug 'foo-bar' exists
# 2. query: SELECT test, if slug 'foo-bar-2' exists
# 3. query: INSERT values
obj = AnotherSlug.objects.create(name=name)
self.assertEquals(obj.slug, "foo-bar-2")
#with PrintQueries("create third 'Foo Bar'"): # display the SQL queries
with self.assertNumQueries(4):
# 1. query: SELECT test, if slug 'foo-bar' exists
# 2. query: SELECT test, if slug 'foo-bar-2' exists
# 3. query: SELECT test, if slug 'foo-bar-3' exists
# 4. query: INSERT values
obj = AnotherSlug.objects.create(name=name)
self.assertEquals(obj.slug, "foo-bar-3")