Page not Found (404) and it's get tricky

Hello, everyone, I am using django 4.2.19, when I runserver and go to “about” page or “contact” I see an error Page not found (404) raised by blog.views.PostDetailView.
So this is my code:

# views.py
from django.views import generic
from django.conf import settings
from django.core.mail import send_mail
from django.shortcuts import reverse
 
from .models import Post
from .forms import ContactForm
 
 
class PostListView(generic.ListView):
    model = Post
    queryset = Post.objects.all()
    context_object_name = 'posts'
    template_name = 'post_list.html'
    paginate_by = 5
 
 
class PostDetailView(generic.DetailView):
    model = Post
    context_object_name = 'post'
    template_name = 'post_detail.html'
 
 
class SuccessView(generic.TemplateView):
    template_name = 'success.html'
 
 
class ContactView(generic.FormView):
    form_class = ContactForm
    template_name = 'contact.html'
 
    def get_success_url(self):
        return reverse('blog:contact')
 
    def form_valid(self, form):
        email = form.cleaned_data.get('email')
        subject = form.cleaned_data.get('subject')
        message = form.cleaned_data.get('message')
 
        full_message = f"""
            Received message below from {email}, {subject}
            ______________________
            {message}
        """
        send_mail(
            subject='Received contact form from submission',
            message=full_message,
            from_email=settings.DEFAULT_FROM_EMAIL,
            recipient_list=[settings.NOTIFY_EMAIL],
        )
        return super(ContactView, self).form_valid(form)


class AboutView(generic.TemplateView):
    template_name = 'about.html'
# urls.py
from django.urls import path
 
from .views import PostListView, PostDetailView, ContactView, SuccessView, AboutView
 
app_name = 'blog'
 
urlpatterns = [
    path('', PostListView.as_view(), name='post_list'),
    path('<slug:slug>/', PostDetailView.as_view(), name='post_detail'),
    path('contact/', ContactView.as_view(), name='contact'),
    path('success/', SuccessView.as_view(), name='success'),
    path('about/', AboutView.as_view(), name='about'),
]
# models.py
from django.db import models
from django.urls import reverse
from django.utils import timezone
from django.template.defaultfilters import slugify
 
from tinymce.models import HTMLField
 
 
class Post(models.Model):
    title = models.CharField(max_length=255)
    description = models.CharField(max_length=255)
    slug = models.SlugField(null=False, unique=True)
    body = HTMLField()
    pub_date = models.DateField(default=timezone.now)
 
    class Meta:
        ordering = ['-pub_date']
        verbose_name = 'Post'
        verbose_name_plural = 'Posts'
 
    def __str__(self):
        return self.title
 
    def get_absolute_url(self):
        return reverse('blog:post_detail', kwargs={'slug': self.slug})
 
    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.title)
        return super().save(*args, **kwargs)
# python3 manage.py runserver
System check identified no issues (0 silenced).
February 21, 2025 - 13:22:35
Django version 4.2.19, using settings 'config.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
 
Not Found: /contact/
[21/Feb/2025 13:22:47] "GET /contact/ HTTP/1.1" 404 2612
Not Found: /favicon.ico
[21/Feb/2025 13:22:47] "GET /favicon.ico HTTP/1.1" 404 3330
Page not found (404)
 
No Post found matching the query
 
Request Method:     GET
Request URL:    http://127.0.0.1:8000/contact/
Raised by:  blog.views.PostDetailView
 
Using the URLconf defined in config.urls, Django tried these URL patterns, in this order:
 
    admin/
    [name='post_list']
    <slug:slug>/ [name='post_detail']
 
The current path, contact/, matched the last one.

But when I change urls.py like this

# urls.py
from django.urls import path
 
from .views import PostListView, PostDetailView, ContactView, SuccessView, AboutView
 
app_name = 'blog'
 
urlpatterns = [
    path('', PostListView.as_view(), name='post_list'),
    path('contact/', ContactView.as_view(), name='contact'),
    path('success/', SuccessView.as_view(), name='success'),
    path('about/', AboutView.as_view(), name='about'),
    path('<slug:slug>/', PostDetailView.as_view(), name='post_detail'),
]

Everything is just working… Why is that?

Because urls are searched in the order that they appear within the urlpatterns.

Since “contact”, “success” and “about” would all be valid values for a slug, it was matching the slug pattern first, and so trying to call the PostDetailView.

See URL dispatcher | Django documentation | Django for more details.