How to Create Django SEO Friendly URL using Slugs/SlugField

Joseph Adediji
Tech Insights
Published in
4 min readMay 19, 2020

Do you want to Create Django SEO Friendly URL using Slugs?

Search engine optimization (SEO) is a very important aspect of any web application especially if you are hoping to get a handful of traffic from search engines such as Google.

There are many components/parts involved in building a search engine-optimized website and one of them is search engine friendly URLs also known as keyword-rich URLS / user-friendly URLs / slug URLs.

Luckily for us, Django comes inbuilt with a SlugField Model Field that allows us to easily generate search engine friendly strings that can be used in our URL patterns for easy creation of pretty URLs or search engine-friendly URLs.

A slug is the part of a URL that identifies a particular page on a website in an easy-to-read form. A slug usually contains only letters, numbers, underscores, or hyphens. They’re generally used in URLs.”

Take a look at these two URLs below for an article titled: “How to Code”

You would agree with me that the second URL looks pretty and conveys a meaning that is related to the content of our article.

In this article, I will be showing you how to create SEO friendly URL patterns in Django that look like the second URL above.

If you would prefer to watch me create SEO-friendly URLs in a Django app, then you can watch the video below.

For this article, I will be assuming you are familiar with Django installation and setup, so I won’t be talking about how to do that.

To get started, create a virtual environment, install Django, create a Django project, and create a Django app called “blog” or whatever you want.

For my example, I will be creating a Django App called “blog” which I will use to create a simple blog App that has an SEO-friendly URL.

Example App

My Blog App will consist of an Article Model, a view, and a URL Pattern.

In blog/models.py

class BlogPost(models.Model):    title = models.CharField(max_length=255)    pub_date = models.DateTimeField()    body = models.TextField()    image = models.ImageField(null=True, blank=True)

In blog/views.py

from django.views.generic import ListView, DetailViewfrom .models import BlogPost
class BlogListView(ListView):
model = BlogPost context_object_name = ‘blog_list’ template_name = ‘blog/blog.html’
class BlogDetailView(DetailView):
model = BlogPost context_object_name = ‘blog’ template_name = ‘blog/blog_post.html’

In blog/urls.py

from django.urls import pathfrom . import viewsurlpatterns = [    path(‘’, views.BlogListView.as_view(), name=’blog_home’),    path(‘article/<int:pk>/’, views.BlogDetailView.as_view(),       name=’blog_post’),]

Follow the steps below to create your pretty URLs.

Use SlugField in the Model

There is a special model Field type in Django for slugs: SlugField.

Create a field named slug with type: SlugField.

In blog/models.py

from django.db import modelsfrom django.urls import reverse
class BlogPost(models.Model):
title = models.CharField(max_length=255) pub_date = models.DateTimeField() body = models.TextField() image = models.ImageField(null=True, blank=True) slug = models.SlugField(default=’’, editable=False, max_length=200, null = False) def get_absolute_url(self): kwargs = { ‘pk’: self.id, ‘slug’: self.slug } return reverse(‘post-detail’, kwargs=kwargs)
def save(self, *args, **kwargs):
value = self.title self.slug = slugify(value, allow_unicode=True) super().save(*args, **kwargs)

Before saving the instance of a blog article, we convert the title to a slug with the slugify Django command, which basically replaces spaces with hyphens and also removes symbols if present.

As SlugField inherits from CharField, it comes with the attribute max_length which handles the maximum length of the string it contains at the database level.

If we use a SlugField without specifying its max_length attribute, it gets the value of 50 by default, which can lead to problems when we generate the string from a bigger max_length field.

So the trick is to make the title and the slug use the same max_length or make the slug field use a lesser max_lenght.

In blog/urls.py


path(‘article/<str:slug>-<int:pk>/’, ArticleDetailView.as_view() , name=’article-detail’)

In blog/views.py

from django.views.generic import ListView, DetailViewfrom .models import BlogPost
class BlogListView(ListView):
model = BlogPost context_object_name = ‘blog_list’ template_name = ‘blog/blog.html’
class BlogDetailView(DetailView): model = BlogPost context_object_name = ‘blog’ template_name = ‘blog/blog_post.html’

OR

You can use a function-based view and pass in the post slug and post PK into the view.

def blogPost(request, slug, pk):    blog = BlogPost.get_post(id=pk)    context = {        “blog”: blog,    }    return render(request, ‘article_details.html’, context)

In the above example, I am fetching the blog post using the “pk” which is a unique number attached to each data added to your database, fetching data via the “pk” is more reliable and I love using this approach.

In this case, the slug is just being used in the URL and nowhere else, the slug has nothing to do with fetching the article from our database.

So, that’s it.

If you follow the above steps, you should have a pretty URL for your articles right now.

Before you go, don’t forget to share this article on your social media profiles, someone might find it useful.

You can also Buy me a coffee.

--

--