Today, we’re looking at how to add a slug field to a Django model that automatically populates itself when you create an object in the database.
Say you’re creating a blog and instead of having each post as
https://myblog/post/1, you want
You could add
SlugField to your model. However, slug fields don’t populate automatically and your URL won’t work until you go into
/admin and populate the slug yourself.
What we need is to find a way to set the slug automatically when the post is created.
There are two ways to go about it:
1. Install django-autoslug
This method involves installing a package called django-autoslug and using its
AutoSlugField instead of
SlugField. This method is best if you need to guarantee the uniqueness of the slug.
2. Use the slugify method
This method involves adding a
SlugField to the model but we override the
save() method of the model so that the slug is calculated and assigned before saving to the database. This method is best if you want to minimise the number of 3rd party packages and take a native Django approach. However, this method only works if you don’t require slugs to be unique.
The gist below outlines how I auto-populated slugs on my movie model.
movie.slug uses the
AutoSlugField method and
movie.slug2 uses the
Method 1: django-autoslug (preferred)
First you need to install django-autoslug.
$ pip install django-autoslug
Then import the AutoSlugField into your model.
from autoslug import AutoSlugField
slug = AutoSlugField(populate_from='title',editable=True, always_update=True)
Method 2: slugify
from django.utils.text import slugify
Next, define a
slug2 = models.SlugField(max_length=255)
Finally, override the
def save(self, **kwargs): self.slug2 = slugify(self.title) super(Movie, self).save(**kwargs)
Note for beginners:
superline is telling Django to call the
save()method of the parent class. This lets us add our custom code and then tell Django to do what
save()would normally do. No copying and pasting code from
**kwargsis short for Keyword Arguments. The double asterisk allows you pass in a dictionary and Python will turn each item of the dictionary into an argument of the function. We have to include this because
save()is usually called with two keyword arguments:
using. By including them, we are preserving the original functionality.
If you’re using slugs to construct URLs, it is critical that each slug is unique.
Method 2 won’t guarantee a unique slug. If you set
unique=True on the
SlugField and then try to create two movies with the same title, then Django will raise an
IntegrityError when attempting to create the second movie because of the duplicate slug.
If you use django-autoslug as per Method 1, then django-autoslug will automatically calculate a unique slug and will not prevent you from creating two movies with the same title.
Unique With User
Django has constraints
unique_for_year. This is useful if you are constructing URLs from both slugs and dates.
How to we make our slugs unique for the user? Say our URL contains the user name and the post slug, we should allow two users to write posts with the same title.
This is where
django-autoslug comes in useful. We can specify
unique_with to provide more flexibility:
slug = AutoSlugField(populate_from='title', unique_with=['author__username'], always_update=True)
Problem: Django won’t let you make the migration without specifying a default.
This issue is common for both methods.
It is impossible to add a non-nullable field 'slug2' to movie without specifying a default. This is because the database needs something to populate existing rows.
If you get this message after running
python manage.py makemigrations, I’ve got a nice trick to automatically populate existing rows without allowing blank values or dropping your database. You can read about it here.
Problem: Django Admin won’t let you create objects without specifying the slug
This happens because the form in Django admin is validated before the
save() method is called.
What we can do is disable the fields in
You can do this by specifying
editable=False on the
AutoSlugField, but if you do this, they will no longer be visible in
My preferred method is to edit the admin code to make the fields read only.
How to make fields read_only in admin
admin.py where your model is registered.
Define a custom ModelAdmin class:
class MovieAdmin(admin.ModelAdmin): readonly_fields = ["slug", "slug2"] admin.site.register(Movie, MovieAdmin)
Don’t forget to state which admin class you are using when registering your model.
Slugs can be auto-populated by using either the
AutoSlugField of django-autoslug or by overriding the
save() method of a model. If you are using slugs to construct URLs and need to guarantee the slug’s uniqueness, then I recommend using
AutoSlugField as it will automatically correct the slug if it’s not unique.