In the previous chapter, I explained how to set up a Django project and run the Django development server. In this chapter, you'll learn the basics of creating dynamic web pages with Django.
As our first goal, let's create a web page that outputs that famous example message: Hello World. If you were publishing a simple Hello World web page without a web framework, you'd simply type Hello world
into a text file, call it hello.html
, and upload it to a directory on a web server somewhere. Notice in that process you've specified two key pieces of information about that web page: its contents (the string Hello world
) and its URL (for example, http://www.example.com/hello.html
). With Django, you specify those same two things, but in a different way. The contents of the page are produced by a view function, and the URL is specified in a URLconf. First, let's write our Hello World view function.
Within the mysite
directory that we created in the last chapter, create an empty file called views.py
. This Python module will contain our views for this chapter. Our Hello World view is simple. Here's the entire function, plus import statements, which you should type into the views.py
file:
from django.http import HttpResponse def hello(request): return HttpResponse("Hello world")
Let's step through this code one line at a time:
HttpResponse
, which lives in the django.http
module. We need to import this class because it's used later in our code.hello
-the view function.Each view function takes at least one parameter, called request
by convention. This is an object that contains information about the current web request that has triggered this view, and is an instance of the class django.http.HttpRequest
.
In this example, we don't do anything with request
, but it must be the first parameter of the view nonetheless. Note that the name of the view function doesn't matter; it doesn't have to be named in a certain way in order for Django to recognize it. We're calling it hello
here, because that name clearly indicates the gist of the view, but it could just as well be named hello_wonderful_beautiful_world
, or something equally revolting. The next section, Your First URLconf", will shed light on how Django finds this function.
The function is a simple one-liner: it merely returns an HttpResponse
object that has been instantiated with the text Hello world
.
The main lesson here is this: a view is just a Python function that takes an HttpRequest
as its first parameter and returns an instance of HttpResponse
. In order for a Python function to be a Django view, it must do these two things. (There are exceptions, but we'll get to those later.)
If, at this point, you ran python manage.py runserver
again, you'd still see the Welcome to Django message, with no trace of our Hello World view anywhere. That's because our mysite
project doesn't yet know about the hello
view; we need to tell Django explicitly that we're activating this view at a particular URL. Continuing our previous analogy of publishing static HTML files, at this point we've created the HTML file but haven't uploaded it to a directory on the server yet.
To hook a view function to a particular URL with Django, we use a URLconf. A URLconf is like a table of contents for your Django-powered web site. Basically, it's a mapping between URLs and the view functions that should be called for those URLs. It's how you tell Django, For this URL, call this code, and for that URL, call that code.
For example, when somebody visits the URL /foo/
, call the view function foo_view()
, which lives in the Python module views.py
. When you executed django-admin startproject
in the previous chapter, the script created a URLconf for you automatically: the file urls.py
.
By default, it looks something like this:
"""mysite URL Configuration The urlpatterns list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/1.8/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') Including another URLconf 1. Add an import: from blog import urls as blog_urls 2. Add a URL to urlpatterns: url(r'^blog/', include(blog_urls)) """ from django.conf.urls import include, url from django.contrib import admin urlpatterns = [ url(r'^admin/', include(admin.site.urls)), ]
If we ignore the documentation comments at the top of the file, here's the essence of a URLconf:
from django.conf.urls import include, url from django.contrib import admin urlpatterns = [ url(r'^admin/', include(admin.site.urls)), ]
Let's step through this code one line at a time:
django.conf.urls
module: include
which allows you to include a full Python import path to another URLconf module, and url
which uses a regular expression to pattern match the URL in your browser to a module in your Django project.admin
from the django.contrib
module. This function is called by the include
function to load the URLs for the Django admin site.urlpatterns
-a simple list of url()
instances.The main thing to note here is the variable urlpatterns
, which Django expects to find in your URLconf module. This variable defines the mapping between URLs and the code that handles those URLs. To add a URL and view to the URLconf, just add a mapping between a URL pattern and the view function. Here's how to hook in our hello
view:
from django.conf.urls import include, url from django.contrib import admin from mysite.views import hello urlpatterns = [ url(r'^admin/', include(admin.site.urls)), url(r'^hello/$', hello), ]
We made two changes here:
hello
view from its module-mysite/views.py
, which translates into mysite.views
in Python import syntax. (This assumes mysite/views.py
is on your Python path.)url(r'^hello/$', hello),
to urlpatterns
. This line is referred to as a URLpattern. The url()
function tells Django how to handle the URL that you are configuring. The first argument is a pattern-matching string (a regular expression; more on this in a bit) and the second argument is the view function to use for that pattern. url()
can take other optional arguments as well, which we'll cover in more depth in Chapter 7, Advanced Views and Urlconfs.One more important detail we've introduced here is that r
character in front of the regular expression string. This tells Python that the string is a raw string-its contents should not interpret backslashes.
In normal Python strings, backslashes are used for escaping special characters-such as in the string
, which is a one-character string containing a newline. When you add the r
to make it a raw string, Python does not apply its backslash escaping-so, r'
'
is a two-character string containing a literal backslash and a lowercase n
.
There's a natural collision between Python's usage of backslashes and the backslashes that are found in regular expressions, so it's best practice to use raw strings any time you're defining a regular expression in Django.
In a nutshell, we just told Django that any request to the URL /hello/
should be handled by the hello
view function.
It's worth discussing the syntax of this URLpattern, as it may not be immediately obvious. Although we want to match the URL /hello/
, the pattern looks a bit different than that. Here's why:
/hello/
. At first, this may seem unintuitive, but this requirement simplifies things-such as the inclusion of URLconfs within other URLconfs, which we'll cover in Chapter 7, Advanced Views and URLconfs.This concept is best explained by example. If we had instead used the pattern ^hello/
(without a dollar sign at the end), then any URL starting with /hello/
would match, such as /hello/foo
and /hello/bar
, not just /hello/
.
Similarly, if we had left off the initial caret character (that is, hello/$
), Django would match any URL that ends with hello/
, such as /foo/bar/hello/
.
If we had simply used hello/
, without a caret or dollar sign, then any URL containing hello/
would match, such as /foo/hello/bar
.
Thus, we use both the caret and dollar sign to ensure that only the URL /hello/
matches-nothing more, nothing less. Most of your URLpatterns will start with carets and end with dollar signs, but it's nice to have the flexibility to perform more sophisticated matches.
You may be wondering what happens if someone requests the URL /hello
(that is, without a trailing slash). Because our URLpattern requires a trailing slash, that URL would not match. However, by default, any request to a URL that doesn't match a URLpattern and doesn't end with a slash will be redirected to the same URL with a trailing slash (This is regulated by the APPEND_SLASH
Django setting, which is covered in Appendix D, Settings).
The other thing to note about this URLconf is that we've passed the hello
view function as an object without calling the function. This is a key feature of Python (and other dynamic languages): functions are first-class objects, which means you can pass them around just like any other variables. Cool stuff, eh?
To test our changes to the URLconf, start the Django development server, as you did in Chapter 1, Introduction to Django and Getting Started, by running the command python manage.py runserver
. (If you left it running, that's fine, too. The development server automatically detects changes to your Python code and reloads as necessary, so you don't have to restart the server between changes.) The server is running at the address http://127.0.0.1:8000/
, so open up a web browser and go to http://127.0.0.1:8000/hello/
. You should see the text Hello World-the output of your Django view (Figure 2.1).
Figure 2.1: Hooray! Your first Django view
Regular expressions (or regexes) are a compact way of specifying patterns in text. While Django URLconfs allow arbitrary regexes for powerful URL matching, you'll probably only use a few regex symbols in practice. Table 2.1 lists a selection of common symbols.
Table 2.1: Common regex symbols
Symbol |
Matches |
|
Any single character |
|
Any single digit |
|
Any character between |
|
Any character between |
|
Any character between |
|
One or more of the previous expression (for example, |
|
One or more characters until (and not including) a forward slash |
|
Zero or one of the previous expression (for example, |
|
Zero or more of the previous expression (for example, |
|
Between one and three (inclusive) of the previous expression (for example, |
For more on regular expressions, see the Python regex documentation, visit https://docs.python.org/3.4/library/re.html.
At this point, our URLconf defines only a single URLpattern: the one that handles requests to the URL /hello/
. What happens when you request a different URL? To find out, try running the Django development server and visiting a page such as http://127.0.0.1:8000/goodbye/
.
You should see a Page not found message (Figure 2.2). Django displays this message because you requested a URL that's not defined in your URLconf.
Figure 2.2: Django's 404 page
The utility of this page goes beyond the basic 404 error message. It also tells you precisely which URLconf Django used and every pattern in that URLconf. From that information, you should be able to tell why the requested URL threw a 404.
Naturally, this is sensitive information intended only for you, the web developer. If this were a production site deployed live on the Internet, you wouldn't want to expose that information to the public. For that reason, this Page not found page is only displayed if your Django project is in debug mode.
I'll explain how to deactivate debug mode later. For now, just know that every Django project is in debug mode when you first create it, and if the project is not in debug mode, Django outputs a different 404 response.
As explained in the last section, you'll see a 404 error message if you view the site root-http://127.0.0.1:8000/
. Django doesn't magically add anything to the site root; that URL is not special-cased in any way.
It's up to you to assign it to a URLpattern, just like every other entry in your URLconf. The URLpattern to match the site root is a bit unintuitive, though, so it's worth mentioning.
When you're ready to implement a view for the site root, use the URLpattern ^$
, which matches an empty string. For example:
from mysite.views import hello, my_homepage_view urlpatterns = [ url(r'^$', my_homepage_view), # ...
Before continuing to our second view function, let's pause to learn a little more about how Django works. Specifically, when you view your Hello World message by visiting http://127.0.0.1:8000/hello/
in your web browser, what does Django do behind the scenes? It all starts with the settings file.
When you run python manage.py runserver
, the script looks for a file called settings.py
in the inner mysite
directory. This file contains all sorts of configuration for this particular Django project, all in uppercase: TEMPLATE_DIRS
, DATABASES
, and so on. The most important setting is called ROOT_URLCONF
. ROOT_URLCONF
tells Django which Python module should be used as the URLconf for this web site.
Remember when django-admin startproject
created the files settings.py
and urls.py
? The auto-generated settings.py
contains a ROOT_URLCONF
setting that points to the auto-generated urls.py
. Open the settings.py
file and see for yourself; it should look like this:
ROOT_URLCONF = 'mysite.urls'
This corresponds to the file mysite/urls.py
. When a request comes in for a particular URL-say, a request for /hello/
-Django loads the URLconf pointed to by the ROOT_URLCONF
setting. Then it checks each of the URLpatterns in that URLconf, in order, comparing the requested URL with the patterns one at a time, until it finds one that matches.
When it finds one that matches, it calls the view function associated with that pattern, passing it an HttpRequest
object as the first parameter. (We'll cover the specifics of HttpRequest
later.) As we saw in our first view example, a view function must return an HttpResponse
.
Once it does this, Django does the rest, converting the Python object to a proper web response with the appropriate HTTP headers and body (that is, the content of the web page). In summary:
/hello/
.ROOT_URLCONF
setting./hello/
.HttpResponse
.HttpResponse
to the proper HTTP response, which results in a web page.You now know the basics of how to make Django-powered pages. It's quite simple, really just write view functions and map them to URLs via URLconfs.