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
0 Comments
Log in with Twitter, Google, Facebook, LinkedIn to leave a comment.