Using Slug in URL with Django

I will show how we will use slug in our blog. So, what is this slug? A slug represents of the current page in the URL. Most of the time, the page title is used as a slug. There are too much examples to prove it. Well, my blog isn't big but it uses Blogger structure. This one of the examples as a slug from my blog post:
A slug as example

Also, if you look some questions from stackoverflow. You can see they use /question_id/slug-text structure for their URLs. We can find too much examples like this.

I'm going to apply this slug feature for my project that exists. Open models.py in the application folder called blog. Define a new field for Post model as slug:
....

class Post(models.Model):
    title = models.CharField(max_length=400)
    content = models.TextField()
    slug = models.SlugField(unique=True)
    pub_date = models.DateTimeField(auto_now_add=True)
    categories = models.ManyToManyField(Category)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    image = models.ImageField(upload_to='image/', null=True)
    
    def __str__(self):
        return self.title
    
    class Meta:
        ordering = ['-pub_date',]
        
...
I set unique as True to avoid url conflicts. However there are another two important points that I want emphazise them here. The first thing is about the posts already exist in the database. If we want to try to update this model in the database, probably it will cause a problem because of the old posts. In this point, we are in the second important thing that is about generating slug automatically. We can solve the problem with this solution. Also, we don't have to type custom slug all the time, this will be optional if you want. Therefore, I will override method called save in the post model:
from django.db import models
from django.contrib.auth.models import User
from django.utils.text import slugify

...

class Post(models.Model):
    title = models.CharField(max_length=400)
    content = models.TextField()
    slug = models.SlugField(blank=True, unique=True)
    pub_date = models.DateTimeField(auto_now_add=True)
    categories = models.ManyToManyField(Category)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    image = models.ImageField(upload_to='image/', null=True, blank=True)
    
    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.title)
        super(Post, self).save(*args, **kwargs)

    def __str__(self):
        return self.title
    
    class Meta:
        ordering = ['-pub_date',]
        
...
After these changes, I will update the database with makemigrations and then migrate command. I want to update url routing for the post detail view:
from django.urls import path
from .views import * 

urlpatterns = [
    path('', IndexView.as_view(), name="index"),
    path('about', about, name="about"),
    path('post/<slug:slug>/', DetailView.as_view(), name="detail"),
]
Probably, we can't open the old posts. So let's update these slug fields of the old posts in the admin panel:
slug in django admin panel

Save them like in the above and then open again old post in blog. I got this error about pk. Probably it's about comment. Because I call comments with pk value of the posts. Let's change it as slug and try again. I changed it DetailView:
....

class DetailView(generic.DetailView):
    model = Post
    template_name = 'detail.html'

    def get_context_data(self,**kwargs):
        context = super(DetailView,self).get_context_data(**kwargs)
        context['comments']=Comment.objects.all().filter(post = get_object_or_404(Post, slug=self.kwargs['slug']))
        return context

    def post(self, request, pk):
        post = get_object_or_404(Post, pk=pk)
        new_comment = Comment(
            username= request.POST.get('comment-username'), 
            content= request.POST.get('comment-textarea'),
            post = post
        )
        new_comment.save()
        return redirect(request.META['HTTP_REFERER'])
        
...
and the result is like this:
Slug in Django

So, let's create a new post but don't define a slug for it and yes we got it:
Django Slug Automatically

If we try to create post with same the post title, it will be occured error after the save operation. That's because we define slug field as unique. I think we've learned important information about slugs. Good work!

No comments:

Post a Comment