How do I create a slug in Django?

PythonDjangoDjango ModelsSlug

Python Problem Overview


I am trying to create a SlugField in Django.

I created this simple model:

from django.db import models

class Test(models.Model):
    q = models.CharField(max_length=30)
    s = models.SlugField()

I then do this:

>>> from mysite.books.models import Test
>>> t=Test(q="aa a a a", s="b b b b")
>>> t.s
'b b b b'
>>> t.save()
>>> t.s
'b b b b'

I was expecting b-b-b-b.

Python Solutions


Solution 1 - Python

You will need to use the slugify function.

>>> from django.template.defaultfilters import slugify
>>> slugify("b b b b")
u'b-b-b-b'
>>>

You can call slugify automatically by overriding the save method:

class Test(models.Model):
    q = models.CharField(max_length=30)
    s = models.SlugField()
    
    def save(self, *args, **kwargs):
        self.s = slugify(self.q)
        super(Test, self).save(*args, **kwargs)

Be aware that the above will cause your URL to change when the q field is edited, which can cause broken links. It may be preferable to generate the slug only once when you create a new object:

class Test(models.Model):
    q = models.CharField(max_length=30)
    s = models.SlugField()
    
    def save(self, *args, **kwargs):
        if not self.id:
            # Newly created object, so set slug
            self.s = slugify(self.q)

        super(Test, self).save(*args, **kwargs)

Solution 2 - Python

There is corner case with some utf-8 characters

Example:

>>> from django.template.defaultfilters import slugify
>>> slugify(u"test ąęśćółń")
u'test-aescon' # there is no "l"

This can be solved with Unidecode

>>> from unidecode import unidecode
>>> from django.template.defaultfilters import slugify
>>> slugify(unidecode(u"test ąęśćółń"))
u'test-aescoln'

Solution 3 - Python

A small correction to Thepeer's answer: To override save() function in model classes, better add arguments to it:

from django.utils.text import slugify

def save(self, *args, **kwargs):
    if not self.id:
        self.s = slugify(self.q)

    super(test, self).save(*args, **kwargs)

Otherwise, test.objects.create(q="blah blah blah") will result in a force_insert error (unexpected argument).

Solution 4 - Python

If you're using the admin interface to add new items of your model, you can set up a ModelAdmin in your admin.py and utilize prepopulated_fields to automate entering of a slug:

class ClientAdmin(admin.ModelAdmin):
    prepopulated_fields = {'slug': ('name',)}

admin.site.register(Client, ClientAdmin)

Here, when the user enters a value in the admin form for the name field, the slug will be automatically populated with the correct slugified name.

Solution 5 - Python

In most cases the slug should not change, so you really only want to calculate it on first save:

class Test(models.Model):
    q = models.CharField(max_length=30)
    s = models.SlugField(editable=False) # hide from admin

    def save(self):
        if not self.id:
            self.s = slugify(self.q)

        super(Test, self).save()

Solution 6 - Python

If you don't want to set the slugfield to Not be editable, then I believe you'll want to set the Null and Blank properties to False. Otherwise you'll get an error when trying to save in Admin.

So a modification to the above example would be::

class test(models.Model):
    q = models.CharField(max_length=30)
    s = models.SlugField(null=True, blank=True) # Allow blank submission in admin.

    def save(self):
        if not self.id:
            self.s = slugify(self.q)

        super(test, self).save()

Solution 7 - Python

Use prepopulated_fields in your admin class:

class ArticleAdmin(admin.ModelAdmin):
    prepopulated_fields = {"slug": ("title",)}

admin.site.register(Article, ArticleAdmin)

Solution 8 - Python

I'm using Django 1.7

Create a SlugField in your model like this:

slug = models.SlugField()

Then in admin.py define prepopulated_fields;

class ArticleAdmin(admin.ModelAdmin):
    prepopulated_fields = {"slug": ("title",)}

Solution 9 - Python

You can look at the docs for the SlugField to get to know more about it in more descriptive way.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJohndView Question on Stackoverflow
Solution 1 - PythonBuddyView Answer on Stackoverflow
Solution 2 - PythonDooBLERView Answer on Stackoverflow
Solution 3 - PythonDingleView Answer on Stackoverflow
Solution 4 - PythonhenrymView Answer on Stackoverflow
Solution 5 - PythonthepeerView Answer on Stackoverflow
Solution 6 - PythonStreamweaverView Answer on Stackoverflow
Solution 7 - PythonsergeyView Answer on Stackoverflow
Solution 8 - Pythonmin2broView Answer on Stackoverflow
Solution 9 - PythonSonia RaniView Answer on Stackoverflow