Build a blog with Django: Add a home page

Our first task will be to get rid of the "Welcome to Django" message that displays as the home page. As stated in the message, Django only shows it because you have DEBUG = True in your Django settings file and you haven't configured any URLs.

Let's dig deeper and really understand why the page shows and then we'd fix it.

Note: We're starting with the code from where we left off in this post. And, here's a link to the code up to that point.

When you navigate to http://127.0.0.1:8000/ a bunch of stuff happens. Here are the important things to note:

  1. Django determines the root URLconf. In this case it is given by the ROOT_URLCONF setting in src/yaba/settings.py, see here. It's 'yaba.urls'. Note how it's written as a string representing the full Python import path to your URLconf.
  2. Django locates the module-level variable urlpatterns in the root URLconf, i.e. src/yaba/urls.py, see here. It runs through each URL pattern, in order, and stops at the first one that matches the requested URL.
  3. Since no pattern matches, Django raises a subclass of the Http404 exception, see here.
  4. Since DEBUG = True, Django handles the exception by displaying the welcome message, see here, here and here.

Let's fix it.

Prepare the workspace

Firstly, go to the Trello board for your project and move the card that tracks the "Add a home page" task from Todo to In Progress.

Note: We talked about how we'd be using Trello here.

Add a home page is in progress

Secondly, let's set up our git branches.

All the work we'll do will be based off a new branch we're calling dev.

Note: We'd only merge production ready code to master.

$ cd /path/to/yaba

# Create a new branch called dev based off master
$ git branch dev master

However, while working on a specific feature we'd create a new branch for each one and work on them in that branch. These types of branches are usually called feature/topic branches.

Let's create and switch to one now.

$ git checkout -b add-home-page dev

That command creates and switches to a new branch based off dev called add-home-page.

$ git branch
* add-home-page
  dev
  master

Lastly, let's activate the virtual environment.

$ . venv/bin/activate

Add a home page

We want that when we navigate to http://127.0.0.1:8000/ that we see a custom home page.

Open src/yaba/urls.py and add a view and a URL pattern.

from django.conf.urls import url  
from django.contrib import admin  
from django.http import HttpResponse


def home(request):  
    return HttpResponse('Hello, world!')


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

In its simplest form a view is just a Python function that takes a request (an instance of HttpRequest) and returns a response (an instance of HttpResponse).

The home function above satisfies those requirements.

The newly added URL pattern uses the regular expression, r'^$', to match the empty string and map it to the home view.

Why the empty string? I'm glad you asked :).

Django searches against the requested URL, as a normal Python string. This does not include GET or POST parameters, the domain name or the port.

So, in a request to http://127.0.0.1:8000/, Django will look for '', i.e. the empty string. If the request was to http://127.0.0.1:8000/foo/ then it would look for 'foo/'.

Start up the server and navigate to http://127.0.0.1:8000/ to see the result.

(venv) $ python src/manage.py runserver

A custom home page displaying a greeting

Great! We've accomplished our goal but we're not quite done yet.

A little about coding conventions

According to the Wikipedia article on coding conventions,

Coding conventions are a set of guidelines for a specific programming language that recommend programming style, practices, and methods for each aspect of a program written in that language. These conventions usually cover file organization, indentation, comments, declarations, statements, white space, naming conventions, programming practices, programming principles, programming rules of thumb, architectural best practices, etc.

Django, although not a programming language, also has coding conventions of its own. I won't list them here but rather point them out to you as we go along.

The importance of code conventions:

Code conventions are important to programmers for a number of reasons:

  • 40%–80% of the lifetime cost of a piece of software goes to maintenance.
  • Hardly any software is maintained for its whole life by the original author.
  • Code conventions improve the readability of the software, allowing engineers to understand new code more quickly and thoroughly.
  • If you ship your source code as a product, you need to make sure it is as well packaged and clean as any other product you create.

Put views in views.py

One convention is to put your views in their own file, usually called views.py. When working on your views you usually don't want to see or think about the URL mapping code or any other unrelated code for that matter. It also helps other developers to quickly find your views since they'd expect them to be in a views.py file.

Create a views.py in src/yaba and edit it to contain:

from django.http import HttpResponse


def home(request):  
    return HttpResponse('Hello, world!')

Now we need access to the view in src/yaba/urls.py. Edit that to contain:

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

from . import views


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

This is much better.

Valid HTML

Let's look at what's returned when we access the page through curl.

$ curl http://127.0.0.1:8000/
Hello, world!  

Notice that there's no doctype, no html, head or body tags. Only, "Hello, world!". Django doesn't add that stuff for us. If we want valid HTML then we have to write it ourselves.

Here's one way to get what we want:

home_html = '''<!DOCTYPE html>  
<html lang="en">  
  <head>
    <meta charset="utf-8">
    <title>Yet Another Blog</title>
  </head>
  <body>
    <p>Hello, world!</p>
  </body>
</html>  
'''


def home(response):  
    return HttpResponse(home_html)

And here's the curl output now:

$ curl http://127.0.0.1:8000/
<!DOCTYPE html>  
<html lang="en">  
  <head>
    <meta charset="utf-8">
    <title>Yet Another Blog</title>
  </head>
  <body>
    <p>Hello, world!</p>
  </body>
</html>  

Much better.

However, as you might imagine, writing huge chunks of HTML in your code like that is frowned upon :(.

The kosher way is to use templates but we'd leave that for another time.

Let's wrap up.

Wrapping up

Stop the server and commit the changes.

$ git add .
$ git commit -m "Add a home page"

We're done with this feature so let's merge it into the dev branch.

$ git checkout dev
$ git merge add-home-page

You may delete the feature branch if you so desire.

$ git branch -d add-home-page

Finally, go back to your Trello board and move the "Add a home page" card from In Progress to Done.

Add a home page is done

For your reference, here's a diff of all the work we did in this post: yaba/add-home-page.

Conclusion

The overall goal was to add our own home page. First we took the time to understand how Django rendered a view when we accessed a given URL.

Using that knowledge we added our own view in the simplest way possible.

However, that caused us to get a mini lecture on coding conventions.

So we refactored the code to follow the Django convention of placing views in their own file.

After inspecting the content returned for the page we noticed that we weren't returning valid HTML and so we fixed it by updating the response.

We didn't write much code but a lot of important concepts were discussed.

Hopefully you learned a few new things.

P.S. What did you learn? Am I teaching too many ideas at once? Do I need to slow down or speed up? Let me know in the comments below.