More than a year ago I wrote the post: Auto generating unique slug in Django. There we considered a model named Article
, which had title
and slug
fields. We had overridden the save
method of that model to automatically save the unique slug which had been generated by our written _get_unique_slug
model method. But what will happen if we want to auto generate unique slug for tens or even hundreds of models? Do the same for each of the models? No way! So, in this post, we will know how we can achieve that through a generic approach. To continue reading this post, you don’t necessarily need to read that previous post, but recommended.
The Basics
What is slug? Consider the URL of this post: /auto-generating-unique-slug-django-generic-approach/ . Here the bold part of the URL is called slug.
Suppose we have tens of models including the Author
:
|
|
Based on the name
filed, slug
filed should be generated. If the name
of our first Author
is ‘John Doe’, the slug
should be ‘john-doe’. If the name
of our second Author
is also ‘John Doe’, the slug
should be ‘john-doe-1’. And if the name
of our third Author
is ‘John Doe’ again, the slug
should be ‘john-doe-2’. And so on.
The Solution
Let’s create a file named utils.py
in the app directory and write this code:
|
|
As the docstring says, the get_unique_slug
takes a django model instance for the first argument, sluggable field name such as ’name’ (based on which the slug will be generated) of that model as string for the second argument and slug field name such as ‘slug’ of the model as string for the third argument. And it returns a unique slug as string.
Let’s break down the code a bit. At line 10, slugify
(django.utils.text.slugify
) takes a string like ‘John Doe’ as argument and returns a string like ‘john-doe’. And we are accessing the sluggable field of the model instance using getattr
. At line 13, we are getting the model class from the model instance using class
.
Take a closer look at line 15-19. Until we get a unique slug, we append the current slug string with an extension number starting from 1; such as ‘john-doe-1’, ‘john-doe-2’…. For accessing the model manager (usually objects
) we are using _default_manager
. Line 15 might look a bit tricky, in short, **{slug_field_name: unique_slug}
works like something similar to slug='john-doe'
. To understand this clearly, we need to know about how **kwargs
works in python and how django model unpacks it. As this is beyond the scope of this post, I’m not discussing it here.
Let’s update our models.py
:
|
|
Here we are overriding the save
method, if the slug
is already not set, we are setting it using the get_unique_slug
function.
You can also consider to use the pre_save signal instead of overriding the save method.
Boom! all done, enjoy!