Unique Slugs for Django Objects

I'm working on a new project and decided to use slugs to access object information.  The built-in in "slugify" does not generate unique slugs for objects, but I found a solution. Overriding the save method allows us to check to see if there are any other objects which have the same slug such as "how-to-make-a-table" and if there are we append a number to it such as "how-to-make-a-table-2." Below is a real-world example of a model "Project" which has pretty typical fields in it and the code to generate a unique slug. file: /myproject/myapp/models.py

from django.contrib.auth.models import User
from sorl.thumbnail import ImageField
import datetime
import re

class Project(models.Model):
        title = models.CharField(max_length=255,blank=True)
        description = models.TextField(blank=True)
        photo = ImageField(upload_to=get_project_upload_path, blank=True, null=True)
        author = models.ForeignKey(User, editable=False,blank=True, null=True)
        pub_date = models.DateTimeField(editable=False, blank=True)
        slug = models.SlugField(unique=True,blank=True)

        def save(self, *args, **kwargs):
		#set pub_date as right now
                self.pub_date=datetime.datetime.now()
		
		#As long as this object does NOT have a slug
                if not self.slug:
                   from django.template.defaultfilters import slugify
		
		   #Take the title and replace spaces with hypens, make lowercase
                   potential_slug = slugify(self.title)
                   self.slug = potential_slug

                   while True:
                      try:
			 #try to save the object
                         super(Project, self).save(*args, **kwargs)
		      
		      #if this slug already exists we get an error
                      except IntegrityError:
			 #match the slug or look for a trailing number
                         match_obj = re.match(r'^(.*)-(\d+)$', self.slug)
			 
			 #if we find a match
                         if match_obj:
			    #take the found number and increment it by 1
                            next_int = int(match_obj.group(2)) + 1
                            self.slug = match_obj.group(1) + "-" + str(next_int)
                         else:
			    #There are no matches for -# so create one with -2
                            self.slug += '-2'
		      #different error than IntegrityError
                      else:
                         break

        def __unicode__(self):
                return self.title
Tagged as django , python slugs
Written by Andrew Konkol on July 20th, 2011

0 Comments

Log in with Twitter, Google, Facebook, LinkedIn to leave a comment.