Why is my URL Template Tag Pointing to the Wrong URL?

Hi there!

I got into this issue that I’ve spent hours yesterday trying to understand. I found a fix, but I have no idea how it works!

Summary of the issue:
The URL template tag in my base HTML is being resolved into the unexpected/unwanted URL. The URL tag ‘should’ point to the base (home) page URL (the same page it currently sits on) but its weirdly pointing to another URL (‘/todo/’).

My files:
Currently, I only have 1 app (“demo_app”).

Here’s my project folder’s main urls.py:

urlpatterns = [
    path('admin/', admin.site.urls),
    path("", include("demo_app.urls")),
    path("todo/", include("demo_app.urls"))
]

And here’s my demo_app’s urls.py:

urlpatterns = [
    path("", views.home, name="base"),
    path("todo/", views.todo, name="todo_list")
]

I’m using 2 HTML files in this example, one called “base.html” and another called “toDoList.html” which I don’t even know how it’s getting to.

“base.html”
(has some boiler plate code but im only including the relevant section)

        <ul class="navbar-nav">
          <li class="nav-item active">
            <a class="nav-link" href="{% url 'base' %}">Home</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="#">About</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="#">Contact</a>
          </li>
        </ul>

toDoList.html

{% extends "base.html" %}
{%block title%} The todo list {%endblock%}
{%block content%}
<h1>This is your TODO list</h1>
{%endblock%}

and finally my demo_app.views file:

from django.shortcuts import render, HttpResponse
# Create your views here.
def base(request):
    return render(request, "base.html")

def todo(request):
    return render(request, "toDoList.html")

So what’s exactly happening??
When I kickstart the server and go to the base page (http://127.0.0.1:8000/), the nav-link “Home” which has the template tag {% url ‘base’ %} points to “/todo/” for some bizarre reason. I expect it to point to “/”, the base page, which is the one it sits on. I have no idea how the views.todo function is even being called.

What’s the weird fix that you found?
If I go to my project’s urls.py, and i change the order of the urls to:

urlpatterns = [
    path('admin/', admin.site.urls),
    path("todo/", include("demo_app.urls")),
    path("", include("demo_app.urls"))
]

everything works as expected. How? That’s what I would like to know!!

Thanks a lot in advance!!!

See the docs for the URL dispatcher | Django documentation | Django to understand how Django searches URL patterns.

Side note: one of the causes of this confusion is having two different url patterns including the same url pattern.

You should have only one of these, not both.

I did go through the main section titled “How Django processes a request”

I understand that Django first calls the URLConf file defined in my settings.py. Then, it matches the first url pattern it finds defined, which in my case is “” (the empty string). Then, by using the include function, I’m telling Django to include my demo_app’s urls.py file as a URLConf file. Then, it finds the “” url in my demo_app’s urls.py and called the view.base handler function which returns the base.html. When I open up my browser and request localhost:8000, it returns base.html! Nice!

Here’s what I don’t understand. The base.html file contains a url template tag that points to the url named “base”. The only url named “base” is the empty string “”. However, the template tag mysteriously points to “/todo/” (I found that out by looking at the page source). This is what I don’t get, and I don’t understand why changing the order of my project’s urls.py mysteriously solves it. I would appreciate any help with this

That’s covered down in the section Naming url patterns

That is not an accurate statement.

The root problem is the duplicate includes I mentioned above.

If you expand these includes to show what you’ve defined, it becomes more clear.

What you have effectively created is the following (ignoring the admin):

""  "" , name = "base"
^^ from your root urls.py
    ^^ from demo_app/urls.py

""  "todo/", name = "todo_list"
^^ from your root urls.py
     ^^^^^ from demo_app/urls.py

"todo/" "", name = "base"
 ^^^^^ from your root urls.py
        ^^ from demo_app/urls.py

"todo/" "todo/", name = "todo_list"
 ^^^^^ from your root urls.py
         ^^^^^ from demo_app/urls.py

You have ended up with two pairs of different url patterns with the same name.

1 Like

I know understand how include() works. I know you’re not supposed to reply unless you have something more to mention, but i just wanted to say thank you so much for the help, and I apologize for wasting your time with this beginner issue.

Have a great day!!

No need to apologize, this is why we’re here.

1 Like