DEV Community

DoriDoro
DoriDoro

Posted on

How to creating a SEO friendly URL in a Django project

Introduction

By creating an Search engine optimization (SEO) friendly URL, you will structure the pattern of a URL in a more meaningful way and make it easier for your content to be indexed.

To avoid a URL like www.example.com/blog/1/, create a canonical URL (get_absolute_url()) in the models.py file and we can change the URL pattern of the canonical URL to a SEO friendly URL.


Here is the Post model:

# models.py

from django.db import models
from django.urls import reverse

class Post(models.Model):
    title = models.CharField(max_length=250)
    slug = models.SlugField(max_length=250)
    author = models.ForeignKey(
        "account.User", on_delete=models.CASCADE, related_name="blog_posts"
    )
    body = models.TextField()

    def __str__(self):
        return self.title
Enter fullscreen mode Exit fullscreen mode

This code is a function-based view (FBV) to display one single Post instance on the website:

# views.py

from django.shortcuts import render, get_object_or_404

from blog.models import Post

def post_detail(request, pk):
    post = get_object_or_404(
        Post,
        pk=pk
    )
    return render(request, "post/detail.html", {"post": post})
Enter fullscreen mode Exit fullscreen mode

And the url pattern for the view:

# urls.py

from django.urls import path

from blog import views

urlpatterns = [
    path('<int:pk>/', views.post_detail, name='post_detail')
]
Enter fullscreen mode Exit fullscreen mode

Now we create the get_absolute_url() method in the Post model. We will use the model attribute slug to generate the SEO friendly URL. The URL pattern will change from www.example.com/blog/pk/ (www.example.com/blog/1/) (1 is the pk (id) of the post instance) and the new URL will look like: www.example.com/blog/slug/ (www.example.com/blog/name-of-the-post/).

# models.py

from django.db import models
from django.urls import reverse

class Post(models.Model):
    title = models.CharField(max_length=250)
    slug = models.SlugField(max_length=250, unique_for_date="publish")
    author = models.ForeignKey(
        "account.User", on_delete=models.CASCADE, related_name="blog_posts"
    )
    body = models.TextField()

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse(
            "blog:post_detail",
            args=[self.slug],
        )
Enter fullscreen mode Exit fullscreen mode

The get_absolute_url() method in Django is used to define the canonical URL for a model object, making it easier to refer to specific objects in templates or views. It returns the absolute URL path as a string, which can be used for redirection or linking. We often use the reverse() function inside get_absolute_url() because it resolves the URL based on the view name and arguments, ensuring a reliable and maintainable URL pattern that adapts to changes in the project’s URL configuration.

Now, we update the view, to exchange the pk with the slug:

# views.py

from django.shortcuts import render, get_object_or_404

from blog.models import Post

def post_detail(request, slug):
    post = get_object_or_404(
        Post,
        slug=post
    )
    return render(request, "post/detail.html", {"post": post})
Enter fullscreen mode Exit fullscreen mode

Don't forget to update the url pattern, and pass the slug as an argument:

# urls.py

from django.urls import path

from blog import views

urlpatterns = [
    path('<slug:post>/', views.post_detail, name='post_detail')
]
Enter fullscreen mode Exit fullscreen mode

Top comments (0)