How to slugify URLs in Django

enter image description here

What is a slug?

In web development a slug is the unique identifying part of a web address, normally being the last part of the URL. For example, in the URL https://www.semrush.com/blog/what-is-a-url-slug the part what-is-a-url-slug is a slug. Slugs are unique for a web page.

Why to slugify your URLs?

The most important reason is to have SEO friendly URLs. When the search engine algorithm comes across your web page, it is a good start if your URLs have talkative slugs so that the algorithm can understand well what your page is about. This can make your website more likely to appear in the search results for relevant queries. Slugs are a good place to put some keywords in, however, keep in mind that having good keywords in your URL slug will not replace all the other ranking factors.
Apart from being SEO friendly, slugs are simply much more readable for us humans too. Imagine the blog URLs blog.com/1956 vs blog.com/slugify-urls. Just by looking at the URL you know what the page is about more or less.

Slugify URLs in Django

As for most of the things, Django provides great support for using URL slugs. Let’s see the main steps to slugify URLs.

You can check my repository of a Django Dog Grooming website on GitHub for a full example.

Add a slug field in your model class:

class Service(models.Model):
    """
    Service model.
    """
    id = models.AutoField(primary_key=True)
    service_name = models.CharField(max_length=100, null=False)
    price = models.IntegerField(null=False)
    service_description = models.TextField(null=False)
    max_duration = models.SmallIntegerField(null=False)
    photo = models.ImageField(blank=False, null=False, upload_to='services')
    active = models.BooleanField(default=True)
    slug = models.SlugField(unique=True, max_length=255, null=True, blank=True)

As you can see, Django even has a SlugField data type. If you didn’t add the slug field in the beginning, it is a good idea to add null=True so that the migration doesn’t fail.

Then, override the save() method of the model class to populate the slug field:

    def save(self, *args, **kwargs):
        # Other stuff not relevant now
        # ...
        if not self.slug:
            self.slug = slugify(self.service_name)
        super().save(*args, **kwargs)

Next, change your Service view so that it uses the slug instead of the id field to get the Service object:

class ServicePage(TemplateView):
    """
    View class for the service.
    """
    template_name = "service.html"

    def get_context_data(self, **kwargs):
        """
        Overriding the get_context_data method to add the Service object.
        """
        context = super().get_context_data(**kwargs)
        context["service"] = get_object_or_404(Service, slug=self.kwargs['slug'])
        return context

Reflect the change in the urls.py file as well:

urlpatterns = [
    # ...
    path('service/<slug:slug>', views.ServicePage.as_view(), name='service'),
    # ...
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

With the above changes I went from having URLs like mywebsite.com/en/service/3 to having mywebsite.com/en/service/cutting-nails.

Conclusion

Of course, there is more to it, but basically with a few changes you can slugify your URLs and enjoy all the advantages it brings, as mentioned above.

Image source: https://pharaonic.io/assets/media/packages/php/slugify.jpg

Comments