Handling dynamic `name’ argument in urls.py with CBVs with recent refactor

I recently refactored my CMS website and web apps to successfully render content for web pages that you’d come to expect for a blog - - pages such as:

  • home
  • about
  • podcasts
  • contact

It all ‘kind of works’ (on its own) as a proof of concept. Each page loads its content. But it is very basic.

The issue I have now is when trying to implement the navbar. Django is throwing a NoReverseMatch /about/

Here is the full traceback:

System check identified no issues (0 silenced).
February 04, 2023 - 17:10:02
Django version 4.1.3, using settings 'thelema_blender.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Internal Server Error: /about/
Traceback (most recent call last):
  File "/home/<user>/.local/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
  File "/home/<user>/.local/lib/python3.10/site-packages/django/core/handlers/base.py", line 220, in _get_response
    response = response.render()
  File "/home/<user>/.local/lib/python3.10/site-packages/django/template/response.py", line 114, in render
    self.content = self.rendered_content
  File "/home/<user>/.local/lib/python3.10/site-packages/django/template/response.py", line 92, in rendered_content
    return template.render(context, self._request)
  File "/home/<user>/.local/lib/python3.10/site-packages/django/template/backends/django.py", line 62, in render
    return self.template.render(context)
  File "/home/<user>/.local/lib/python3.10/site-packages/django/template/base.py", line 175, in render
    return self._render(context)
  File "/home/<user>/.local/lib/python3.10/site-packages/django/template/base.py", line 167, in _render
    return self.nodelist.render(context)
  File "/home/<user>/.local/lib/python3.10/site-packages/django/template/base.py", line 1005, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/home/<user>/.local/lib/python3.10/site-packages/django/template/base.py", line 1005, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/home/<user>/.local/lib/python3.10/site-packages/django/template/base.py", line 966, in render_annotated
    return self.render(context)
  File "/home/<user>/.local/lib/python3.10/site-packages/django/template/loader_tags.py", line 157, in render
    return compiled_parent._render(context)
  File "/home/<user>/.local/lib/python3.10/site-packages/django/template/base.py", line 167, in _render
    return self.nodelist.render(context)
  File "/home/<user>/.local/lib/python3.10/site-packages/django/template/base.py", line 1005, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/home/<user>/.local/lib/python3.10/site-packages/django/template/base.py", line 1005, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/home/<user>/.local/lib/python3.10/site-packages/django/template/base.py", line 966, in render_annotated
    return self.render(context)
  File "/home/<user>/.local/lib/python3.10/site-packages/django/template/loader_tags.py", line 208, in render
    return template.render(context)
  File "/home/<user>/.local/lib/python3.10/site-packages/django/template/base.py", line 177, in render
    return self._render(context)
  File "/home/<user>/.local/lib/python3.10/site-packages/django/template/base.py", line 167, in _render
    return self.nodelist.render(context)
  File "/home/<user>/.local/lib/python3.10/site-packages/django/template/base.py", line 1005, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/home/<user>/.local/lib/python3.10/site-packages/django/template/base.py", line 1005, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/home/<user>/.local/lib/python3.10/site-packages/django/template/base.py", line 966, in render_annotated
    return self.render(context)
  File "/home/<user>/.local/lib/python3.10/site-packages/django/template/defaulttags.py", line 472, in render
    url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app)
  File "/home/<user>/.local/lib/python3.10/site-packages/django/urls/base.py", line 88, in reverse
    return resolver._reverse_with_prefix(view, prefix, *args, **kwargs)
  File "/home/<user>/.local/lib/python3.10/site-packages/django/urls/resolvers.py", line 828, in _reverse_with_prefix
    raise NoReverseMatch(msg)
django.urls.exceptions.NoReverseMatch: Reverse for 'home' with no arguments not found. 1 pattern(s) tried: ['(?P<slug>[^/]+)/\\Z']

Here is the problematic urls.py:

from django.contrib import admin
from django.urls import path, include
from .views import PageView 

app_name= 'landings'

urlpatterns = [
   path('<str:slug>/', PageView.as_view(),name='home'),
]

I realize there is a lot wrong with the above. As you can see in my models below, the slug variable is dynamic and can have different strings interpolated depending on what data the Admin Dashboard user enters for the app. So the problem with the urls.py above is that the name parameter has a statically declared string called: ’home’. I get that much. For my web app, I need name to change every time Django makes a pass when calling that particular path() function in the urlpatterns list variable.

I would think that the veterans on this message board will laugh at my efforts outlined below, but now I am going to share all the different path() function alternatives I have tried so far:

   path('<str:slug>/', PageView.as_view(),name='home'),
   path('<str:slug>/', PageView.as_view(),name='about'),
   path('<str:slug>/', PageView.as_view(),name='podcasts'),
   path('<str:slug>/', PageView.as_view(),name='contact'),

The above didn’t work. In my next effort, I tried to leverage f-strings while calling the slug variable by through a reference with the active PageView CBV:

   path('<str:slug>/', PageView.as_view(),name='f{PageView.slug}'),

That didn’t work. In my final effort I tried importing the class model at the top and refer to the slug that way also with an f-string:

from .models import PageContent
...
    path('<str:slug>/', PageView.as_view(),name='f{PageContent.slug}'),

No dice.

What follows are all the other relevant samples from my codebase.

_navbar.html partial:

{% load static %}


<!-- Header Section -->
<header class="header">
   <div class="container container--narrow">
       <a href="{% url 'landings:home' %}" class="header__logo">
           <img src="Toronto_Thelema_static_image_needed_here" alt="DevSearch Logo" />
       </a>


       <nav class="header__nav">
           <input type="checkbox" id="responsive-menu" />
           <label for="responsive-menu" class="toggle-menu">
               <span>Menu</span>
               <div class="toggle-menu__lines"></div>
           </label>
           <ul class="header__menu">
               <li class="header__menuItem"><a href="/">Home</a></li>
               <li class="header__menuItem"><a href="{% url 'landings:about' %}">About</a></li> 
               <li class="header__menuItem"><a href="{% url 'landings:podcasts' %}">Podcasts</a></li>
               <li class="header__menuItem"><a href="{% url 'articles:article_listing' %}">Articles</a></li>          
               <li class="header__menuItem"><a href="{% url 'landings:contact' %}">Contact</a></li>       
           </ul>
       </nav>
   </div>
</header>

models.py:

from django.db import models
from ckeditor.fields import RichTextField




class PageContent(models.Model):
   slug = models.SlugField(null=False, unique=True, blank=True)
   page_type = models.CharField(max_length=20)
   body = RichTextField(config_name='default',max_length=300000,blank=True, null=True)


   def __str__(self):
       return f'{self.page_type}'

views.py:

from django.shortcuts import render, reverse
from django.views.generic import DetailView # TemplateView
from .models import PageContent 


class PageView(DetailView):
   model = PageContent
   template_name = "landings/page_detail.html"
   context_object_name = 'contents'

When you are going to reverse a url like this, you need to pass it a parameter.

So for example, using the url tag, you would need to do something like this:
{% url 'home' 'home' %}. The first 'home' is to match the url name, the second is the parameter for the slug.