Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Tutorial: unexplained 404 error after completing first page

Tags:

python

django

I finished https://docs.djangoproject.com/en/1.9/intro/tutorial01/

The intended behaviour works. My polls index is showing. But there is one unintended consequence that I don't understand. When I go to localhost:8000 I get a page not found. Why?

This is my mysite/mysite/urls.py as the tutorial explained.

from django.conf.urls import include, url
from django.contrib import admin

urlpatterns = [
    url(r'^polls/', include('polls.urls')),
    url(r'^admin/', admin.site.urls),
]

The server says:

Not Found: /
[11/Feb/2016 04:25:46] "GET / HTTP/1.1" 404 2010

When I delete the polls line, the 404 disappears. I.e.:

from django.conf.urls import include, url
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
]

Now the server says:

Not Found: /
[11/Feb/2016 04:24:23] "GET / HTTP/1.1" 200 1767

So I guess it is some default quirk but I still don't fully know if I am making a mistake or if this is defined behaviour. My other code is the same as in the code snippets of the tutorial.

like image 401
Melvin Roest Avatar asked Mar 14 '23 08:03

Melvin Roest


2 Answers

The tutorial does not define what will happen when you go to your site root, it only deals with the polls app. You have to add a url mapping if you want to see something when you browse to http://localhost:8080/.

As a simple example, try making the following changes in your mysite/urls.py:

from polls import views

urlpatterns = [
    url(r'^$', views.index, name='site_index'),
    ...
]

From now on you should see the index view of polls app when you browse to your site root.

like image 34
Selcuk Avatar answered Apr 08 '23 16:04

Selcuk


Interesting observation! Never noticed that before.

When you access a URL, Django tries to match it with the all the defined patterns (in the order of definition). For the first pattern it matches, the corresponding view will be called.

But if there is no URL pattern defined, then django will print Not found: {url} that you see in the runserver shell. And it will try to raise 404 exception, as expected.

But in the debug mode, it does a bit extra. Let's examine this function in django/views/debug.py:

def technical_404_response(request, exception):
    # some extra code here
    if (not tried                           # empty URLconf
        or (request.path == '/'
            and len(tried) == 1             # default URLconf
            and len(tried[0]) == 1
            and getattr(tried[0][0], 'app_name', '') == getattr(tried[0][0], 'namespace', '') == 'admin')):
        return default_urlconf(request)
    # more extra code here

What Django tries to do here is check how many URL patterns it tried. If specific conditions meet, it will try to return through the default_urlconf. These specific conditions are:

  • if there is no URL pattern defined
  • if the tried URL is '/', and the only URL pattern defined is for the admin app

So what we learn from here that if no URL pattern is defined, then Django will always call the default_urlconf. Try deleting the admin URLs also, and then access any random URL. You will always get something like this:

Not Found: /random/url/
[11/Feb/2016 04:24:23] "GET /random/url/ HTTP/1.1" 200 1767

Now let us look at the default_urlconf code:

def default_urlconf(request):
    "Create an empty URLconf 404 error response."
    t = DEBUG_ENGINE.from_string(DEFAULT_URLCONF_TEMPLATE)
    c = Context({
        "title": _("Welcome to Django"),
        "heading": _("It worked!"),
        "subheading": _("Congratulations on your first Django-powered page."),
        "instructions": _("Of course, you haven't actually done any work yet. "
            "Next, start your first app by running <code>python manage.py startapp [app_label]</code>."),
        "explanation": _("You're seeing this message because you have <code>DEBUG = True</code> in your "
            "Django settings file and you haven't configured any URLs. Get to work!"),
    })

    return HttpResponse(t.render(c), content_type='text/html')

(It returns a proper HttpResponse => 200 HTTP code)

like image 58
jatinderjit Avatar answered Apr 08 '23 16:04

jatinderjit