Module-1-L6. the Basics of Dynamic Web Pages
Module-1-L6. the Basics of Dynamic Web Pages
This simple example doesn’t involve a database or any sort of user input—just the
output of your server’s internal clock.
Your First View: Dynamic Content
To create this page, we’ll write a view function.
A view function, or view for short, is simply a Python function that takes a Web request
and returns a Web response.
This response can be the HTML contents of a Web page, or a redirect, or a 404 error, or
an XML document, or an image . . . or anything, really.
The view itself contains whatever arbitrary logic is necessary to return that response.
This code can live anywhere you want, as long as it’s on your Python path.
There’s no other requirement—no “magic,” so to speak.
For the sake of putting the code somewhere, let’s create a file called views.py in the
mysite directory.
Your First View: Dynamic Content
File: views.py
from django.http import HttpResponse
import datetime
def current_datetime(request):
now = datetime.datetime.now()
return HttpResponse(html)
Your First View: Dynamic Content
First, we import the class HttpResponse, which lives in the django.http module.
Then we import the datetime module from Python’s standard library, the set of useful
modules that comes with Python.
The datetime module contains several functions and classes for dealing with dates and
times, including a function that returns the current time.
Next, we define a function called current_datetime.
This is the view function.
Each view function takes an HttpRequest object as its first parameter, which is typically
named request.
Your First View: Dynamic Content
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.
How Django finds this function.
The first line of code within the function calculates the current date/time as a
datetime.datetime object, and stores that as the local variable now.
The second line of code within the function constructs an HTML response using
Python’s format-string capability.
The %s within the string is a placeholder, and the percent sign after the string means
“Replace the %s with the value of the variable now.”
Finally, the view returns an HttpResponse object that contains the generated response.
Each view function is responsible for returning an HttpResponse object.
Mapping URLs to Views
So, to recap, this view function returns an HTML page that includes the current date
and time.
But how do we tell Django to use this code? That’s where URLconfs come in.
A URLconf is like a table of contents for your Django-powered Web site.
Basically, it’s a mapping between URL patterns and the view functions that should be
called for those URL patterns.
It’s how you tell Django, “For this URL, call this code, and for that URL, call that
code.”
Remember that the view functions need to be on the Python path.
Mapping URLs to Views
When you executed django-admin.py startproject in the previous chapter, the script
created a URLconf for you automatically: the file urls.py.
Let’s edit that file.
By default, it looks something like this:
from django.conf.urls.defaults import *
urlpatterns = patterns('',
# Example:
# (r'^mysite/', include('mysite.apps.foo.urls.foo')),
# Uncomment this for admin:
# (r'^admin/', include('django.contrib.admin.urls')),
)
✘ from django.urls import re_path
✘ from exp3.views import current_datetime
✘ urlpatterns = [re_path(r'^time/$', current_datetime)]
Mapping URLs to Views
Let’s edit this file to expose our current_datetime view:
from django.conf.urls.defaults import *
from mysite.views import current_datetime
urlpatterns = patterns('',
(r'^time/$', current_datetime),)
First, we imported the current_datetime view from its module (mysite/views.py, which
translates into mysite.views in Python import syntax).
Next, we added the line (r'^time/$', current_datetime),.
This line is referred to as a URLpattern—it’s a Python tuple in which the first
element is a simple regular expression and the second element is the view function to
use for that pattern.
Mapping URLs to Views
At first glance, this may seem odd, but URLconfs can be included in other URLconfs,
and leaving off the leading slash simplifies matters.
The caret character (^) and dollar sign character ($) are important.
The caret means “require that the pattern matches the start of the string,” and the dollar
sign means “require that the pattern matches the end of the string.”
How Django Processes a Request
What goes on when you run the Django development server and make requests to Web
pages:
• The command python manage.py runserver imports a file called settings.py from the
same directory.
This file contains all sorts of optional configuration for this particular Django instance,
but one of the most important settings is ROOT_URLCONF.
The ROOT_URLCONF setting tells Django which Python module should be used as
the URLconf for this Web site.
Remember when django-admin.py startproject created the files settings.py and urls.py?
Well, the autogenerated settings.py has a ROOT_URLCONF that points to the
autogenerated urls.py.
How Django Processes a Request
• When a request comes in—say, a request to the URL /time/—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 an HttpRequest object as the first parameter to the function.
• The view function is responsible for returning an HttpResponse object.
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.
You might think it would be slow to map URLs to functions using a series of regular
expressions, but you’d be surprised.
How Django Processes a Request:
Complete Details
In addition to the straightforward URL-to-view mapping just described, Django
provides quite a bit of flexibility in processing requests.
The typical flow—URLconf resolution to a view function that returns an
HttpResponse—can be short-circuited or augmented via middleware.
How Django Processes a Request:
Complete Details
When an HTTP request comes in from the browser, a server-specific handler constructs
the HttpRequest passed to later components and handles the flow of the response
processing.
The handler then calls any available Request or View middleware.
These types of middleware are useful for augmenting incoming HttpRequest objects as
well as providing special handling for specific types of requests.
If either returns an HttpResponse, processing bypasses the view.
Bugs slip by even the best programmers, but exception middleware can help squash
them.
If a view function raises an exception, control passes to the exception middleware. If
this middleware does not return an HttpResponse, the exception is reraised.
Even then, all is not lost. Django includes default views that create a friendly 404 and
500 response.
Finally, response middleware is good for postprocessing an HttpResponse just before
it’s sent to the browser or doing cleanup of request-specific resources.
URLconfs and Loose Coupling
Now’s a good time to highlight a key philosophy behind URLconfs and behind Django
in general: the principle of loose coupling.
Simply put, loose coupling is a software-development approach that values the
importance of making pieces interchangeable.
If two pieces of code are loosely coupled, then changes made to one of the pieces will
have little or no effect on the other.
Django’s URLconfs are a good example of this principle in practice.
In a Django Web application, the URL definitions and the view functions they call are
loosely coupled; that is, the decision of what the URL should be for a given function,
and the implementation of the function itself, reside in two separate places.
In contrast, other Web development platforms couple the URL to the program. In
typical PHP (http://www.php.net/) applications, for example, the URL of your
application is designated by where you place the code on your filesystem.
URLconfs and Loose Coupling
For example, consider the view function we wrote earlier, which displays the current
date and time.
If we wanted to change the URL for the application— say, move it from /time/ to
/currenttime/—we could make a quick change to the URLconf, without having to worry
about the underlying implementation of the function.
Similarly, if we wanted to change the view function—altering its logic somehow—we
could do that without affecting the URL to which the function is bound.
Furthermore, if we wanted to expose the current-date functionality at several URLs, we
could easily take care of that by editing the URLconf, without having to touch the view
code.
That’s loose coupling in action.
Your Second View: Dynamic URLs
In our first view example, the contents of the page—the current date/time—were
dynamic, but the URL (/time/) was static.
In most dynamic Web applications, though, a URL contains parameters that influence
the output of the page.
Let’s create a second view that displays the current date and time offset by a certain
number of hours.
The goal is to craft a site in such a way that the page /time/plus/1/ displays the date/time
one hour into the future, the page /time/plus/2/ displays the date/time two hours into the
future and so on.
Your Second View: Dynamic URLs
A novice might think to code a separate view function for each hour offset, which might
result in a URLconf like this:
urlpatterns = patterns('',
(r'^time/$', current_datetime),
(r'^time/plus/1/$', one_hour_ahead),
(r'^time/plus/2/$', two_hours_ahead),
(r'^time/plus/3/$', three_hours_ahead),
(r'^time/plus/4//$', four_hours_ahead),
)
Clearly, this line of thought is flawed. Not only would this result in redundant view
functions, but also the application is fundamentally limited to supporting only the
A Word About Pretty URLs
If you’re experienced in another Web development platform, such as PHP or Java, you
may be thinking,
“Hey, let’s use a query string parameter!”—something like /time/plus?hours=3, in
which the hours would be designated by the hours parameter in the URL’s query string
(the part after the ?).
You can do that with Django (and we’ll tell you how later, if you really must know), but
one of Django’s core philosophies is that URLs should be beautiful.
The URL /time/plus/3/ is far cleaner, simpler, more readable, easier to recite to
somebody aloud and . . . just plain prettier than its query string counterpart.
Pretty URLs are a sign of a quality Web application.
Django’s URLconf system encourages pretty URLs by making it easier to use pretty
Wildcard URLpatterns
Continuing with our hours_ahead example, let’s put a wildcard in the URLpattern.
As we mentioned previously, a URLpattern is a regular expression; hence, we can use
the regular expression pattern \d+ to match one or more digits:
from django.conf.urls.defaults import *
from mysite.views import current_datetime, hours_ahead
urlpatterns = patterns('',
(r'^time/$', current_datetime),
(r'^time/plus/\d+/$', hours_ahead),
)
This URLpattern will match any URL such as /time/plus/2/, /time/plus/25/, or even
/time/plus/100000000000/.
That means we want to allow either one- or two-digit numbers—in regular expression
syntax, that translates into \d{1,2}:
(r'^time/plus/\d{1,2}/$', hours_ahead),
Wildcard URLpatterns
We need a way of passing offset data to the view function, so that we can use a single
view function for any arbitrary hour offset.
We do this by placing parentheses around the data in the URLpattern that we want to
save.
In the case of our example, we want to save whatever number was entered in the URL,
so let’s put parentheses around the \d{1,2}:
(r'^time/plus/(\d{1,2})/$', hours_ahead),
The final URLconf, including our previous current_datetime view, looks like this:
from django.conf.urls.defaults import *
from mysite.views import current_datetime, hours_ahead
urlpatterns = patterns('',
(r'^time/$', current_datetime),
(r'^time/plus/(\d{1,2})/$', hours_ahead),
)
Wildcard URLpatterns
hours_ahead is very similar to the current_datetime view we wrote earlier, with a key
difference: it takes an extra argument, the number of hours of offset.
Add this to views.py:
def hours_ahead(request, offset):
offset = int(offset)
dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
html = "<html><body>In %s hour(s), it will be %s.</body></html>" % (offset, dt)
return HttpResponse(html)
Wildcard URLpatterns
from django.http import HttpResponse
import datetime
def current_datetime(request):
now = datetime.datetime.now()
html = "<html><body>It is now %s.</body></html>" % now
return HttpResponse(html)