Professional Documents
Culture Documents
Dejan Lukan
evangeline.eleanor@gmail.com
August 3, 2010
1
1 Intoduction
1.1 Creating a project
If this is the first time you’re using django, you have to take care of initial setup (auto-generate some code that
establishes a django project):
# cd t o t h e d i r e c t o r y where you would l i k e t o s t o r e your c o d e
cd <d i r >
# c r e a t e new p r o j e c t
django−admin . py s t a r t p r o j e c t <p r o j e c t n a m e >
If your background is in PHP, you’re probably used to putting code under the web server’s document root
(/var/www/). With django, you don’t do that - it’s not a good idea to put any of this python code wihin your
web server’s document root, because it risks the possibility that people may be able to view your code over the
web. Put your code in some directory outside of the document root.
Startproject created:
−rw−r−−r−− 1 eleanor eleanor 0 Mar 7 15:08 init . py
−rw−r−−r−− 1 eleanor eleanor 546 Mar 7 1 5 : 0 8 manage . py
−rw−r−−r−− 1 eleanor e l e a n o r 2773 Mar 7 1 5 : 0 8 s e t t i n g s . py
−rw−r−−r−− 1 eleanor eleanor 542 Mar 7 1 5 : 0 8 u r l s . py
Explanation:
• init .py: empty file that tells python that this directory should be considered a python package
• manage.py: a command line utility that lets you interact with this django project in various ways
• settings.py: Settings/configuration for this django project
• urls.py: the url declarations for this django project (a table of contents)
Django v e r s i o n 1 . 1 . 1 , using s e t t i n g s ’ e s t u d e n t . s e t t i n g s ’
Development s e r v e r i s r u n n i n g a t h t t p : // 1 2 7 . 0 . 0 . 1 : 8 0 0 0 /
Quit t h e s e r v e r w i t h CONTROL−C .
you’ve started the django development server, a lightweight web server written purely in python (you don’t
have to bother yourself with apache).
If you want to change the server’s ip, pass it along with the port (to listen on public IPs use):
python manage . py r u n s e r v e r 0.0.0.0:8000
1
1.4 Database setup
Edit setings.py:
• DATABASE NAME: the name of your database (if using sqlite the database will be a file in your computer:
a full absolute path. If the file doesn’t exist it will automatically be created when you sync the database for
the first time). If you’re using mysql create the database with ”CREATE DATABASE <database name>.
• DATABASE HOST: the host your database is on (empty string if database is on the same pysical machine
- not used for sqlite)
• INSTALLED APPS: the names of all django applications that are activated in this django instance. By
default it contains these apps:
– django.contrib.auth - an authentication system
– djando.contrib.contenttypes - a framework for content types
– djando.contrib.sessions - a session framework
– django.contrib.sites - a framework for managing multiple sites with one django installation
Each of these applications makes use of at least one database table, so we need to create the tables in the
database before we can use them:
python manage . py syncdb
this looks at the INSTALLED APPS setting and creates any necessary database tables according to the
database settings in your settings.py file.
Each application you write in django consists of a python package, somewhere on your python path. Django
comes with a utility that automatically generates the basic directory structure of an app, so you can focus on
writing code rather than creating directories.
What’s the difference between a project and an app? An app is a Web application that does something –
e.g., a weblog system, a database of public records or a simple poll app. A project is a collection of configura-
tion and apps for a particular Web site. A project can contain multiple apps. An app can be in multiple projects.
To create your app, make sure you’re in the mysite directory and type this:
python manage . py s t a r t a p p <app name>
2
This will create:
−rw−r−−r−− 1 eleanor eleanor 0 Mar 7 15:41 init . py
−rw−r−−r−− 1 eleanor eleanor 57 Mar 7 1 5 : 4 1 models . py
−rw−r−−r−− 1 eleanor e l e a n o r 514 Mar 7 1 5 : 4 1 t e s t s . py
−rw−r−−r−− 1 eleanor eleanor 26 Mar 7 1 5 : 4 1 v i e w s . py
A model is the single, definitive source of data about your data. It contains the essential fields and behaviors
of the data you’re storing. The goal is to define your data model in one place and automatically derive things
from it.
First step in writing a database web app in django is to define your models - your database layout, with
additional metadata. In our simple app, we’ll create two models: polls and choices. Poll has a question and a
publication date, a choice has two fields: the text of the choice and a voite tally.
c l a s s P o l l ( models . Model ) :
q u e s t i o n = models . C h a r F i e l d ( m a x l e n g t h =200)
p u b d a t e = models . D at e Ti meF i el d ( ’ d a t e p u b l i s h e d ’ )
c l a s s C h o i c e ( models . Model ) :
p o l l = models . ForeignKey ( P o l l )
c h o i c e = models . C h a r F i e l d ( m a x l e n g t h =200)
v o t e s = models . I n t e g e r F i e l d ( )
Explanation:
• each model is represented by a class that subclasses django.db.models.Model
• each model has a number of class variables, each of which represents a database field of the model
• each field is represented by an instance of a Field class - CharField for character fields and DateTimeField
for datetimes. This tells django what type of data each field holds.
• the name of each Field instance (question or pub date) is the field’s name. You’ll use this value in your
python code, and your database will use it as the column name.
• some Field classes have required elements. CharField, for example, requires that you give it a max length.
That’s used not only in the database schema, but in validation
• note a relationship is defined, using ForeignKey. That tells Django each Choice is related to a single Poll.
Django supports all the common database relationships: many-to-ones, many-to-manys and one-to-ones
• create a python database access API for accessing Poll and Choice objects
But first we need to tell our project that the polls app is installed. Edit the settings.py file again and change
the INSTALLED APPS setting to include the string estudent.polls:
3
INSTALLED APPS = (
’ django . c o n t r i b . auth ’ ,
’ django . c o n t r i b . contenttypes ’ ,
’ django . c o n t r i b . sessions ’ ,
’ django . c o n t r i b . sites ’ ,
’ estudent . p o l l s ’,
)
The sql command doesn’t actually run the SQL in your database - it just prints it to the screen so that you
can see what SQL Django thinks is required. If you wanted to, you could copy and paste this SQL into your
database prompt. However, as we will see shortly, Django provides an easier way of committing the SQL to the
database.
Also run these commands:
• outputs any custom sql statements that are defined for the application:
$ python manage . py s q l c u s t o m p o l l s
The syncdb command runs the sql from ’sqlall’ on your database for all apps in INSTALLED APPS that don’t
already exist in your database. This creates all the tables, initial data and indexes for any apps you have added
to your project since the last time you ran syncdb. syncdb can be called as often as you like, and it will only
ever create the tables that don’t exist.
4
Now explore the database API:
# i m p o r t t h e model c l a s s e s we j u s t w r o t e
>>> from e s t u d e n t . p o l l s . models i m p o r t P o l l
# no p o l l s a r e i n t h e s y s t e m y e t
>>> P o l l . o b j e c t s . a l l ( )
[]
# c r e a t e a new p o l l
>>> i m p o r t d a t e t i m e
>>> p = P o l l ( q u e s t i o n=”What ’ s up ? ” , p u b d a t e=d a t e t i m e . d a t e t i m e . now ( ) )
# s a v e t h e o b j e c t i n t o t h e d a t a b a s e − i t h as an ID
>>> p . s a v e ( )
>>> p . i d
1
# a c c e s s d a t a b a s e columns v i a python a t t r i b u t e s
>>> p . q u e s t i o n
”What ’ s up ? ”
>>> p . p u b d a t e
datetime . datetime (2010 , 3 , 7 , 9 , 4 , 22 , 674315)
This is unhelpful representation of this object. Edit polls.models.py and add unicode () method to both Poll
and Choice (let’s also add another function):
from d j a n g o . db i m p o r t models
import datetime
c l a s s P o l l ( models . Model ) :
q u e s t i o n = models . C h a r F i e l d ( m a x l e n g t h =200)
p u b d a t e = models . D at e Ti meF i el d ( ’ d a t e p u b l i s h e d ’ )
c l a s s C h o i c e ( models . Model ) :
p o l l = models . ForeignKey ( P o l l )
c h o i c e = models . C h a r F i e l d ( m a x l e n g t h =200)
v o t e s = models . I n t e g e r F i e l d ( )
# database lookups
>>> P o l l . o b j e c t s . f i l t e r ( i d =1)
[< P o l l : What ’ s up? >]
>>> P o l l . o b j e c t s . f i l t e r ( q u e s t i o n s t a r t s w i t h= ’ What ’ )
[< P o l l : What ’ s up? >]
>>> P o l l . o b j e c t s . g e t ( p u b d a t e y e a r =2010)
<P o l l : What ’ s up?>
>>> P o l l . o b j e c t s . g e t ( i d =2)
T r a ceback ( most r e c e n t c a l l l a s t ) :
5
F i l e ”<c o n s o l e >” , l i n e 1 , i n <module>
F i l e ” / u s r / l i b / python2 . 6 / s i t e −p a c k a g e s / d j a n g o /db/ models / manager . py ” , l i n e 1 2 0 , i n g e t
return s e l f . g e t q u e r y s e t ( ) . g e t ( ∗ a r g s , ∗∗ kwargs )
F i l e ” / u s r / l i b / python2 . 6 / s i t e −p a c k a g e s / d j a n g o /db/ models / q u e r y . py ” , l i n e 3 0 5 , i n g e t
% s e l f . model . meta . o b j e c t n a m e )
D o e s N o t E x i s t : P o l l matching q u e r y d o e s not e x i s t .
# P o l l o b j e c t s get a c c e s s to Choice o b j e c t s
>>> p . c h o i c e s e t . a l l ( )
[< C h o i c e : Not much>, <C h o i c e : The sky >, <C h o i c e : J u s t h a c k i n g a g a i n >, <C h o i c e : J u s t h a c k i n g a g a i n >]
>>> p . c h o i c e s e t . c o u n t ( )
4
# d e l e t e one o f t h e c h o i c e s
>>> c = p . c h o i c e s e t . f i l t e r ( c h o i c e s t a r t s w i t h= ’ J u s t h a c k i n g ’ )
>>> c . d e l e t e ( )
• edit estudent/urls.py file and uncomment the lines that reference the admin
We need to tell the admin that Poll objects have an admin interface: create a file called admin.py in your polls
directory and edit it to look like this:
from e s t u d e n t . p o l l s . models i m p o r t P o l l
from d j a n g o . c o n t r i b i m p o r t admin
admin . s i t e . r e g i s t e r ( P o l l )
You’ll need to restart the development server to see your changes. Normally, the server auto-reloads code every
time you modify a file, but the action of creating a new file doesn’t trigger the auto-reloading logic.
By registering the Poll model with admin.site.register(Poll), django was able to construct a default form repre-
sentation. Often you’ll want to customize how the admin form looks and works. You’ll do this by telling django
the options you want when you register the object.
6
Example: replace the admin.site.register(Poll) with:
from e s t u d e n t . p o l l s . models i m p o r t P o l l
from d j a n g o . c o n t r i b i m p o r t admin
admin . s i t e . r e g i s t e r ( P o l l , PollAdmin )
Explanation: create a model admin object, then pass it as the second argument to admin.site.register() - any
time you need to change the admin options for an object. This makes the ”Publication date” come before the
”Question” field. This isn’t impressive with only two fields, but for admin forms with dozens of fields, choosing
an intuitive order is an important usability detail.
admin . s i t e . r e g i s t e r ( P o l l , PollAdmin )
the first element of each tuple in fieldsets is the title of the fieldset.
You can assign arbitrary HTML classes to each fieldset. Django provides a ”collapse” class that displays a
particular fieldset initially collapsed. This is useful when you have a long form that contains a number of fields
that aren’t commonly used:
from e s t u d e n t . p o l l s . models i m p o r t P o l l
from d j a n g o . c o n t r i b i m p o r t admin
admin . s i t e . r e g i s t e r ( P o l l , PollAdmin )
admin . s i t e . r e g i s t e r ( P o l l , PollAdmin )
admin . s i t e . r e g i s t e r ( C h o i c e )
if adding a new Choice, the ”Poll” field is a select box containing every poll in the database. Django knows
that a ForeignKey should be represented in the admin as a <select> box.
This is an inefficient way of adding Choice objects to the system. It’d be better if you could add a bunch
of Choices directly when you create the Poll object:
7
from e s t u d e n t . p o l l s . models i m p o r t P o l l
from e s t u d e n t . p o l l s . models i m p o r t C h o i c e
from d j a n g o . c o n t r i b i m p o r t admin
c l a s s C h o i c e I n l i n e ( admin . S t a c k e d I n l i n e ) :
model = C h o i c e
extra = 3
admin . s i t e . r e g i s t e r ( P o l l , PollAdmin )
this tells django: Choice objects are edited on the Poll admin page.
With TabularInline (instead of StackedInline), the related objects are displayed in a more compact, table-based
format:
c l a s s C h o i c e I n l i n e ( admin . T a b u l a r I n l i n e ) :
The type of filter displayed depends on the type of field you’re filtering on. Because pub date is a DateTime-
Field, Django knows to give the default filter options for DateTimeFields: ”Any date,” ”Today,” ”Past 7 days,”
”This month,” ”This year.”
Add search field (search box at the top - django will search the qiestion field):
s e a r c h f i e l d s = [ ’ question ’ ]
That adds hierarchical navigation, by date, to the top of the change list page. At top level, it displays all
available years. Then it drills down to months and, ultimately, days.
When a user requests a django-powered page, the system looks at the ROOT URLCONF setting, which contains
a string in python syntax. Django loads that module and looks for a module-level variable called urlpatterns,
which is a sequence of tuples:
8
( r e g u l a r e x p r e s s i o n , Python c a l l b a c k f u n c t i o n [, optional dictionary ])
django starts at the first regular expression and makes its way down the list, comparing the requested URL
against each regular expression until it finds one that matches: then it calls the python function, with an
HttpRequest object as the first argument, any captured values from the RE as keyword arguments.
The default URLconf is located at estudent/urls.py, and the settings.py ROOT URLCONF variable is set
to point at that file. Edit urls.py:
from d j a n g o . c o n f . u r l s . d e f a u l t s i m p o r t ∗
from d j a n g o . c o n t r i b i m p o r t admin
admin . a u t o d i s c o v e r ( )
urlpatterns = patterns ( ’ ’ ,
( r ’ ˆ p o l l s /$ ’ , ’ estudent . p o l l s . views . index ’ ) ,
( r ’ ˆ p o l l s / ( ?P<p o l l i d >\d+)/ $ ’ , ’ e s t u d e n t . p o l l s . v i e w s . d e t a i l ’ ) ,
( r ’ ˆ p o l l s / ( ?P<p o l l i d >\d+)/ r e s u l t s / $ ’ , ’ e s t u d e n t . p o l l s . v i e w s . r e s u l t s ’ ) ,
( r ’ ˆ p o l l s / ( ?P<p o l l i d >\d+)/ v o t e / $ ’ , ’ e s t u d e n t . p o l l s . v i e w s . v o t e ’ ) ,
( r ’ ˆ admin / ’ , i n c l u d e ( admin . s i t e . u r l s ) ) ,
)
when somebody requests a page ”/polls/23/”, django loads this module (because it’s pointed to by the ROOT URLCONF),
it finds the variable urlpatterns and traverses the RE in order. When it finds the RE that matches it loads the
function detail() from estudent/polls/views.py and calls it like:
d e t a i l ( r e q u e s t=<HttpRequest o b j e c t >, p o l l i d = ’ 23 ’ )
the poll id=’23’ part comes from (?P<poll id>+ . ): using parentheses around a pattern captures the text matched
by that pattern and sends it as argument to the view function. the ?P<>poll id¿ defines the name that will be
used to identify the matched pattern; and +. is a regular expression to match a sequence of digits.
Because the URL patterns are RE there is no limit on what you can do with them (no need to add .php
extensions).
These RE do not search GET and POST parameters, or the domain name. The request to http://www.example.com/myapp/,
the URLconf will look for myapp/. In a request to http://www.example.com/myapp/?page=3, the URLconf
will look for myapp/
this happens because you haven’t written a function vote() in the module estudent.polls.views.py:
from d j a n g o . h t t p i m p o r t HttpResponse
def r e s u l t s ( request , p o l l i d ) :
return HttpResponse ( ”You ’ r e l o o k i n g a t t h e r e s u l t s of p o l l %s . ” % p o l l i d )
def d e t a i l ( request , p o l l i d ) :
return HttpResponse ( ”You ’ r e l o o k i n g a t p o l l %s . ” % p o l l i d )
9
now visit this addresses (it will display the placeholder results and voting pages):
• /polls/34/
• /polls/34/result/
• /polls/34/vote/
Let’s change the index() function (display the latest 5 poll questions in the system, separated by commas):
def index ( request ) :
l a t e s t p o l l l i s t = P o l l . o b j e c t s . a l l ( ) . o r d e r b y ( ’−p u b d a t e ’ ) [ : 5 ]
output = ’ , ’ . j o i n ( [ p . q u e s t i o n for p i n l a t e s t p o l l l i s t ] )
return HttpResponse ( o u t p u t )
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
S i s t u d e n t ? , Kako j e t v o j f o t e r ? , Kako j e t v o j a mama? , Kako s i ? , What ’ s up ?
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
The page’s design is hard-coded in the view. If you want to change the way the page looks, you’ll have to edit
this python code: use django’s template system to separate the design from python:
from d j a n g o . template i m p o r t Context , l o a d e r
from e s t u d e n t . p o l l s . models i m p o r t P o l l
from d j a n g o . h t t p i m p o r t HttpResponse
def r e s u l t s ( request , p o l l i d ) :
return HttpResponse ( ”You ’ r e l o o k i n g a t t h e r e s u l t s of p o l l %s . ” % p o l l i d )
def d e t a i l ( request , p o l l i d ) :
return HttpResponse ( ”You ’ r e l o o k i n g a t p o l l %s . ” % p o l l i d )
Edit TEMPLATES DIRS in your settings.py and set the templates directory and in there create directory
polls in that directory and within that index.html (loader.get template(’polls/index.html’) maps to ”[tem-
plate directory]/polls/index.html). Template should contain:
{% i f l a t e s t p o l l l i s t %}
<u l >
{% f o r p o l l i n l a t e s t p o l l l i s t %}
< l i > {{ p o l l . q u e s t i o n }} </ l i >
{% e n d f o r %}
</u l >
{% e l s e %}
<p>No p o l l s a r e a v a i l a b l e . </p>
{% e n d i f %}
10
load the page in your Web browser, and you should see a bulleted-list containing the ”What’s up” poll. Shortcut:
from d j a n g o . s h o r t c u t s i m p o r t r e n d e r t o r e s p o n s e
from m y s i t e . p o l l s . models i m p o r t P o l l
render to response takes a template name as its first argument and a dictionary as its optional second argument.
It returns an HttpResponse object of the given template rendered with the given context.
Let’s also change the urls.py so that URL design will be specific to the app (and not the django installation).
Copy the file estudent/urls.py to estudent/polls/urls.py and edit it:
from d j a n g o . c o n f . u r l s . d e f a u l t s i m p o r t ∗
from d j a n g o . c o n t r i b i m p o r t admin
admin . a u t o d i s c o v e r ( )
urlpatterns = patterns ( ’ ’ ,
( r ’ ˆ p o l l s / ’ , include ( ’ estudent . p o l l s . views . index ’ ) ) ,
( r ’ ˆ p o l l s / ( ?P<p o l l i d >\d+)/ ’ , i n c l u d e ( ’ e s t u d e n t . p o l l s . v i e w s . d e t a i l ’ ) ) ,
( r ’ ˆ p o l l s / ( ?P<p o l l i d >\d+)/ r e s u l t s / ’ , i n c l u d e ( ’ e s t u d e n t . p o l l s . v i e w s . r e s u l t s ’ ) ) ,
( r ’ ˆ p o l l s / ( ?P<p o l l i d >\d+)/ v o t e / ’ , i n c l u d e ( ’ e s t u d e n t . p o l l s . v i e w s . v o t e ’ ) ) ,
( r ’ ˆ admin / ’ , i n c l u d e ( admin . s i t e . u r l s ) ) ,
)
include() chops off whatever part of the URL matched up to that point and sends the remaining string to the
the included URLconf for further processing.
The idea behind include() and URLconf decoupling is to make it easy to plug-and-play URLs.
Goal: create a web page that displays the current date and time. We’ll write a view function() - a python
function that tkaes a web request and returns a web response. Response can be:
• the HTML contents of a web page
• a redirect
• a 404 error
• an XML document
• an image
• ...
view contains whatever logic is necessary to return that response. Create eleanor/views.py:
Explanation:
• the current datetime is the view function - each view function takes an HttpRequest object as it’s first
parameter.
• 1: calculates the current date and time
11
• 2: constructs an HTML response using python’s format-string capability. The %s within thr string is a
placeholder.
urlpatterns = patterns ( ’ ’ ,
( r ’ ˆ time /$ ’ , c u r r e n t d a t e t i m e ) ,
)
Explanation:
• line is an urlpattern which is a python tuple in which the first element is a simple RE and second element
is the view function to use (any request to the URL /time/ should be handled by the current datetime
view function)
• we passed current datetime as an object without calling the function (functions are first-class objects)
The urlpatterns variable (defined in ROOT URLCONF) defines the mapping between URLs and the code
that handles those URLs.
• when a request comes in - example: /time/ - django loads the URLconf and check each of the URLpatterns
in order (until it finds one it matches) and then calls the view function associated with that pattern, passing
an HttpRequest object as the first parameter to the function
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.
12
2.4 Dynamic URLs
The /time/ was static, let’s make a dynamic url now: /time/plus/1 would display date/time one hour into the
future, /time/plus/2 two hours,...
from d j a n g o . c o n f . u r l s . d e f a u l t s i m p o r t ∗
from e l e a n o r . v i e w s i m p o r t c u r r e n t d a t e t i m e , h o u r s a h e a d
urlpatterns = patterns ( ’ ’ ,
( r ’ ˆ time /$ ’ , c u r r e n t d a t e t i m e ) ,
( r ’ ˆ t i m e / p l u s /\d { 1 , 2 } / $ ’ , h o u r s a h e a d ) ,
)
the ”\d1,2” allows either one-or-two digit numbers (number limited to 99).
Now we need to pass that data to view function: place parentheses around the data in the URLpattern that we
want to save:
( r ’ ˆ time / p l u s /(\ d {1 ,2}) /$ ’ , hours ahead ) ,
Now we need to write he hours ahead view (takes an extra argument - number of hours of offset):
def hours ahead ( request , o f f s e t ) :
o f f s e t = int ( o f f s e t )
dt = d a t e t i m e . d a t e t i m e . now ( ) + d a t e t i m e . t i m e d e l t a ( h o u r s= o f f s e t )
html = ”<html><body>I n %s hour ( s ) , i t w i l l be %s . </ body></html>” % ( o f f s e t , dt )
return HttpResponse ( html )
• Request information
Are you the type of programmer who likes to debug with the help of carefully placed print statements? You can
use the Django error page to do so—just without the print statements. At any point in your view, temporarily
insert an assert False to trigger the error page. Then, you can view the local variables and state of the program.
All this info is only displayed when then the django project is in debug mode.
• any change to the design of the page requires a change to the python code
Template system is a string of text that is intended to separate the presentation of a document from its data. A
template defines placeholders and various bits of basic logic that regulate how the document should be displayed.
Example:
13
<html>
<head><t i t l e >O r d e r i n g n o t i c e </ t i t l e ></head>
<body>
<p>Dear {{ p e r s o n n a m e }} , </p>
<u l >
{% f o r i t e m i n i t e m l i s t %}
< l i >{{ i t e m }}</ l i >
{% e n d f o r %}
</u l >
{% i f o r d e r e d w a r r a n t y %}
<p>Your w a r r a n t y i n f o r m a t i o n w i l l be i n c l u d e d i n t h e p a c k a g i n g . </p>
{% e n d i f %}
</body>
</html>
here we’re passing the ship date variable to the date filter, giving (pipe) the date filter the argument ”F
j, Y”: the date filter formats dates in a given format.
14
>>> from d j a n g o . template i m p o r t Template
>>> t = Template ( ”My name i s {{ name } } . ” )
>>> p r i n t t
<d j a n g o . template . Template o b j e c t a t 0 x83b2e6c>
>>>
>>>
>>> from d j a n g o . template i m p o r t Context , Template
>>> t = Template ( ”My name i s {{ name } } . ” )
>>> c = Context ( { ”name” : ” E l e a n o r ” } )
>>> t . r e n d e r ( c )
u ’My name i s E l e a n o r .
we call the render() method on our template object, passing it the context. This returns the rendered tem-
plate—that is, it replaces template variables with the actual values of the variables, and it executes any block
tags.
Those are the fundamentals of using the Django template system: just write a template, create a Template
object, create a Context, and call the render() method.
Example:
>>> from d j a n g o . template i m p o r t Context , Template
>>> p e r s o n = { ’ name ’ : ’ E l e a n o r ’ , ’ a g e ’ : ’ 22 ’ }
>>> t = Template ( ’ {{ p e r s o n . name }} i s {{ p e r s o n . a g e }} y e a r s o l d . ’ )
>>> c = Context ( { ’ p e r s o n ’ : p e r s o n } )
>>> t . r e n d e r ( c )
u ’ E l e a n o r i s 22 y e a r s o l d .
Another example:
>>> from d j a n g o . template i m p o r t Context , Template
>>> i m p o r t d a t e t i m e
>>> d = d a t e t i m e . d a t e ( 1 9 9 3 , 5 , 2 )
>>> d . y e a r
1993
>>> d . month
5
>>> d . day
2
>>> t = Template ( ’ The month i s {{ d a t e . month }} and t h e y e a r i s {{ d a t e . y e a r } } . ’ )
>>> c = Context ( { ’ d a t e ’ : d } )
>>> t . r e n d e r ( c )
u ’ The month i s 5 and t h e y e a r i s 1 9 9 3 . ’
15
>>> from d j a n g o . template i m p o r t Context , Template
>>> t = Template ( ’ {{ v a r }} −− {{ v a r . upper }} −− {{ v a r . i s d i g i t }} ’ )
>>> t . r e n d e r ( Context ( { ’ v a r ’ : ’ h e l l o ’ } ) )
u ’ h e l l o −− HELLO −− F a l s e ’
>>> t . r e n d e r ( Context ( { ’ v a r ’ : ’ 123 ’ } ) )
u ’ 123 −− 123 −− True ’
It’s not possible to pass arguments to the methods: you can only call methods that have no required arguments.
You can also list indices (Negative list indices are not allowed. For example, the template variable items.-
1 would cause a TemplateSyntaxError):
>>> from d j a n g o . template i m p o r t Context , Template
>>> t = Template ( ’ Item 2 i s {{ i t e m s . 2 } } . ’ )
>>> c = Context ( { ’ i t e m s ’ : [ ’ a p p l e s ’ , ’ bananas ’ , ’ c a r r o t s ’ ] } )
>>> t . r e n d e r ( c )
u ’ Item 2 i s c a r r o t s . ’
How to prevent the template from executing a certain function (if you have a BankAccount object that has a
delete() method. A template shouldn’t be allowed to include something like account.delete ): set the function
attribute alters data on the method:
d e f delete ( s e l f ) :
# Delete the account
d e l e t e . a l t e r s d a t a = True
the template system won’t execute any method marked in this way. In other words, if a template includes
account.delete , that tag will not execute the delete() method. It will fail silently.
16
3.4 Playing with context objects
Most of the time, you’ll instantiate Context objects by passing in a fully populated dictionary to Context().
But you can add and delete items from a Context object once it’s been instantiated, too, using standard Python
dictionary syntax:
>>> from d j a n g o . template i m p o r t Context
>>> c = Context ( { ” f o o ” : ” b a r ” } )
>>> c [ ’ f o o ’ ]
’ bar ’
>>> d e l c [ ’ f o o ’ ]
>>> c [ ’ f o o ’ ]
T r a ceback ( most r e c e n t c a l l l a s t ) :
F i l e ”<c o n s o l e >” , l i n e 1 , i n <module>
F i l e ” / u s r / l i b / python2 . 6 / s i t e −p a c k a g e s / d j a n g o / t e m p l a t e / c o n t e x t . py ” , l i n e 4 4 , i n getitem
r a i s e KeyError ( key )
KeyError : ’ f o o ’
>>> c [ ’ newfoo ’ ] = ’ newbar ’
>>> c [ ’ newfoo ’ ]
’ newbar ’
In Python, the empty list ([]), tuple (()), dictionary (), string (”), zero (0), and the special object None
are False in a Boolean context. Everything else is True.
The {% if %} tag accepts and, or, or not for testing multiple variables, or to negate a given variable:
{% i f a t h l e t e l i s t and c o a c h l i s t %}
Both a t h l e t e s and c o a c h e s a r e a v a i l a b l e .
{% e n d i f %}
{% i f not a t h l e t e l i s t %}
There a r e no a t h l e t e s .
{% e n d i f %}
{% i f a t h l e t e l i s t or c o a c h l i s t %}
There a r e some a t h l e t e s or some c o a c h e s .
{% e n d i f %}
{% i f not a t h l e t e l i s t or c o a c h l i s t %}
There a r e no a t h l e t e s or t h e r e a r e some c o a c h e s . (OK, s o
w r i t i n g E n g l i s h t r a n s l a t i o n s o f Boolean l o g i c sounds
s t u p i d ; i t ’ s not our f a u l t . )
{% e n d i f %}
if tags don’t allow and and or clauses within the same tag, because the order of logic would be ambiguous. For
example, this is invalid:
{% i f a t h l e t e l i s t and c o a c h l i s t or c h e e r l e a d e r l i s t %}
There is no elif tag: use nested if tags to accomplish the same thing.
You should close each if with an endif tag, otherwise django will throw a TemplateSyntaxError.
17
3.5.2 for
The for tag allows you to loop over each item in a sequence. Syntax is:
for X in Y
each time through the loop, the template system will render everything between for and endfor.
Example:
<u l >
{% f o r a t h l e t e i n a t h l e t e l i s t %}
< l i >{{ a t h l e t e . name }}</ l i >
{% e n d f o r %}
</u l >
You can’t break out of the loop before the loop is finished: like break or continue.
For tag sets the forloop template that can give you information about the progress in loop:
• forloop.counter: the number of times the loop has been entered (first time == 1)
• forloop.counter0: the same as forloop.counter except zero indexed
• forloop.revcounter: the number of remaining items in the loop
• forloop.revcouner0
• forloop.first: True if the first time through the loop
{% f o r o b j e c t i n o b j e c t s %}
{% i f f o r l o o p . f i r s t %}< l i c l a s s=” f i r s t ”>{% e l s e %}< l i >{% e n d i f %}
{{ o b j e c t }}
</ l i >
{% e n d f o r %}
3.5.3 ifequal/ifnotequal
To compare two values and display something (everything between ifequal and endifequal) if they’re equal:
{% i f e q u a l u s e r c u r r e n t u s e r %}
<h1>Welcome! </h1>
{% e n d i f e q u a l %}
Only template variables, strings, integers, and decimal numbers are allowed as arguments to ifequal:
{% ifequal v a r i a b l e 1 %}
{% ifequal v a r i a b l e 1 . 2 3 %}
{% ifequal v a r i a b l e ’ f o o ’ %}
{% ifequal v a r i a b l e ” f o o ” %}
Any other types of variables, such as Python dictionaries, lists, or Booleans, can’t be hard-coded in ifequal:
{% i f e q u a l v a r i a b l e True %}
{% i f e q u a l v a r i a b l e [ 1 , 2 , 3 ] %}
{% i f e q u a l v a r i a b l e { ’ key ’ : ’ v a l u e ’ } %}
18
3.5.4 Comments
A comment:
{# T h i s i s a comment #}
3.6 Filters
Template filters are a simple way of altering the value of variables before they’re displayed:
{{ name | l o w e r }}
this displays the value of the {{ name }} variable after being filtered through the lower filter, which converts
text to lowercase. Use a pipe (—) to apply a filter.
Filtering can be chained and some filters take arguments (always in double quotes):
{{ m y t e x t | e s c a p e | l i n e b r e a k s }}
{{ b i o | t r u n c a t e w o r d s : ” 30 ” }}
we’re using the function django.template.loader.get template() rather than loading the template from the filesys-
tem manually. The get template() function takes a template name as its argument, figures out where the tem-
plate lives on the filesystem, opens that file, and returns a compiled Template object.
If get template() cannot find the template with the given name, it raises a TemplateDoesNotExist exception.
19
<html><body>I t i s now {{ c u r r e n t d a t e }}. </ body></html>
instead of manually specifying the context dictionary as before, we pass the value of locals(), which will include
all variables defined at that point in the function’s execution. This can save you a lot of typing.
One thing to watch out for when using locals() is that it includes every local variable, which may comprise
more variables than you actually want your template to have access to.
A final thing to consider is that locals() incurs a small bit of overhead, because when you call it, Python has to
create the dictionary dynamically. If you specify the context dictionary manually, you avoid this overhead.
Example:
20
# include t h e template i n c l u d e s / nav . html
{% i n c l u d e ’ i n c l u d e s / nav . html ’ %}
Included templates are evaluated with the context of the template that’s including them.
<hr>
<p>Thanks f o r v i s i t i n g my s i t e . </p>
</body>
</html>
<hr>
<p>Thanks f o r v i s i t i n g my s i t e . </p>
</body>
</html>
we’ve just duplicated a lot of HTML. Solution: factor out the common bits in both template and save them in
a separate template snippets, which are then included in each template.
but then it would get messy, because we couldn’t include anything else (different stuff on every page).
21
Solution is: django inheritance: instead of defining the snippets that are common, you define the snip-
pets that are different.
Define a base template (a skeleton of your page that child template will later fill in):
<!DOCTYPE HTML PUBLIC ”−//W3C//DTD HTML 4 . 0 1 / /EN”>
<html l a n g=” en ”>
<head>
< t i t l e >{% b l o c k t i t l e %}{% e n d b l o c k %}</ t i t l e >
</head>
<body>
<h1>My h e l p f u l timestamp s i t e </h1>
{% b l o c k c o n t e n t %}{% e n d b l o c k %}
{% b l o c k f o o t e r %}
<hr>
<p>Thanks f o r v i s i t i n g my s i t e . </p>
{% e n d b l o c k %}
</body>
</html>
we’ll use this templates for all the pages on the site: and then the child templates will override/add/leave alone
the contents of the blocks.
The block tag tells the template engine that a child template may override those portions of the template.
{% b l o c k t i t l e %}The c u r r e n t t i m e{% e n d b l o c k %}
{% b l o c k c o n t e n t %}
<p>I t i s now {{ c u r r e n t d a t e }}. </p>
{% e n d b l o c k %}
now the template only contains code that’s unique to that template (no redundancy).
Inheritance doesn’t affect the way the context works, and you can use as many levels of inheritance as needed.
One common way of using inheritance is the following three-level approach:
• create a base.html template that holds the main look and feel of your site (rarely changes)
• create a base SECTION.html template for each section of your site (base photos.html and base forum.html,...).
These templates extend base.html and include section-specific styles/design.
• create individual templates for each type of page, such as forum page or photo gallery. These templates
extend the appropriate section template.
Useful info:
• If you find yourself duplicating code in a number of templates, it probably means you should move that
code to a block in a parent template.
• If you need to get the content of the block from the parent template, the {{ block.super }} variable will
do the trick. This is useful if you want to add to the contents of a parent block instead of completely
overriding it.
• The template name you pass to extends is loaded using the same method that get template() uses. That
is, the template name is appended to your TEMPLATE DIRS setting.
22
4 Interacting with database
You can of course hard-code the the text to view (use python library to execute a SQL query):
from d j a n g o . s h o r t c u t s i m p o r t r e n d e r t o r e s p o n s e
i m p o r t MySQLdb
A number of problems exits: hard-coding the database connection parameters ; we have to create a connection,
create a cursor, execute a statement and close the connection ; it ties us to mysql.
Finally, we should note that Django includes a utility that can generate models by introspecting an exist-
ing database. This is useful for quickly getting up and running with legacy data.
First step: declaring the database layout. Edit the models.py file that was created by the startapp command:
from d j a n g o . db i m p o r t models
c l a s s P u b l i s h e r ( models . Model ) :
name = models . C h a r F i e l d ( m a x l e n g t h =30)
a d d r e s s = models . C h a r F i e l d ( m a x l e n g t h =50)
c i t y = models . C h a r F i e l d ( m a x l e n g t h =60)
s t a t e p r o v i n c e = models . C h a r F i e l d ( m a x l e n g t h =30)
c o u n t r y = models . C h a r F i e l d ( m a x l e n g t h =50)
w e b s i t e = models . URLField ( )
Explanation:
23
• each model is represented by a python class that is a subclass of django.db.models.Model: the parent
class Model contains all the machinery necessary to make these objects capable of interacting with a
database - and we only define the fields.
• each model corresponds to a single database table and each attribute to a column in that table (the
attribute name == column’s name and the type of the field (CharField) == database column type
(varchar)).
• we haven’t explicitly defined a primary key in any of these models. Unless you instruct it otherwise,
Django automatically gives every model an integer primary key field called id. Each Django model is
required to have a single-column primary key.
Sync looks at all of the models in each app in your INSTALLED APPS setting, checks the database to see
whether the appropriate tables exist yet, and creates the tables if they don’t yet exist. Note that syncdb does
not sync changes in models or deletions of models; if you make a change to a model or delete a model, and you
want to update the database, syncdb will not handle that.
24
from d j a n g o . c o n t r i b i m p o r t admin
from <m y p r o j e c t >.<myapp>. models i m p o r t MyModel
admin . s i t e . r e g i s t e r ( MyModel )
from d j a n g o . c o n t r i b i m p o r t admin
from e l e a n o r . book s . models i m p o r t P u b l i s h e r
admin . s i t e . r e g i s t e r ( P u b l i s h e r )
c l a s s P u b l i s h e r ( models . Model ) :
name = models . C h a r F i e l d ( m a x l e n g t h =30)
a d d r e s s = models . C h a r F i e l d ( m a x l e n g t h =50)
c i t y = models . C h a r F i e l d ( m a x l e n g t h =60)
s t a t e p r o v i n c e = models . C h a r F i e l d ( m a x l e n g t h =30)
c o u n t r y = models . C h a r F i e l d ( m a x l e n g t h =50)
w e b s i t e = models . URLField ( )
• run ”python manage.py syncdb”: installs extra database tables the admin interface uses
• add the URL pattern to your urls.py:
from d j a n g o . c o n f . u r l s . d e f a u l t s i m p o r t ∗
from d j a n g o . c o n t r i b i m p o r t admin
admin . a u t o d i s c o v e r ( )
( r ’ ˆ admin / ’ , i n c l u d e ( ’ d j a n g o . c o n t r i b . admin . u r l s ’ ) ) ,
You’ll need to restart the development server to see your changes. Normally, the server auto-reloads code every
time you modify a file, but the action of creating a new file doesn’t trigger the auto-reloading logic.
Each object given an Admin declaration shows up on the main index page.
User objects have the standard username, password, e-mail, and real name fields you might expect, along
with a set of fields that define what the user is allowed to do in the admin interface. First, there’s a set of three
flags:
25
from d j a n g o . c o n t r i b i m p o r t admin
from e l e a n o r . books . models i m p o r t Book
Each of those lines instructed the admin interface to construct a different piece of interface:
• list display: controls which columns to appear in the change list table (default: displays only a single
column that contains the object’s string representation)
• list filter: creates the filtering bar on the right side of the list (filtering by date - can be any field)
• ordering: the order in which the objects are presented in the admin interface (prefixing a field by minus
sign reverses the given order)
Then just edit the admin base.html to replace the generic django text with your own.
You should edit the admin/index.html template. Edit the file, and you’ll see it uses a template tag called
get admin app list as app list. This tag retrieves every installed Django application. Instead of using the
tag, you can hard-code links to object-specific admin pages in whatever way you think is best.
6 Form processing
6.1 Search
Often the difference between the success or failure of a site is the quality of its search. We’ll start by adding
the search view to our URLconf (eleanor.urls):
( r ’ ˆ search /$ ’ , ’ e l e a n o r . boo ks . v i e w s . s e a r c h ’ ) ,
26
from d j a n g o . db . models i m p o r t Q
from d j a n g o . s h o r t c u t s i m p o r t r e n d e r t o r e s p o n s e
from models i m p o r t Book
Explanation:
• request.GET is how you access GET data from django (POST is accessed through request.POST). GET
and POST are the two methods that browsers use to send data to a server (instruct the browser to submit
the form data to the URL /book/search/ using the GET method):
<form a c t i o n=” / boo ks / s e a r c h / ” method=” g e t ”>
• the get() method on request.GET looks for a GET parameter named q and return an empty string if that
parameter wasn’t submitted.
• Q objects are used to build complex queries (here we’re searching for any books where either the title or
name matches the search).
• icontains == a case-insensitive seach that uses the SQL like operator in the underlying database
• distinct() eliminates any duplicate values
We also have to create the template:
<!DOCTYPE HTML PUBLIC ”−//W3C//DTD HTML 4 . 0 1 / /EN”>
<html l a n g=” en ”>
<head>
< t i t l e >S e a r c h{% i f q u e r y %} R e s u l t s{% e n d i f %}</ t i t l e >
</head>
<body>
<h1>S e a r c h </h1>
<form a c t i o n=” . ” method=”GET”>
< l a b e l f o r=”q”>S e a r c h : </ l a b e l >
<i n p u t t y p e=” t e x t ” name=”q” v a l u e=” {{ q u e r y | e s c a p e }} ”>
<i n p u t t y p e=” submit ” v a l u e=” S e a r c h ”>
</form>
{% i f q u e r y %}
<h2>R e s u l t s f o r ” {{ q u e r y | e s c a p e }} ” : </h2>
{% i f r e s u l t s %}
<u l >
{% f o r book i n r e s u l t s %}
< l i >{{ book | e s c a p e }}</ l 1 >
{% e n d f o r %}
</u l >
{% e l s e %}
<p>No books found </p>
{% e n d i f %}
{% e n d i f %}
</body>
</html>
Explanation:
27
• the form’s action is ’.’ which means ”the current url”
• we reinserted the query back into the <input> which lets readers easily refine their searches without
having to retype what they searched for.
• everywhere query and book is used, we pass it through the escape filter to make sure that any potentially
malicious search text is filtered out before being inserted into the page.
• The submitted data should be subjected to extensive validation. The golden rule of Web application
security is “never trust incoming data,” so validation is essential.
• If the user has made any mistakes, the form should be redisplayed with detailed, informative error mes-
sages. The original data should be prefilled, to save the user from having to reenter everything.
• The form should continue to redisplay until all of the fields have been correctly filled.
Create the new form and save it in forms.py within application directory:
from d j a n g o i m p o r t f o r m s
TOPIC CHOICES = (
( ’ g e n e r a l ’ , ’ General enquiry ’ ) ,
( ’ bug ’ , ’ Bug r e p o r t ’ ) ,
( ’ suggestion ’ , ’ Suggestion ’ ) ,
)
c l a s s ContactForm ( f o r m s . Form ) :
t o p i c = f o r m s . C h o i c e F i e l d ( c h o i c e s=TOPIC CHOICES)
message = f o r m s . C h a r F i e l d ( )
s e n d e r = f o r m s . E m a i l F i e l d ( r e q u i r e d=F a l s e )
a django form is a subclass of django.newforms.Form and contains a number of field classes (topic, message,
sender, ...). The form object knows how to do a number of useful things: validate a collection of data, generate
its own HTML widgets, and draw the entire form for us.
views.py:
from f o r m s i m p o r t ContactForm
contact.html:
28
<!DOCTYPE HTML PUBLIC ”−//W3C//DTD HTML 4 . 0 1 / /EN”>
<html l a n g=” en ”>
<head>
< t i t l e >Contact us </ t i t l e >
</head>
<body>
<h1>Contact us </h1>
<form a c t i o n=” . ” method=”POST”>
<t a b l e >
{{ form . a s t a b l e }}
</ t a b l e >
<p><i n p u t t y p e=” submit ” v a l u e=” Submit ”></p>
</form>
</body>
</html>
Explanation:
• form.as table: form is our ContactForm instance, passed to render to response, as table is a method on
that object that renders the form as a sequence of table rows - this is generated:
<t r >
<th><l a b e l f o r=” i d t o p i c ”>Topic : </ l a b e l ></th>
<td>
< s e l e c t name=” t o p i c ” i d=” i d t o p i c ”>
<o p t i o n v a l u e=” g e n e r a l ”>G e n e r a l e n q u i r y </o p t i o n >
<o p t i o n v a l u e=” bug ”>Bug r e p o r t </o p t i o n >
<o p t i o n v a l u e=” s u g g e s t i o n ”>S u g g e s t i o n </o p t i o n >
</ s e l e c t >
</td>
</t r >
<t r >
<th><l a b e l f o r=” i d m e s s a g e ”>Message : </ l a b e l ></th>
<td><i n p u t t y p e=” t e x t ” name=” message ” i d=” i d m e s s a g e ” /></td>
</t r >
<t r >
<th><l a b e l f o r=” i d s e n d e r ”>S e n d e r : </ l a b e l ></th>
<td><i n p u t t y p e=” t e x t ” name=” s e n d e r ” i d=” i d s e n d e r ” /></td>
</t r >
the table and form tags are not included: define those yourself
We can add arguments to the ”message = forms.CharField(widget=forms.Textarea())”:
• widget=forms.Textarea(): each field type has a default widget, but we can override the default or provide
a custom widget of your own
• initial=”test”: initial data of the form
We need to tell if the data is indeed valid and then access the data:
form = ContactForm ( r e q u e s t . POST)
i f form . i s v a l i d ( ) :
t o p i c = form . c l e a n e d d a t a [ ’ t o p i c ’ ]
message = form . c l e a n e d d a t a [ ’ message ’ ]
s e n d e r = form . c l e a n e d d a t a . g e t ( ’ s e n d e r ’ , ’ no repl y@exa mple . com ’ )
# ...
Explanation:
• we use form.clean data to access the data.
29
• since the sender is not required, we provide a default when it’s missing
Finally, we need to record the user’s feedback: (email it to a site admin):
from d j a n g o . c o r e . m a i l i m p o r t s e n d m a i l
# ...
send mail (
’ Feedback from your s i t e , t o p i c : %s ’ % t o p i c ,
message , s e n d e r ,
[ ’ a d m i n i s t r a t o r @ e x a m p l e . com ’ ]
)
30
display : block ;
f o n t −s i z e : 10 px ;
margin : 0 0 3 px ;
padding : 4 px 5 px ;
}
</ s t y l e >
Each field widget (<input type=”text”>, <textarea>, ...) can be rendered by accessing {{ form.fieldname }}.
Any errors associated with a field are available as {{ form.fieldname.errors }}.
We can use these form variables to construct a custom template for our contact form:
<form a c t i o n=” . ” method=”POST”>
<d i v c l a s s=” f i e l d W r a p p e r ”>
{{ form . t o p i c . e r r o r s }}
< l a b e l f o r=” i d t o p i c ”>Kind o f f e e d b a c k : </ l a b e l >
{{ form . t o p i c }}
</div>
<d i v c l a s s=” f i e l d W r a p p e r ”>
{{ form . message . e r r o r s }}
< l a b e l f o r=” i d m e s s a g e ”>Your message : </ l a b e l >
{{ form . message }}
</div>
<d i v c l a s s=” f i e l d W r a p p e r ”>
{{ form . s e n d e r . e r r o r s }}
< l a b e l f o r=” i d s e n d e r ”>Your e m a i l ( o p t i o n a l ) : </ l a b e l >
{{ form . s e n d e r }}
</div>
<p><i n p u t t y p e=” submit ” v a l u e=” Submit ”></p>
</form>
PublisherForm = f o r m f o r m o d e l ( P u b l i s h e r )
There’s one more shortcut being demonstrated here. Since forms derived from models are often used to save
new instances of the model to the database, the form class created by form for model includes a convenient
save() method. This deals with the common case; you’re welcome to ignore it if you want to do something a
bit more involved with the submitted data.
form for instance() is a related method that can create a preinitialized form from an instance of a model
class. This is useful for creating “edit” forms.
31
• required: if the value is required
• error messages: overrides the default messages that the field will raise
• validators: let you provide a list of validation functions for this field
Those are:
• BooleanField: CheckboxInput
• CharField: TextInput
• ChoiceField: Select
• TypedChoiceField: Select
• DateField: DateInput
• DateTimeField: DateTimeInput
• DecimalField: TextInput
• EmailField: TextInput
• FileField: FileInput
• FilePathField: Select
• FloatField: TextInput
• ImageField: FileInput
• IntegerField: TextInput
• IPAddressField: TextInput
• MultipleChoiceField: SelectMultiple
• NullBooleanField: NullBooleanSelect
• RegexField: TextInput
• SlugField: TextInput
• TimeField: TextInput
• URLField: TextInput
• ComboField: TextInput
• MultiValueField: TextInput
32
• SplitDateTimeField: SplitDateTimeWidget
• ModelChoiceField: Allows the selection of a single model object, suitable for representing a foreign key.
A single argument is required:
– ModelChoiceField.queryset: A QuerySet of model objects from which the choices for the field will
be derived, and which will be used to validate the user’s selection.
– ModelChoiceField.empty label: By default the select widget used by ModelChoiceField will have
a an empty choice at the top of the list. You can change the text of this label (which is ”———”
by default) with the empty label attribute, or you can disable the empty label entirely by setting
empty label to None:
• ModelMultipleChoiceField: Allows the selection of one or more model objects, suitable for representing
a many-to-many relation. As with ModelChoiceField, you can use label from instance to customize the
object representations, and queryset is a required parameter.
If the built-in Field classes don’t meet your needs, you can easily create custom Field classes. To do this, just
create a subclass of django.forms.Field. Its only requirements are that it implement a clean() method and that
its init () method accept the core arguments mentioned above (required, label, initial, widget, help text).
urlpatterns = patterns ( ’ ’ ,
( r ’ ˆnow/ $ ’ , c u r r e n t d a t e t i m e ) ,
)
but when django app grows in complexity, its URLconf grows too: import is necessary for every view function,
but you can avoid that by importing the view module itself:
from d j a n g o . c o n f . u r l s . d e f a u l t s i m p o r t ∗
from e l e a n o r i m p o r t v i e w s
urlpatterns = patterns ( ’ ’ ,
( r ’ ˆnow/ $ ’ , v i e w s . c u r r e n t d a t e t i m e ) ,
)
You can also pass a string containing the module name and function name rather than the function object itself:
from d j a n g o . c o n f . u r l s . d e f a u l t s i m p o r t ∗
urlpatterns = patterns ( ’ ’ ,
( r ’ ˆnow/ $ ’ , ’ e l e a n o r . v i e w s . c u r r e n t d a t e t i m e ’ ) ,
)
using this, it’s no longer necessary to import the view functions (django automatically imports the appropriate
view function the first time it’s needed).
If using the string technique, you can factor out the common view prefix:
33
from d j a n g o . c o n f . u r l s . d e f a u l t s i m p o r t ∗
you don’t put a trailing dot (”.”) in the prefix, nor do you put a leading dot in the view strings. Django puts
those in automatically.
u r l p a t t e r n s += p a t t e r n s ( ’ weblog . v i e w s ’ ,
( r ’ ˆ t a g / ( \w+)/ $ ’ , ’ t a g ’ ) ,
)
urlpatterns = patterns ( ’ ’ ,
( r ’ ˆ a r t i c l e s /(\d{4}) /$ ’ , views . y e a r a r c h i v e ) ,
( r ’ ˆ a r t i c l e s /(\d{4}) /(\d{2}) /$ ’ , views . month archive ) ,
)
urlpatterns = patterns ( ’ ’ ,
( r ’ ˆ a r t i c l e s / ( ?P<y e a r >\d { 4 } ) / $ ’ , v i e w s . y e a r a r c h i v e ) ,
( r ’ ˆ a r t i c l e s / ( ?P<y e a r >\d { 4 } ) / ( ?P<month>\d { 2 } ) / $ ’ , v i e w s . m o n t h a r c h i v e ) ,
)
the captured values are passed to view functions as keyword arguments rather than positional
arguments.
Example: function call with non-named groups:
month archive ( request , ’ 2006 ’ , ’ 03 ’ )
34
Example: function call with named groups:
m o n t h a r c h i v e ( r e q u e s t , y e a r= ’ 2006 ’ , month= ’ 03 ’ )
from d j a n g o . c o n f . u r l s . d e f a u l t s i m p o r t ∗
from m y s i t e i m p o r t v i e w s
urlpatterns = patterns ( ’ ’ ,
( r ’ ˆ foo /$ ’ , views . foo view ) ,
( r ’ ˆ ba r / $ ’ , v i e w s . b a r v i e w ) ,
)
# v i e w s . py
from d j a n g o . s h o r t c u t s i m p o r t r e n d e r t o r e s p o n s e
from m y s i t e . models i m p o r t MyModel
To solve this use optional URLconf parameter. Each pattern in URLconf may include a third item: a dictionary
of keyword arguments to pass to the view function:
# u r l s . py
from d j a n g o . c o n f . u r l s . d e f a u l t s i m p o r t ∗
from m y s i t e i m p o r t v i e w s
urlpatterns = patterns ( ’ ’ ,
( r ’ ˆ f o o /$ ’ , views . foobar view , { ’ template name ’ : ’ t e m p l a t e 1 . html ’ } ) ,
( r ’ ˆ ba r / $ ’ , v i e w s . f o o b a r v i e w , { ’ t e m p l a t e n a m e ’ : ’ t e m p l a t e 2 . html ’ } ) ,
)
# v i e w s . py
from d j a n g o . s h o r t c u t s i m p o r t r e n d e r t o r e s p o n s e
from m y s i t e . models i m p o r t MyModel
the URLconf specifies template name in the URLconf. The view function treats it as just another parameter.
This extra URLconf options technique is a nice way of sending additional information to your view functions
with minimal fuss.
Every Python class has a name attribute that returns the class name. This feature is useful at times
like this, when we don’t know the type of class until runtime. For example, the BlogEntry class’s name is
the string ’BlogEntry’.
When there’s a conflict, extra URLconf parameters get precedence over captured parameters. In other words,
if your URLconf captures a named-group variable and an extra URLconf parameter includes a variable with
the same name, the extra URLconf parameter value will be used:
35
from d j a n g o . c o n f . u r l s . d e f a u l t s i m p o r t ∗
urlpatterns = patterns ( ’ ’ ,
( r ’ ˆ mydata / ( ?P<i d >\d+)/ $ ’ , v i e w s . my view , { ’ i d ’ : 3 } ) ,
)
both the regular expression and the extra dictionary include an id. The hard-coded id gets precedence. That
means any request (e.g., /mydata/2/ or /mydata/432432/) will be treated as if id is set to 3, regardless of the
value captured in the URL.
from d j a n g o . c o n f . u r l s . d e f a u l t s i m p o r t ∗
urlpatterns = patterns ( ’ ’ ,
( r ’ ˆ b l o g / $ ’ , v i e w s . page ) ,
( r ’ ˆ b l o g / page ( ?P<num>\d+)/ $ ’ , v i e w s . page ) ,
)
# v i e w s . py
d e f page ( r e q u e s t , num=” 1 ” ) :
# Output t h e a p p r o p r i a t e page o f b l o g e n t r i e s , a c c o r d i n g t o num .
# ...
both URL patterns point to the same view — views.page — but the first pattern doesn’t capture anything from
the URL. If the first pattern matches, the page() function will use its default argument for num, ”1”. If the
second pattern matches, page() will use whatever num value was captured by the regular expression.
Don’t put URL logic in the view. Each captured argument is sent to the view as a plain Python
string, regardless of what sort of match the regular expression makes.
urlpatterns = patterns ( ’ ’ ,
( r ’ ˆ weblog / ’ , i n c l u d e ( ’ m y s i t e . b l o g . u r l s ’ ) ) ,
( r ’ ˆ photos / ’ , i n c l u d e ( ’ mysite . photos . u r l s ’ ) ) ,
( r ’ ˆ about / $ ’ , ’ m y s i t e . v i e w s . about ’ ) ,
)
The regular expressions in this example that point to an include() do not have a $ (end-of-string match char-
acter) but do include a trailing slash. Whenever Django encounters include(), it chops off whatever part of the
URL matched up to that point and sends the remaining string to the included URLconf for further processing.
urlpatterns = patterns ( ’ ’ ,
( r ’ ˆ ( \ d\d\d\d ) / $ ’ , ’ m y s i t e . b l o g . v i e w s . y e a r d e t a i l ’ ) ,
( r ’ ˆ ( \ d\d\d\d ) / ( \ d\d ) / $ ’ , ’ m y s i t e . b l o g . v i e w s . m o n t h d e t a i l ’ ) ,
)
36
Handled requests:
• /weblog/2007/ : django strips weblog/ and the remaining part 2007/ is sent to mysite.blog.urls where it
matches the first line
• /about/ : matches mysite.views.about (you can mix include patterns with non-include patterns)
8 Generic views
Take certain common idioms and patterns found in view development and abstract them so that you can quickly
write common views of data without having to write too much code.
• perform common simple tasks: redirect to a different page and render a given template
Example:
from d j a n g o . c o n f . u r l s . d e f a u l t s i m p o r t ∗
from d j a n g o . v i e w s . g e n e r i c . s i m p l e i m p o r t d i r e c t t o t e m p l a t e
urlpatterns = patterns ( ’ ’ ,
( ’ ˆ about / $ ’ , d i r e c t t o t e m p l a t e , { ’ t e m p l a t e ’ : ’ about . html ’ } ) ,
)
Explanation:
• direct to template grabs information from the extra-parameters dictionary and uses that information when
rendering the view
• (w+) in URLconf accpets only letters and numbers (any malicious characters - dots and slashes - will be
rejected by the URL resolver before they reach the view itself)
Generic view is a regular view function like any other - and that’s why we can reuse it inside our own views: map
URLs of the form /about/<whatever>.html to staticaly rendered about/<whatever>.html. Edit URLconf:
from m y s i t e . books . v i e w s i m p o r t a b o u t p a g e s
urlpatterns = patterns ( ’ ’ ,
( ’ ˆ about / (w+)/ $ ’ , a b o u t p a g e s ) ,
)
37
from d j a n g o . h t t p i m p o r t Http404
from d j a n g o . template i m p o r t T e mp l at e Do esN o tE xi st
from d j a n g o . v i e w s . g e n e r i c . s i m p l e i m p o r t d i r e c t t o t e m p l a t e
d e f a b o u t p a g e s ( r e q u e s t , page ) :
try :
return d i r e c t t o t e m p l a t e ( r e q u e s t , template=” about/%s . html ” % page )
e x c e p t Templat e Do esN o t Exi st :
r a i s e Http404 ( )
How do we deal with missing templates: we don’t want a nonexistent template to cause a server error, so we
catch TemplateDoesNotExist exception and return 404 error instead.
c l a s s P u b l i s h e r ( models . Model ) :
name = models . C h a r F i e l d ( m a x l e n g t h =30)
a d d r e s s = models . C h a r F i e l d ( m a x l e n g t h =50)
c i t y = models . C h a r F i e l d ( m a x l e n g t h =60)
s t a t e p r o v i n c e = models . C h a r F i e l d ( m a x l e n g t h =30)
c o u n t r y = models . C h a r F i e l d ( m a x l e n g t h =50)
w e b s i t e = models . URLField ( )
c l a s s Meta :
o r d e r i n g = [ ”−name” ]
publisher info = {
” queryset ” : Publisher . objects . a l l () ,
}
urlpatterns = patterns ( ’ ’ ,
( r ’ ˆ p u b l i s h e r s /$ ’ , l i s t d e t a i l . o b j e c t l i s t , publisher info )
)
We need to write the template too (we could tell the object list view which template to use by including a
template name key in extra arguments dictionary, but in absence of an explicit template django will infer one
from the object’s name - books/publisher list.html: books comes from the name of the app that defines the
model, while the publisher bit is just lowercased version of the model’s name):
{% e x t e n d s ” b a s e . html ” %}
{% b l o c k c o n t e n t %}
<h2>P u b l i s h e r s </h2>
<u l >
{% f o r p u b l i s h e r i n o b j e c t l i s t %}
< l i >{{ p u b l i s h e r . name }}</ l i >
{% e n d f o r %}
</u l >
{% e n d b l o c k %}
All the cool features of generic views come from changing the “info” dictionary passed to the generic view.
38
8.3 Extending generic views
There’s no question that using generic views can speed up development substantially. In most projects, however,
there comes a moment when the generic views no longer suffice: there are ways to simply extend generic views
to handle a larger array of use cases.
The publisher list template stores all the books in a variable named object list. We can change the name
of that variable easily with the template object name:
publisher info = {
” queryset ” : Publisher . objects . a l l () ,
” template object name ” : ” publisher ” ,
}
urlpatterns = patterns ( ’ ’ ,
( r ’ ˆ p u b l i s h e r s /$ ’ , l i s t d e t a i l . o b j e c t l i s t , publisher info )
)
Any callable function that’s passed to extra context will be evaluated when the view is rendered (instead
of only once):
def get books () :
return Book . o b j e c t s . a l l ( )
publisher info = {
” queryset ” : Publisher . objects . a l l () ,
” template object name ” : ” publisher ” ,
” e x t r a c o n t e x t ” : {” b o o k l i s t ” : g e t b o o k s }
}
Example (order a list of books by publication date, with the most recent first):
book info = {
” q u e r y s e t ” : Book . o b j e c t s . a l l ( ) . o r d e r b y ( ”−p u b l i c a t i o n d a t e ” ) ,
}
urlpatterns = patterns ( ’ ’ ,
( r ’ ˆ p u b l i s h e r s /$ ’ , l i s t d e t a i l . o b j e c t l i s t , p u b l i s h e r i n f o ) ,
( r ’ ˆ books / $ ’ , l i s t d e t a i l . o b j e c t l i s t , b o o k i n f o ) ,
)
39
9 Extending the template engine
9.1 Template language review
• A template is a text document, or a normal Python string, that is marked up using the Django template
language. A template can contain block tags and variables.
• A block tag is a symbol within a template that does something: produce content, serve as a control
structure
• A variable is a symbol within a template that outputs a value.
• A context is a name - value mapping (similar to a Python dictionary) that is passed to a template.
• A template renders a context by replacing the variable “holes” with values from the context and executing
all block tags.
Use RequestContext when you don’t want to have to specify the same set of variables in a series of templates:
from d j a n g o . template i m p o r t l o a d e r , Context
40
’ i p a d d r e s s ’ : r e q u e s t .META[ ’REMOTE ADDR ’ ] ,
’ message ’ : ’ I am t h e f o u r t h view . ’
})
return t . r e n d e r ( c )
Each view passes the same three variables - app, user and ip address - to its template. Context processors let
you specify a number of variables that get set in each context automatically - without you having to specify the
variables in each render to response() call:
from d j a n g o . template i m p o r t l o a d e r , R e q u e s t C o n t e x t
Explanation:
• define function custom proc: is a context processor which takes an HttpRequest object and returns a
dictionary of variables to use in the template context.
• other view functions use RequestContext: the first argument has to be an HttpRequest and Request-
Context takes an optional processors argument, which is a list or tuple of context processor functions to
use.
• each view no longer has to include app, user or ip address in its context construction, because those are
provided by custom proc.
• each view still has the flexibility to introduce any custom template variables it might need. In this example,
the message template variable is set differently in each view.
Render to response() shortcut saves you from having to call loader.get template(), then create a Context, then
call the render() method on the template:
from d j a n g o . s h o r t c u t s i m p o r t r e n d e r t o r e s p o n s e
from d j a n g o . template i m p o r t R e q u e s t C o n t e x t
41
def custom proc ( request ) :
”A c o n t e x t p r o c e s s o r t h a t p r o v i d e s ’ app ’ , ’ u s e r ’ and ’ i p a d d r e s s ’ . ”
return {
’ app ’ : ’My app ’ ,
’ user ’ : request . user ,
’ i p a d d r e s s ’ : r e q u e s t .META[ ’REMOTE ADDR ’ ]
}
Using context processors doesn’t save you much typing if you have to type processors all the time. For that rea-
son, Django provides support for global context processors. The TEMPLATE CONTEXT PROCESSORS
setting designates which context processors should always be applied to RequestContext. This removes the need
to specify processors each time you use RequestContext.
• sql queries: a list of dictionaries representing every sql query that has happened so far during the request
and how long it took
42
9.2.3 django.core.context processors.i18n
• LANGUAGES: the value of LANGUAGES setting
• LANGUAGE CODE: the value of LANGUAGE CODE setting
To be a valid tag library, the module must contain a module-level variable named register that is a tem-
plate.Library instance. This template.Library instance is the data structure in which all the tags and filters are
registered. So, near the top of your module, insert the following:
from d j a n g o i m p o r t template
r e g i s t e r = template . L i b r a r y ( )
Once you’ve created this register variable, you’ll use it to create template filters and tags.
10 Deploying django
10.1 Using django with apache and mod python
mod python is an apache plugin that embeds python within apache and loads python code into memory when
the server starts: code stays in memory throughout the life of an apache process, which leads to significant
performance gains over other server arrangements.
43
Edit the config file and add:
<L o c a t i o n ” / d j a n g o / ”>
S e t H a n d l e r mod python
PythonHandler d j a n g o . c o r e . h a n d l e r s . modpython
SetEnv DJANGO SETTINGS MODULE e l i t e s o f t . s e t t i n g s
PythonOption d j a n g o . r o o t / d j a n g o
PythonDebug On
PythonPath ” [ ’ / home/ e l e a n o r / P r o j e c t s / d j a n g o ’ , ’ / home/ e l e a n o r / P r o j e c t s / d j a n g o / e l i t e s o f t ’ ] + s y s . path
”
</L o c a t i o n >
then all URL patterns will need to start with ”/mysite/”: deploy django at the root of your domain or edit
URLconf to also contain the /mysite/ level.
Apache should have access to files settings.py and database (you also need to grant access to all parent direc-
tories):
chmod 777 e l i t e s o f t d a t a b a s e
chmod 777 s e t t i n g s . py
Changing the read/write permissions to directories (you need that so apache can have access to files it needs):
eleanor@elitesoft ˜/ P r o j e c t s / d j a n g o $ chown e l e a n o r : apache /home/ e l e a n o r /
eleanor@elitesoft ˜/ P r o j e c t s / d j a n g o $ chown e l e a n o r : apache /home/ e l e a n o r / P r o j e c t s /
eleanor@elitesoft ˜/ P r o j e c t s / d j a n g o $ chown e l e a n o r : apache /home/ e l e a n o r / P r o j e c t s / d j a n g o
eleanor@elitesoft ˜/ P r o j e c t s / d j a n g o $ chown e l e a n o r : apache /home/ e l e a n o r / P r o j e c t s / d j a n g o / e l i t e s o f t
eleanor@elitesoft ˜/ P r o j e c t s / d j a n g o $ chmod g+rwx /home/ e l e a n o r
eleanor@elitesoft ˜/ P r o j e c t s / d j a n g o $ chmod g+rwx /home/ e l e a n o r / P r o j e c t s /
eleanor@elitesoft ˜/ P r o j e c t s / d j a n g o $ chmod g+rwx /home/ e l e a n o r / P r o j e c t s / d j a n g o
eleanor@elitesoft ˜/ P r o j e c t s / d j a n g o $ chmod g+rwx /home/ e l e a n o r / P r o j e c t s / d j a n g o / e l i t e s o f t
Then you have to serve static pages (images, style sheets, video): django itself doesn’t serve that, but leaves
the job to whichever web server you choose.
• create a symbolic link to the admin files from within your document root (all your django related files -
code and templates - will stay in one place)
• copy the admin media files so that they live within your apache document root
44
W S G I S c r i p t A l i a s / /< d i r >/d j a n g o . w s g i
<D i r e c t o r y /< p a r e n t d i r /<p r o j e c t n a m e >
Order deny , a l l o w
Allow from a l l
</ D i r e c t o r y >
11 Django Models
Each model maps to a single database table. The only required part of a model is the list of database fields it
defines which can have specific types (should be an appropriate Field class).
Each field takes a certain set of field-specific arguments (CharField requires a max length argument). There is
also a set of common arguments avilable to all field types:
• null: if true, django will store empty values as NULL in the database
• choices: an iterable list/tuple of 2-tuples to use as choices for this field - django will use the select box
instead of the standard text field and will limit choices to the choices given (first element == value that
will be stored in the database ; second element == will be displayed by the admin interface
• default: default value for the field (can be a value of a callable object - will be called every time a new
object is created)
• help text: extra text help to be displayed under the field on the object’s admin form
• primary key: if true, this field is the primary key for the model (oterwise django will automatically add
an IntegerField to hold the primary key)
11.2 Relationships
Relations are: many-to-one, many-to-many and one-to-one.
45
11.2.1 many-to-one
Use ForeignKey: use it just like any other Field type (by including it as a class attribute of your model).
Example: a Car model has a Manufacturer - that is, a Manufacturer makes multiple cars but each Car only has
one Manufacturer - use the following definitions:
c l a s s M a n u f a c t u r e r ( models . Model ) :
# ...
It’s suggested, but not required, that the name of a ForeignKey field (manufacturer in the example above) be
the name of the model, lowercase. You can, of course, call the field whatever you want.
11.2.2 many-to-many
Use ManyToManyField: use it by including it as a class attribute of your model.
Example: a Pizza has multiple Topping objects - that is, a Topping can be on multiple pizzas and each
Pizza has multiple toppings:
c l a s s Topping ( models . Model ) :
# ...
c l a s s P i z z a ( models . Model ) :
# ...
t o p p i n g s = models . ManyToManyField ( Topping )
It’s suggested, but not required, that the name of a ManyToManyField (toppings in the example above) be a
plural describing the set of related model objects.
It doesn’t matter which model gets the ManyToManyField, but you only need it in one of the models - not in
both.
11.2.3 one-to-one
Use OneToOneField. OneToOneField requires a positional argument: the class to which the model is related.
12 Database design
12.1 Primary key
Primary key is used to uniquely identify each row of a relational table: often just an ID of the table, but can be
any number of attributes. The question arises: How can we uniquely identify a table row? The primary
key can only occur once in the primery key column of a table.
46
customer id FirstName LastName PhoneNumber
1 John Smith 123456789
2 John Connor 987654321
we could try to select a customer in this table by searching for customer’s first name: not a good idea, because
there are two johns in the table (impossible to select the john you want). You could search for combination of
first and last name, but it’s not as efficient. Define the customer id instead.
here the customer id is a foreign key (can be used to refer to given customer) in order table, which can be
used to reference a customer stored in the customer table.
You define a foreign key in database to model relationship in the real world: relationships between pairs of
tables, which can be: one-to-one, one-to-many, many-to-many.
Tables that are related in a one-to-one relationship should always have the same primary key, which will
serve as the join column.
13 Django tips
13.1 Make TEMPLATE DIRS in settings.py relative
Edit the settings.py like this:
ROOT PATH = o s . path . dirname ( file )
TEMPLATE DIRS = (
( o s . path . j o i n (ROOT PATH, ’ templates ’ ) ) ,
47
13.2 save foreign keys as objects
If you want the values to have the foreign keys as actual objects rather than just ids:
d i c t ( [ ( f . name , g e t a t t r ( o bj , f . name ) ) f o r f i n o b j . meta . f i e l d s ] )
c l a s s Meta :
a b s t r a c t = True
c l a s s StudentSubject ( BaseStudent ) :
pass
c l a s s StudentGrades ( BaseStudent ) :
pass
c l a s s PeriodExamsForm ( f o r m s . Form ) :
e x a m i d = f o r m s . M o d e l M u l t i p l e C h o i c e F i e l d ( q u e r y s e t=S u b j e c t . o b j e c t s . a l l ( ) )
exam date = f o r m s . D a t e F i e l d ( r e q u i r e d=True , w i d g e t=AdminDateWidget ( ) )
e x a m p r o f e s s o r =f o r m s . M o d e l M u l t i p l e C h o i c e F i e l d ( q u e r y s e t=P r o f e s s o r . o b j e c t s . a l l ( ) )
{% b l o c k c o n t e n t j a v a s c r i p t %}
< s c r i p t t y p e=” t e x t / j a v a s c r i p t ” s r c=” / my admin / j s i 1 8 n / ”></ s c r i p t >
< s c r i p t t y p e=” t e x t / j a v a s c r i p t ” s r c=” / media / admin / media / j s / c o r e . j s ”></ s c r i p t >
< s c r i p t t y p e=” t e x t / j a v a s c r i p t ” s r c=” / admin / j s i 1 8 n / ”></ s c r i p t >
< l i n k r e l=” s t y l e s h e e t ” t y p e=” t e x t / c s s ” h r e f=” / admin / media / c s s / f o r m s . c s s ”/>
< l i n k r e l=” s t y l e s h e e t ” t y p e=” t e x t / c s s ” h r e f=” / admin / media / c s s / b a s e . c s s ”/>
< l i n k r e l=” s t y l e s h e e t ” t y p e=” t e x t / c s s ” h r e f=” / admin / media / c s s / g l o b a l . c s s ”/>
< l i n k r e l=” s t y l e s h e e t ” t y p e=” t e x t / c s s ” h r e f=” / admin / media / c s s / w i d g e t s . c s s ”/>
{{ form . media }}
{% e n d b l o c k %}
{% b l o c k c o n t e n t b o d y %}
<t a b l e >
{{ form . a s t a b l e }}
</ t a b l e >
{% e n d b l o c k %}
48
# s e t t i n g s . py
MEDIA ROOT = o s . path . j o i n ( o s . path . dirname ( file ) , ” templates /” )
MEDIA ROOT2 = ” / u s r / l i b 6 4 / python2 . 6 / s i t e −p a c k a g e s / d j a n g o / c o n t r i b / ”
49