What is a slug in Django and How To Use It?
If you are working with Django or a similar web framework, you might have come across the term slug
, slugField
or slugify
. What do these terms mean, why are slugs useful and how to use them properly? Where does the term slug come from?
A slug is a human-readable, unique label for a piece of data - usually an article or post. It’s most commonly used in urls, so it should contain no special characters.
In this tutorial I’ll quickly walk you through the “why”s and “how”s of Django slugs and also reveal the secret: what does an url identifier have to do with those slimy little creatures?
What is a slug?
Slug is just a regular string, with some restrictions: as it is very often used to build nice, human readable urls, it should not contain any special characters, that would be encoded when passed to the browser as an url.
Why Are Slugs Important
Accessibility - Human-readable URLs
Which one is better to look at:
https://pythonin1minute.com/what-is-a-slug-in-django/
or
https://pythonin1minute.com/articles?article_id=976f9bab-da45-4dd6-a5be-7e243472bd07
?
It is just a much nicer user experience to see meaningful, intelligible urls on a website.
Search Engine Optimization
Having human human readable URLs does help with technical SEO, as it is a basic requirement by search engines. Excerpt from Google’s SEO guidelines:
A site’s URL structure should be as simple as possible. Consider organizing your content so that URLs are constructed logically and in a manner that is most intelligible to humans (when possible, readable words rather than long ID numbers). For example, if you’re searching for information about aviation, a URL like http://en.wikipedia.org/wiki/Aviation will help you decide whether to click that link. A URL like http://www.example.com/index.php?id_sezione=360&sid=3a5ebc944f41daa6f849f730f1, is much less appealing to users.
Consider using punctuation in your URLs. The URL http://www.example.com/green-dress.html is much more useful to us than http://www.example.com/greendress.html. We recommend that you use hyphens (-) instead of underscores (_) in your URLs.
So, if you have a Django app, that has some Article
records in the database, then - from an SEO point-of-view - you are better off, if you look them up by some kind of meaningful identifier, then using just the auto-generated pk
or uuid
value.
Permalinks
In theory, you could have the article’s title directly included in the url and use that to look up the article, but the main problem with that approach would be that if you happen to update the title, that would mean the url also changes. You probably do not want that, as that would mean that all the external links to the page would be broken. From an SEO point-of-view that’s catastrophic. It would also mean that you need to update all your internal links as well. On top of that all users who might have bookmarked the page will probably be greeted with a 404 error page, as their bookmark would bring them to the old url.
For these reasons, it is considered good practice to keep webpages accessible on a permanent, unchanging link - a permalink.
How to Generate a Slug?
One possible (and actually the most commonly used) strategy to generate a slug for - let’s say - a blog post, is something like this:
- Take the title of the blog post
- Turn the whole title into lowercase
- Replace all whitespace characters with a hyphen (
-
). Note: Multiple consequent whitespace characters should also be replaced with one single hyphen:hello
world
should becomehello-world
nothello----world
- Remove all other special characters (only letters, numbers and hyphens are allowed)
For example: the title of this article is What is a slug in Django?
. The generated slug - as you can see in the url - is what-is-a-slug-in-django
Let’s see how to do that in Django!
Slugs in Django - the SlugField
Django comes with a model field that’s aimed specifically at storing slugs. It’s called SlugField
and actually it’s just a Charfield
with some extra validation, that makes sure that there are no invalid characters in the string.
Let’s see how to use it in practice:
How to Add SlugField to a Django Model
Let’s say you have an article model with a title:
# models.py
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=200)
You can simply add the slug field like this:
# models.py
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(max_length=200)
Populating Slug Fields
Adding the field to your model does not do much good in itself, somehow you will need to populate these fields with values.
Auto-Populating in Admin
One way to generate values for you slug field is to add it to the prepopulated_fields
in the admin class.
For example, for the Article
model defined above, we can define an admin class like this:
# admin.py
from django.contrib import admin
from .models import Article
class ArticleAdmin(admin.ModelAdmin):
prepopulated_fields = {"slug": ("title",)}
admin.site.register(Article, ArticleAdmin)
This will add a bit of javascript to the article admin page, that automatically generates a slug from the title. This is done only on creation, but not on update (in most cases we do not want to change the url, even if the title changes - see the section about permalinks)
If you go with this solution, the admin users will have the ability to change the generated slug manually.
As this is only a piece of client side code on the admin page, if the article is created programmatically, you will have to take care of the slug generation, otherwise it will remain empty.
Generating Slug Fields on Save
Another valid approach is to do the slug generation behind the scenes. You can override your Article
model’s save method to generate a slug and populate the field with it.
To generate the slug value, we will use Django’s slugify
utility.
Update your models file, like this:
# models.py
from django.utils.text import slugify
class Article(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField()
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super().save(*args, **kwargs)
The problem with this code is that it always regenerates the slug, whenever the title changes. We only want to do that on creation. (permalinks - remember?).
This issue is easily fixed, by checking the slug, and updating it only if it’s empty. The modified code looks like this:
# models.py
from django.db import models
from django.utils.text import slugify
class Article(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField()
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super().save(*args, **kwargs)
Ensure Uniqueness
This is looking good so far, but what happens if an admin creates two articles the would have the same slug? How would Django know which one to find?
To ensure that for each slug there is always only one record in the articles table in the database, we can add some constraints on the Article
model’s slug
field: we want it to be unique
and we do not want to allow null
values.
The model’s code now looks like this:
# models.py
from django.db import models
from django.utils.text import slugify
class Article(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(unique=True, null=False)
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super().save(*args, **kwargs)
This ensures that no duplicate values are allowed for the slug
column in the database. If you try to create a second one with an existing value, you will get an error.
Depending on the database backend, most likely the lookups will also be a bit faster, as the db engine will be able to use an index on the unique key.
Lookup
The lookup itself, is pretty simple, assuming that you are using django.views.generic.DetailView
as the base class for your ArticleView
class, you can just define the urls for your articles with slug
as a keyword argument:
# urls.py
from django.urls import path
from .views import ArticleView
urlpatterns = [
path('<slug:slug>', ArticleView.as_view())
]
Bonus: Where Does the Term “slug” Came From?
This all make sense, but why are they called slugs? As you made this far, here’s some fun trivia:
Actually, this term comes from newspaper publishing lingo - in the news room articles were referred to by a short, unique a name, to save time and avoid confusion.
The expression originated from printing/typesetting jargon. From the New York Times:
The term slug derives from the days of hot-metal printing, when printers set type by hand in a small form called a stick. Later huge Linotype machines turned molten lead into casts of letters, lines, sentences and paragraphs. A line of lead in both eras was known as a slug.
References
https://www.nytimes.com/times-insider/2014/11/24/whats-in-a-slug/ https://developers.google.com/search/docs/advanced/guidelines/url-structure?hl=en&visit_id=637415938585980856-1552768230&rd=1