# Top level home page routing for CBV-based website - - how to configure the urls.py properly?

**URL:** <https://forum.djangoproject.com/t/top-level-home-page-routing-for-cbv-based-website-how-to-configure-the-urls-py-properly/19275>\
**Category:** Forms & APIs\
**Created:** [March 5, 2023, 10:40am UTC](https://forum.djangoproject.com/t/top-level-home-page-routing-for-cbv-based-website-how-to-configure-the-urls-py-properly/19275 "2023-03-05T10:40:49Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Drone4four](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/drone4four/32/3072_2.png) [@Drone4four](https://forum.djangoproject.com/u/Drone4four)\
**Post date:** [March 5, 2023, 10:40am UTC](https://forum.djangoproject.com/t/top-level-home-page-routing-for-cbv-based-website-how-to-configure-the-urls-py-properly/19275/1 "2023-03-05T10:40:49Z")

</div>

Greetings Pythonistas!

I’m writing a Django CMS for a low traffic philosophy society. It’s like a blog.

I’m building the navbar and url navigation. I’m using a DetailView CBV and a single template to handle these four basic pages:

- Home
- About
- Podcasts
- Contact

Pretty standard website layout / usecase. When a web visitor clicks on one of those list items from the navigation menu, the urls.py successfully routes the visitor to the right corresponding addresses such as:

- `http://localhost:8000/home`
- `http://localhost:8000/about`
- `http://localhost:8000/podcasts`
- `http://localhost:8000/contact`

So far so good.

My goal is to have Django serve the home page at the top level parent address `http://localhost:8000/` without the “home” slug at the end (suffix). But right now, when I navigate to `http://localhost:8000/`, Django serves a 404 and I can’t wrap my head around how to reconfigure my two urls.py to accomplish this desired outcome.

Here is my web app’s urls.py:

```auto
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'),
]

```

In the past, what I normally would do, for the first `path()` argument, I’d substitute an empty string like it appears here: `path('', views.home, name='home')`.Notice the empty string as fthe first paramer. So I tried placing this line - - `path('', PageView.as_view(),name='home')` - - above the path() in the code snippet above but then Django throws an “AttributeError at / Generic detail view PageView must be called with either an object pk or a slug in the URLconf.” So that isn’t working in this case since I am exploring this new CBV approach to generate pages.

What do I need to change in my urls.py above (or any of my other project files below) to get Django to serve the home page at the top level address without a “/home” suffix appended to the end of the domain name?

Here is my project urls.py:

```auto
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
   path('admin/', admin.site.urls),
   path('', include('landings.urls')),
   path('articles/', include('articles.urls')),
   path('contributors/', include('contributors.urls')),
]

```

\_navbar.html:

```auto
{% load static %}

<!-- Header Section -->
<header class="header">
   <div class="container container--narrow">
       <a href="{% url 'landings:home' 'home' %}" class="header__logo">
           <img src="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:home' 'about' %}">About</a></li> 
               <li class="header__menuItem"><a href="{% url 'landings:home' 'podcasts' %}">Podcasts</a></li>      
               <li class="header__menuItem"><a href="{% url 'landings:home' 'contact' %}">Contact</a></li>    
           </ul>
       </nav>
   </div>
</header>

```

When clicking the first unordered list menu item hyperlink Home, the traceback in my Django terminal is simply:

```auto
Not Found: /
[05/Mar/2023 10:01:58] "GET / HTTP/1.1" 404 2467

```

The 404 showing in my browser, Django appears to be looking for the page but can’t find it and chokes at this line in my url routing: `<str:slug>/ [name='home']`

template:

```auto
{% extends 'base.html' %}

{% block content %}

   {% if contents %}

      {{ contents.body|safe }}

   {% endif %}

{% endblock %}

```

Here is my concise CBV:

```auto
from django.views.generic import DetailView
from .models import PageContent

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

```

My web app models.py:

```auto
from django.db import models
from ckeditor.fields import RichTextField
# from django.template.defaultfilters import slugify

class PageContent(models.Model):
   # title = models.CharField(max_length=200)
   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}'

```

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [March 5, 2023, 1:14pm UTC](https://forum.djangoproject.com/t/top-level-home-page-routing-for-cbv-based-website-how-to-configure-the-urls-py-properly/19275/2 "2023-03-05T13:14:07Z")

</div>

You can pass arguments to your view function in the url definition. See [URL dispatcher | Django documentation | Django](https://docs.djangoproject.com/en/4.1/topics/http/urls/#passing-extra-options-to-view-functions)

---

<div class="post-metadata">

**Author:** ![Drone4four](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/drone4four/32/3072_2.png) [@Drone4four](https://forum.djangoproject.com/u/Drone4four)\
**Post date:** [April 1, 2023, 11:55am UTC](https://forum.djangoproject.com/t/top-level-home-page-routing-for-cbv-based-website-how-to-configure-the-urls-py-properly/19275/3 "2023-04-01T11:55:20Z")

</div>

Hi Ken. Thanks for the reply.

That doc you shared is instructive. It certainly is relevant. But I struggle with the [metasyntactic placeholder variables](https://en.wikipedia.org/wiki/Metasyntactic_variable) used in their examples. They use `'foo':'bar'` which I find very hard to follow and adapt to my use case.

To renew and clarify my intention (with refreshed context), here is my latest web app’s `path()` line:

```auto
path('the_gate', PageView.as_view(),name='the_gate'),

```

I’ve paired that with this corresponding line in my template:

```auto
<li class="nav-item"><a class="nav-link" href="{% url 'stock_pages:the_gate' %}">Home </a></li>

```

And when I navigate to:

```auto
http://127.0.0.1:8000/the_gate/

```

Django serves the page. But I am trying to get that page to load when the a web visitor navigates to:

```auto
http://127.0.0.1:8000/

```

That’s what I am trying to accomplish. To make it clear, that is my intention.

To that end, based on my reading of the passage in the Django doc that Ken shared, I’ve tried passing in arguments to my `path()` function such as:

```auto
path('', PageView.as_view(),name={"the_gate": "the_gate"}),

```

And:

```auto
path('', PageView.as_view(),name={"": "the_gate"}),

```

As well as:

```auto
path('', PageView.as_view(),name={"the_gate": ""}),

```

In all three cases above (and in the subsequent cases described below), I am experimenting with passing in an empty string to the url. Django returns this error:

```auto
self.view_name = ":".join(self.namespaces + [view_path])
TypeError: sequence item 0: expected str instance, dict found

```

The above is all wrong.

I even tried these combos too:

```auto
path('<str:slug>', PageView.as_view(),name='the_gate'),

```

And:

```auto
path('<str:slug>', PageView.as_view(),name={'the_gate':''}),

```

And:

```auto
path('<str:slug>', PageView.as_view(),name={'the_gate':'the_gate'}),

```

With:

```auto
<li class="nav-item"><a class="nav-link" href="{% url 'stock_pages:the_gate' '' %}">Home </a></li>

```

None of that worked. I tried additional variations of the above.

In the Django doc at the specific passage involving passing extra options to views functions (which uses the same jarring non-descriptive metasyntactic variables again) suggests that the views be called in this way with these parameters:

```auto
views.year_archive(request, year=2005, foo='bar').

```

There the view is function based. In my project I’m using CBVs so that adds to my bewilderment in this case.

Any idea what I could try next? Is there a way to rephrase the advice in the Django docs but with using more meaningful variable nomenclature in the context of a project with more moving parts like the one I am working on (source code below)?

I have made some changes to my source code since my original post. Here are the latest code snippets in play:

Problematic template ( **\_navbar.html** partial):

```auto
...
<li class="nav-item"><a class="nav-link" href="{% url 'stock_pages:the_gate' %}">Home </a></li>
           <li class="nav-item"><a class="nav-link" href="{% url 'stock_pages:switch' 'podcasts' %}">Podcasts </a></li>
           <li class="nav-item"><a class="nav-link" href="{% url 'articles:article_listing' %}">Research </a></li>
           <li class="nav-item"><a class="nav-link" href="{% url 'contributors:writers' %}">Contributors </a></li>
           <li class="nav-item"><a class="nav-link" href="{% url 'stock_pages:switch' 'contact' %}">Contact</a></li>
...

```

Current web app **urls.py** :

```auto
from django.urls import path, include
from .views import PageView

app_name= 'stock_pages'

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

```

Project (parent) **urls.py** :

```auto
from django.contrib import admin
from django.urls import path, include
from django.conf.urls.static import static
from django.conf import settings

urlpatterns = [
   path('admin/', admin.site.urls),
   path('', include('stock_pages.urls')),
   path('articles/', include('articles.urls')),
   path('contributors/', include('contributors.urls')),
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

```

Web app **models.py** :

```auto
from django.db import models
from ckeditor.fields import RichTextField
# from django.template.defaultfilters import slugify

class PageContent(models.Model):
   # title = models.CharField(max_length=200)
   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)
   pure_html_body = models.TextField(blank=True,null=True)

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

```

Web app **views.py** :

```auto
from django.views.generic import DetailView
from .models import PageContent

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

```

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [April 1, 2023, 2:02pm UTC](https://forum.djangoproject.com/t/top-level-home-page-routing-for-cbv-based-website-how-to-configure-the-urls-py-properly/19275/4 "2023-04-01T14:02:11Z")

</div>

Ok, from the docs:

```auto
urlpatterns = [
    path('blog/<int:year>/', views.year_archive, {'foo': 'bar'}),
]

```

First, notice that the parameters dict is not assigned to the `name` parameter, it’s a positional parameter following the url and view.

This line:

```auto
path('blog/<int:year>/', views.year_archive, {'foo': 'bar'}),

```

should be understood in the context of the following text:

> In this example, for a request to `/blog/2005/` , Django will call `views.year_archive(request, year=2005, foo='bar')` .

The `foo` in this case is the name of the parameter - it’s passed to the view in exactly the same way as `year`.

So in your CBV, you would access it as `self.kwargs['foo']` in exactly the same way as you would access the year as `self.kwargs['year']`.

Or to extend this example slightly, they could also write:

```auto
path('blog/', views.year_archive, {'year': 2020, 'foo': 'bar'}),

```

Does this make the docs more clear?

> [@Drone4four](#):
>
> There the view is function based. In my project I’m using CBVs so that adds to my bewilderment in this case.

There is no difference to the url definition whether you are using an FBV or CBV. The structure of a url does not change.

---

<div class="post-metadata">

**Author:** ![Drone4four](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/drone4four/32/3072_2.png) [@Drone4four](https://forum.djangoproject.com/u/Drone4four)\
**Post date:** [April 2, 2023, 4:03am UTC](https://forum.djangoproject.com/t/top-level-home-page-routing-for-cbv-based-website-how-to-configure-the-urls-py-properly/19275/5 "2023-04-02T04:03:35Z")

</div>

Thank you Ken for your feedback so far.

> [@KenWhitesell](#):
>
> First, notice that the parameters dict is not assigned to the `name` parameter, it’s a positional parameter following the url and view.

Good catch and noted.

> [@KenWhitesell](#):
>
> There is no difference to the url definition whether you are using an FBV or CBV. The structure of a url does not change.

You are right that the url structure whether FBV or CBV are the same. But the way the second path parameter in the urls.py conf is different. For example, while:

```auto
views.year_archive(year=2005, foo='bar') 

```

might work for FBVs, those same paramaters won’t work if they are passed in using a CBV in an urls.py such as this:

```auto
views.PageView.as_view(year=2005, foo='bar')

```

That won’t work.

> [@KenWhitesell](#):
>
> Does this make the docs more clear?

The continued discussion involving foo and bar is still a barrier that makes me queasy.

But in terms of the logic and dictionary reference in the path() urlpattern function, I think I have some mew additional insight. I am open to being corrected. Further advice is welcome.

Here is the insight:

Usually the name argument in a `path()` function connects to or serves as a bridge to the string variable that is referred to in a template which in turn tells Django to serve or redirect to the given url. I believe that is accurate. So in my template below, you can see that the reference is `'the_gate'`. Then when a user clicks that link, what is supposed to happen is Django will go looking for the slug, which in my case is generated by an Admin staff member who entered it in one of the content posts, and then Django will redirect to the very top level path on the site: `localhost:8000/` (emphasis: no suffix or post fix). That’s what I am trying to achieve below.

Here is the relevant line in my template:

```auto
<li class="nav-item"><a class="nav-link" href="{% url 'stock_pages:the_gate' %}">Home </a></li>

```

Here is the relevant line in play in my `urls.py`:

```auto
path('', PageView.as_view(),{'the_gate':'the_gate'}),   

```

Here is the traceback:

```auto
Generic detail view PageView must be called with either an object pk or a slug in the URLconf.

```

That error says it needs a slug or pk. I gave it a slug in the key:value pair positional argument (not assigned to `name`). The key ‘the\_gate’ and value ‘the\_gate’ just happen to be the same strings. I tried swapping the quotes on and off with different combinations. No dice.

Also notice in this traceback it is “expecting a slug” presumably as a string inside the first `path()` paramater but this is precisely what I am trying to avoid: I don’t want a string to appear at the end of the top level address. So the first paramater must strictly be an empty string. Django won’t accept that.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [April 2, 2023, 4:32am UTC](https://forum.djangoproject.com/t/top-level-home-page-routing-for-cbv-based-website-how-to-configure-the-urls-py-properly/19275/6 "2023-04-02T04:32:23Z")

</div>

I think you’re trying to connect things that don’t directly connect.

> [@Drone4four](#):
>
> `views.year_archive(year=2005, foo='bar') `

No, actually that would _not_ work in the url definition of an FBV. That would be an improper definition on a couple of different levels. (Well, technically, it _could_ be made to work, but the results aren’t what one typically expects from something like this.)

In the template at:

> [@Drone4four](#):
>
> `{% url 'stock_pages:the_gate' %}`

This is a reference to the `name` attribute of the url.

> [@Drone4four](#):
>
> Then when a user clicks that link, what is supposed to happen is Django will go looking for the slug,

That name gets converted to the referenced url, which is then rendered in the html. This means that if the url is defined as:

> [@Drone4four](#):
>
> `path('the_gate', PageView.as_view(),name='the_gate'),`

Then that anchor tag will be rendered like this:

`<a class="nav-link" href="the_gate">`

Now, the issue with your url is a completely separate topic.

When you define a url as:

> [@Drone4four](#):
>
> ```plaintext
> path('<str:slug>/', PageView.as_view(),name='home'),
> ^^^^ This is the name of the variable accessed by the view, 
> regardless of it being an FBV or CBV
> 
> ```
> 
> The value that that variable named `slug` will be set to, is what is passed in the url.

You have defined:

> [@Drone4four](#):
>
> ```plaintext
> path('', PageView.as_view(),{'the_gate':'the_gate'}), 
> ^^^^^^^^ This is the name of the variable
> ^^^^^^^^ This is the value
>                                             
> 
> ```

Your view is expecting a variable named `slug`. (Actually, the `DetailView` will accept either a `slug` or the `pk` by default.)

You are looking to define the **value** of that variable in the url definition, **not** the variable name itself.

Strictly speaking, the view (again, regardless of being either an FBV or CBV) does not care what the url looks like. It only cares that it receives the parameters named what it expects to receive.

I would strongly encourage you to take the time and dig through the docs and the source code of the generic CBVs to understand how they work.

I also recommend to people the [Classy Class-Based Views](https://ccbv.co.uk/) site along with the [Django Class Based Views Diagrams](https://www.brennantymrak.com/articles/django-class-based-views-diagrams.html) page.

---

<div class="post-metadata">

**Author:** ![Drone4four](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/drone4four/32/3072_2.png) [@Drone4four](https://forum.djangoproject.com/u/Drone4four)\
**Post date:** [April 5, 2023, 7:37am UTC](https://forum.djangoproject.com/t/top-level-home-page-routing-for-cbv-based-website-how-to-configure-the-urls-py-properly/19275/7 "2023-04-05T07:37:05Z")

</div>

> [@KenWhitesell](#):
>
> I would strongly encourage you to take the time and dig through the docs and the source code of the generic CBVs to understand how they work.
> 
> I also recommend to people the [Classy Class-Based Views](https://ccbv.co.uk/) site along with the [Django Class Based Views Diagrams](https://www.brennantymrak.com/articles/django-class-based-views-diagrams.html) page.

I’ve seen these sites before. I should have thought to have checked them out first before writing my last post. Troubleshooting on online forums can be humbling.

Based on what I learned from Classy CBVs, I experimented with building a new separate view that looked like this:

```auto
class HomeView(DetailView):
    model = PageContent
    template_name = "stock_pages/home.html"
    context_object_name = 'contents' 
    slug_field = 'slug'
    slug_url_kwarg = 'my_slug'
    
    def get_object(self, queryset=None):
        """
        Retrieve the object based on the slug instead of the pk.
        """
        slug = self.kwargs.get('slug')
        queryset = self.get_queryset()
        obj = queryset.filter(slug=slug).first()
        return obj

```

I then tried different variable names in my **urls.py** and **template**. After much wrangling, I resolved to writing this basic home-page specific view:

```auto
def home(request):
    contents = PageContent.objects.get(slug='home_page')
    context = {'contents': contents}
    return render(request, 'stock_pages/home.html', context=context)

```

This is my latest path function:

```auto
path ('', views.home, name='home_page'),

```

This works.

In the end I didn’t even have to write a separate model. I just used the existing one so my Admin Dashboard looks clean just as it did before.

I realize this is not best practices because the `home` view above uses a `get()` query meaning that it is hard coded and not dynamic. Alas, I digress.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [April 5, 2023, 11:21am UTC](https://forum.djangoproject.com/t/top-level-home-page-routing-for-cbv-based-website-how-to-configure-the-urls-py-properly/19275/8 "2023-04-05T11:21:02Z")

</div>

> [@Drone4four](#):
>
> This works.

Yep, sure does!

Now, to wrap this back up, you’ve got:

> [@Drone4four](#):
>
> `PageContent.objects.get(slug='home_page')`

combined with:

> [@Drone4four](#):
>
> `path ('', views.home, name='home_page'),`

Would give you:

> [@Drone4four](#):
>
> `path('', PageView.as_view(),{'slug':'the_gate'}), `
