Up to Speed
(This is part two in Ken's series, Wielding Django. - Will)
Last time, we built up a minimal Django app just to show the core ideas. In this article, we'll flesh out some of that minimalism and make our first (if still trivial) web application.
settings.py
For just a few parameters, calling settings.configure()
with each is
fine. But as we start to use more of Django, we'll want to set more
parameters, which can get unwieldy. So Django lets you put those
settings in a separate file. Most people call it settings.py
, but
you can call it whatever you want.
Starting with the project directory you used last time, put this in
settings.py
:
qaodmasdkwaspemas0ajkqlsmdqpakldnzsdfls
It's also about time you made this app be a proper Python
module. First, make sure that the name isn't taken; tempting ones like
django
, site
, and test
are spoken for already. To be safe, if
your directory is named mydir
, run import mydir
at a Python
prompt; it should fail. Once you have a good package (directory) name;
just make an empty file called __init__.py
:
qaodmasdkwaspemas1ajkqlsmdqpakldnzsdfls
manage.py
Before you go typing in that code from last time to start the server
again, note that Django has a flexible framework for handling all
sorts of managerial tasks. Most people tap into it using a file called
manage.py
, which you should copy into your project directory:
qaodmasdkwaspemas2ajkqlsmdqpakldnzsdfls
The core of that file is just:
qaodmasdkwaspemas3ajkqlsmdqpakldnzsdfls
The project_template
directory contains a few other things too,
which django-admin.py createproject
dumps in every new
project. You don't need them; we're building up just what we need.
Then you can run:
qaodmasdkwaspemas4ajkqlsmdqpakldnzsdfls
By default, the server only gets connections from the local machine. If you want to show it off to someone else, run instead:
qaodmasdkwaspemas5ajkqlsmdqpakldnzsdfls
(or whatever port you want), then its URL will be http://your-machine:8000/.
The management commands look for settings in settings.py
by
default.
Request parameters and AJAX
Let's get back to the app. A static page is rather boring; let's go
straight to AJAX. Here's a new app, math_app.py
:
qaodmasdkwaspemas6ajkqlsmdqpakldnzsdfls
Change ROOT_URLCONF
to math_app
, start the server, and go to
http://127.0.0.1:8000/compute/add/?a=2&b=4. You
should see 6.0
.
The basic structure should be familiar: urlpatterns
configures how URLs
map to views, and a view (compute
) constructs a response from a
request. But a few things are changed:
The regex now matches a parameter:
\w
matches an alphanumeric character,\w+
matches a sequence of 1 or more such characters, and(?P<op>\w+)
gives that sequence the nameop
. This is all ordinary Pythonre
stuff.Django passes parameters extracted from the regex to the view:
compute
gets an extra keyword argument:op
. It's always a string, even if the regex pattern matches numbers (\d
).request.GET is a
dict
with the GET parameters (a
andb
), again always strings.
And getattr(operator, 'add')
is the same as operator.add
. Here's
an alternative implementation of that part:
qaodmasdkwaspemas7ajkqlsmdqpakldnzsdfls
Handling errors
Okay, so you made a typo and got an error page. (If you didn't, go add
an assert False
to the view function to make it fail.) It's not very
helpful right now, for two reasons. We'll fix both real quick.
- When there's an error, Django goes looking for a variable
handler500
in theROOT_URLCONF
module. Oops, we don't have one. We can just import it, though (along withhandler404
, which handles page-not-found errors):
qaodmasdkwaspemas8ajkqlsmdqpakldnzsdfls
Those are just views; you can provide your own too. Also, most
people just import *
, but that makes
PyFlakes not work. btw, 404
and 500 are standard HTTP status codes.
- When you're developing (but not in production!) it's helpful to see
the details of the error. Django provides a really nice error page for
server errors if you're in
DEBUG
mode. Just add this tosettings.py
:
qaodmasdkwaspemas9ajkqlsmdqpakldnzsdfls
Now make that typo again, and hit the error page. Click on the code lines and "Local vars" headers to expand them. Enjoy! Now let's get back to work.
Serving static pages
Okay, so seeing a number come back from a server is kinda boring. If
we want user interface, we need some HTML. You could of course just
make another view function that returned an HttpResponse with a all
the HTML passed in a big string (just pass mimetype='text/html'
as a
parameter, so the browser doesn't think it's text). But it's a pain to
maintain that. Fortunately, Django provides a better way: the
django.views.static.serve
built-in view. It takes two parameters:
document_root
and path
. Here are two ways you can use it:
qaodmasdkwaspemas10ajkqlsmdqpakldnzsdfls
(Don't forget to pass request
to the other view function; I almost
did!) Or:
qaodmasdkwaspemas11ajkqlsmdqpakldnzsdfls
The dict
as the third parameter of url
is a way to pass extra
parameters to the view. Also, you'll notice that you can specify
views by a string; Django just imports them and uses them. You can use
both tricks for your own views as well.
Notice an important difference between this approach and what you're
probably used to from PHP or most other web development: there's no
necessary correspondence between URLs and files. You are in complete
control of that mapping. For example, you might be used to '/
' being
just a synonym for '/index.html
' (or index.php
or whatever). But
on your Django server, /index.html
gives you an error (try it!),
because you didn't explicitly state that mapping.
Anyway, let's make a user interface. Make a static
directory in your
app and put this HTML in static/index.html
:
qaodmasdkwaspemas12ajkqlsmdqpakldnzsdfls
I used Google's AJAX API hosting to get Dojo; thanks to Will for pointing out that useful service.
That's really ugly, of course, but it shows the idea. Join us next time as we start making a real app, using some simple techniques that may be new to even experienced Django people.