Your First View
Project Files
The following code examples assume you have created your project and app files with the startproject
and startapp
utilities. It’s recommended you use this default structure throughout the book so your code matches the examples. Also note, the code in this book was written in Django 3.0, so the default file contents may be slightly different if you are using Django 2.2 or a later version of Django 3.
To create our first view, we need to modify the views.py
file in our events
app (changes in bold):
# \myclub_root\events\views.py
1 from django.shortcuts import render
2 from django.http import HttpResponse
3
4 def index(request):
5 return HttpResponse("<h1>MyClub Event Calendar</h1>")
Let’s examine this code closely:
- Line 1. Import the
render()
method.startapp
adds this line to the file automatically.render()
is used when rendering templates, which we will cover in Chapter 6. - Line 2. We import the
HttpResponse
method. HTTP, the communication protocol used by all web browsers, uses request and response objects to pass data to and from your app and the browser. We need a response object to pass view information back to the browser. We cover request and response objects in Chapter 10. - Lines 4 and 5. This is your view function. It’s an example of a function-based view. It takes a request from your web browser and returns a response. In this simple case, it’s just a line of text formatted as an HTML heading.
Configuring the URLs
If you started the development server now, you would notice it still displays the welcome page. For Django to use your new view, you need to tell Django the index
view is the view you want to display when someone navigates to the site root (home page). We do this by configuring our URLs.
In Django, the path()
function is used to configure URLs. In its basic form, the path()
function has a very simple syntax:
path(route, view)
A practical example of the basic path()
function would be:
path('mypage/', views.myview)
In this example, a request to http://example.com/mypage
would route to the myview
function in the application’s views.py
file. Don’t worry if this is a bit confusing now; it will make a lot more sense once you have written more views.
The path()
function also takes an optional name
argument, and zero or more keyword arguments passed as a Python dictionary. We will get to these more advanced options later in the book.
The path()
function statements live in a special file called urls.py
.
When startproject
created our website, it created a urls.py
file in our site folder (\myclub_site\urls.py
). This is the correct place for site-wide navigation, but is rarely a good place to put URLs relating to individual applications. Not only is having all our URLs in the one file more complex and less portable, but it can lead to strange behavior if two applications use a view with the same name.
To solve this problem, we create a new urls.py
file for each application. If you are wondering why startapp
didn’t create the file for us, not all apps have public views accessible via URL. For example, a utility program that performs background tasks would not need a urls.py
file. For this reason, Django lets you decide whether your app needs its own urls.py
file.
First, we need to create a urls.py
file in our events
app (new file):
# \myclub_root\events\urls.py
1 from django.urls import path
2 from . import views
3
4 urlpatterns = [
5 path('', views.index, name='index'),
6 ]
Let’s look at this code closer:
- Line 1 imports the
path()
function. This import is necessary for the URL dispatcher to work and is common to allurls.py
files. - Line 2 imports the local
views.py
file. The dot operator (“.”) in this case is shorthand for the current package, so this is saying “import all views from the current package (events
)”. - Line 4 lists the URL patterns registered for this app. For readability, the list is broken into multiple lines, with one URL pattern per line.
- Line 5 is the actual URL dispatcher:
''
matches an empty string. It will also match the “/” as Django automatically removes the slash. In other words, this matches bothhttp://example.com
andhttp://example.com/
.views.index
points to ourindex
view. I.e., the dot operator is pointing to theindex
view inside theviews.py
file that we imported in line 2.name='index'
. While it’s optional, you should always name your URLs. We name URLs so they can be referred to in code (reverse lookup). URL reversing is common in both templates and views, so you will see several examples as we work through the book.
Now let’s look at the site urls.py
file (changes in bold):
# \myclub_site\urls.py
1 from django.contrib import admin
2 from django.urls import include, path
3
4 urlpatterns = [
5 path('admin/', admin.site.urls),
6 path('', include('events.urls')),
7 ]
We have made two important changes to the file:
- Line 2. We have added the
include()
function to our imports. - Line 6. We have added a new URL dispatcher. In this file, the dispatcher is including the
urls.py
file from theevents
app. The empty string (''
) will match everything after the domain name. This pattern must be the last entry in theurlpatterns
list, otherwise Django’s shortcut logic will switch to theevents
app before trying to match any of the other site URLs.
If you now run the development server and navigate to http://127.0.0.1:8000/
in your browser, you should see a plain, but functioning home page (Figure 5-1).
Figure 5-1: A plain, but functioning homepage for your website.
So What Just Happened?
To better understand how Django works, let’s build on the generic example from Chapter 3 with a concrete example of what Django did to display our home page:
- Our browser sent a message to the Django development server requesting it return content located at the root URL (
http://127.0.0.1:8000/
). - Django then looked for a URL pattern matching the request, by first searching the site level
urls.py
, and then each of the apps for aurls.py
file containing a pattern that matches. - Django checks the first pattern (
admin/
) in our site levelurls.py
which doesn’t match and moves on to the second line in which the empty string (root URL) matches. - The matching pattern includes the
urls.py
from theevents
app. Basically, this include says “go look in theevents
app for a pattern that matches”. - Once in the app-level
urls.py
, the empty string matches again. But this time, the request is sent to theindex
view. - The
index
view then renders our simple HTML message to aHttpResponse
and sends it to the browser. - The browser renders the response and we see our page heading.
Every Django application follows this same basic process each time it receives a request from the browser.