The Django Book User Manual

User Manual: Pdf

Open the PDF directly: View PDF PDF.
Page Count: 424

DownloadThe Django Book User Manual
Open PDF In BrowserView PDF
The Django Book
Release 2.0

Adrian Holovaty, Jacob Kaplan-Moss, et al.

May 08, 2014

Contents

1

About this book
1.1 Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2 About the Authors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.3 About the Technical Reviewer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3
3
4
4

2

Introduction

5

3

Chapter 1: Introduction to Django
3.1 What Is a Web Framework? .
3.2 The MVC Design Pattern . .
3.3 Django’s History . . . . . . .
3.4 How to Read This Book . . .

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

7
7
8
10
11

Chapter 2: Getting Started
4.1 Installing Python . . . . . . .
4.2 Installing Django . . . . . . .
4.3 Testing the Django installation
4.4 Setting Up a Database . . . .
4.5 Starting a Project . . . . . . .
4.6 What’s Next? . . . . . . . . .

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

13
13
14
16
16
18
20

Chapter 3: Views and URLconfs
5.1 Your First Django-Powered Page: Hello World
5.2 How Django Processes a Request . . . . . . .
5.3 Your Second View: Dynamic Content . . . . .
5.4 URLconfs and Loose Coupling . . . . . . . .
5.5 Your Third View: Dynamic URLs . . . . . . .
5.6 Django’s Pretty Error Pages . . . . . . . . . .
5.7 What’s next? . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

21
21
27
27
29
30
33
34

Chapter 4: Templates
6.1 Template System Basics . . . .
6.2 Using the Template System . .
6.3 Basic Template Tags and Filters
6.4 Philosophies and Limitations .
6.5 Using Templates in Views . . .
6.6 Template Loading . . . . . . .
6.7 Template Inheritance . . . . . .
6.8 What’s next? . . . . . . . . . .

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

35
35
36
43
49
50
51
55
58

4

5

6

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

i

7

Chapter 5: Models
7.1 The “Dumb” Way to Do Database Queries in Views
7.2 The MTV (or MVC) Development Pattern . . . . .
7.3 Configuring the Database . . . . . . . . . . . . . .
7.4 Your First App . . . . . . . . . . . . . . . . . . . .
7.5 Defining Models in Python . . . . . . . . . . . . . .
7.6 Your First Model . . . . . . . . . . . . . . . . . . .
7.7 Installing the Model . . . . . . . . . . . . . . . . .
7.8 Basic Data Access . . . . . . . . . . . . . . . . . .
7.9 Adding Model String Representations . . . . . . . .
7.10 Inserting and Updating Data . . . . . . . . . . . . .
7.11 Selecting Objects . . . . . . . . . . . . . . . . . . .
7.12 Deleting Objects . . . . . . . . . . . . . . . . . . .
7.13 What’s Next? . . . . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

Chapter 6: The Django Admin Site
8.1 The django.contrib packages . . . . . . . . . . . . . . . . . . .
8.2 Activating the Admin Interface . . . . . . . . . . . . . . . . .
8.3 Using the Admin Site . . . . . . . . . . . . . . . . . . . . . .
8.4 Adding Your Models to the Admin Site . . . . . . . . . . . . .
8.5 How the Admin Site Works . . . . . . . . . . . . . . . . . . .
8.6 Making Fields Optional . . . . . . . . . . . . . . . . . . . . .
8.7 Customizing Field Labels . . . . . . . . . . . . . . . . . . . .
8.8 Custom ModelAdmin classes . . . . . . . . . . . . . . . . . .
8.9 Users, Groups, and Permissions . . . . . . . . . . . . . . . . .
8.10 When and Why to Use the Admin Interface – And When Not to
8.11 What’s Next? . . . . . . . . . . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

81
. 81
. 81
. 82
. 89
. 89
. 90
. 92
. 92
. 102
. 102
. 103

Chapter 7: Forms
9.1 Getting Data From the Request Object . . . . .
9.2 A Simple Form-Handling Example . . . . . . .
9.3 Improving Our Simple Form-Handling Example
9.4 Simple validation . . . . . . . . . . . . . . . . .
9.5 Making a Contact Form . . . . . . . . . . . . .
9.6 Your First Form Class . . . . . . . . . . . . . .
9.7 Tying Form Objects Into Views . . . . . . . . .
9.8 Changing How Fields Are Rendered . . . . . . .
9.9 Setting a Maximum Length . . . . . . . . . . .
9.10 Setting Initial Values . . . . . . . . . . . . . . .
9.11 Custom Validation Rules . . . . . . . . . . . . .
9.12 Specifying labels . . . . . . . . . . . . . . . . .
9.13 Customizing Form Design . . . . . . . . . . . .
9.14 What’s Next? . . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

105
105
107
110
111
113
116
118
119
120
120
120
121
121
123

10 Chapter 8: Advanced Views and URLconfs
10.1 URLconf Tricks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.2 Including Other URLconfs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.3 What’s Next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

125
125
139
142

11 Chapter 9: Advanced Templates
11.1 Template Language Review . . . . . .
11.2 RequestContext and Context Processors
11.3 Automatic HTML Escaping . . . . . .
11.4 Inside Template Loading . . . . . . . .
11.5 Extending the Template System . . . .

143
143
144
148
150
151

9

ii

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

61
61
62
63
65
66
67
68
71
72
73
74
79
80

.
.
.
.
.
.
.
.
.
.
.
.
.

8

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

11.6 Writing Custom Template Loaders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
11.7 Configuring the Template System in Standalone Mode . . . . . . . . . . . . . . . . . . . . . . . . . 161
11.8 What’s Next . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
12 Chapter 10: Advanced Models
12.1 Related Objects . . . . . . . . . . . . .
12.2 Making Changes to a Database Schema
12.3 Managers . . . . . . . . . . . . . . . .
12.4 Model methods . . . . . . . . . . . . .
12.5 Executing Raw SQL Queries . . . . . .
12.6 What’s Next? . . . . . . . . . . . . . .

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

163
163
165
167
170
171
171

13 Chapter 11: Generic Views
13.1 Using Generic Views . . .
13.2 Generic Views of Objects
13.3 Extending Generic Views
13.4 What’s Next? . . . . . . .

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

173
173
174
176
180

14 Chapter 12: Deploying Django
14.1 Preparing Your Codebase for Production . .
14.2 Using Different Settings for Production . . .
14.3 DJANGO_SETTINGS_MODULE . . . . .
14.4 Using Django with Apache and mod_python
14.5 Using Django with FastCGI . . . . . . . . .
14.6 Scaling . . . . . . . . . . . . . . . . . . . .
14.7 Performance Tuning . . . . . . . . . . . . .
14.8 What’s Next? . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

181
181
183
185
185
188
193
198
199

15 Chapter 13: Generating Non-HTML Content
15.1 The basics: views and MIME-types . . .
15.2 Producing CSV . . . . . . . . . . . . . .
15.3 Generating PDFs . . . . . . . . . . . . .
15.4 Other Possibilities . . . . . . . . . . . .
15.5 The Syndication Feed Framework . . . .
15.6 The Sitemap Framework . . . . . . . . .
15.7 What’s Next? . . . . . . . . . . . . . . .

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

201
201
202
203
205
205
211
215

16 Chapter 14: Sessions, Users, and Registration
16.1 Cookies . . . . . . . . . . . . . . . . . . .
16.2 Django’s Session Framework . . . . . . .
16.3 Users and Authentication . . . . . . . . .
16.4 Permissions, Groups and Messages . . . .
16.5 What’s Next . . . . . . . . . . . . . . . .

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

217
217
219
224
232
234

17 Chapter 15: Caching
17.1 Setting Up the Cache . . . . . . . . . . .
17.2 The Per-Site Cache . . . . . . . . . . . .
17.3 The Per-View Cache . . . . . . . . . . .
17.4 Template Fragment Caching . . . . . . .
17.5 The Low-Level Cache API . . . . . . . .
17.6 Upstream Caches . . . . . . . . . . . . .
17.7 Using Vary Headers . . . . . . . . . . .
17.8 Controlling Cache: Using Other Headers
17.9 Other Optimizations . . . . . . . . . . .
17.10 Order of MIDDLEWARE_CLASSES . .

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

235
235
238
239
240
241
242
243
244
245
245

.
.
.
.
.
.
.
.
.
.

iii

17.11 What’s Next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246
18 Chapter 16: django.contrib
18.1 The Django Standard Library
18.2 Sites . . . . . . . . . . . . .
18.3 Flatpages . . . . . . . . . . .
18.4 Redirects . . . . . . . . . . .
18.5 CSRF Protection . . . . . . .
18.6 Humanizing Data . . . . . . .
18.7 Markup Filters . . . . . . . .
18.8 What’s Next? . . . . . . . . .

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

247
247
248
253
256
257
259
260
260

19 Chapter 17: Middleware
19.1 What’s Middleware? . .
19.2 Middleware Installation
19.3 Middleware Methods . .
19.4 Built-in Middleware . .
19.5 What’s Next? . . . . . .

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

263
263
264
264
266
268

20 Chapter 18: Integrating with Legacy Databases and Applications
20.1 Integrating with a Legacy Database . . . . . . . . . . . . . . .
20.2 Integrating with an Authentication System . . . . . . . . . . .
20.3 Integrating with Legacy Web Applications . . . . . . . . . . .
20.4 What’s Next? . . . . . . . . . . . . . . . . . . . . . . . . . . .

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

269
269
271
272
273

21 Chapter 19: Internationalization
21.1 1. How to Specify Translation Strings . . . . . .
21.2 2. How to Create Language Files . . . . . . . .
21.3 3. How Django Discovers Language Preference .
21.4 Using Translations in Your Own Projects . . . .
21.5 The set_language Redirect View . . . . . .
21.6 Translations and JavaScript . . . . . . . . . . .
21.7 Notes for Users Familiar with gettext . . . .
21.8 gettext on Windows . . . . . . . . . . . . .
21.9 What’s Next? . . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

275
276
280
282
284
285
286
287
288
288

22 Chapter 20: Security
22.1 The Theme of Web Security
22.2 SQL Injection . . . . . . .
22.3 Cross-Site Scripting (XSS) .
22.4 Cross-Site Request Forgery
22.5 Session Forging/Hijacking .
22.6 E-mail Header Injection . .
22.7 Directory Traversal . . . . .
22.8 Exposed Error Messages . .
22.9 A Final Word on Security .
22.10 What’s Next? . . . . . . . .

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

289
289
289
291
292
292
294
294
295
296
296

23 Appendix A: Model Definition Reference
23.1 Fields . . . . . . . . . . . . . . . . .
23.2 Universal Field Options . . . . . . .
23.3 Relationships . . . . . . . . . . . . .
23.4 Model Metadata Options . . . . . . .

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

297
297
302
305
307

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

24 Appendix B: Database API Reference

iv

.
.
.
.
.
.
.
.
.
.

311

24.1
24.2
24.3
24.4
24.5
24.6
24.7
24.8
24.9
24.10
24.11

Creating Objects . . . . . . . . .
Saving Changes to Objects . . . .
Retrieving Objects . . . . . . . .
Caching and QuerySets . . . . .
Filtering Objects . . . . . . . . .
Field Lookups . . . . . . . . . .
Complex Lookups with Q Objects
Related Objects . . . . . . . . . .
Deleting Objects . . . . . . . . .
Shortcuts . . . . . . . . . . . . .
Falling Back to Raw SQL . . . .

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

311
313
314
314
315
322
325
326
330
330
331

25 Appendix C: Generic View Reference
25.1 Common Arguments to Generic Views
25.2 “Simple” Generic Views . . . . . . . .
25.3 List/Detail Generic Views . . . . . . .
25.4 Date-Based Generic Views . . . . . . .

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

333
333
334
335
338

26 Appendix D: Settings
26.1 What’s a Settings File? . . . . . . . . . . . . . . . . . . . . . . . .
26.2 Designating the Settings: DJANGO_SETTINGS_MODULE . . . .
26.3 Using Settings Without Setting DJANGO_SETTINGS_MODULE .
26.4 Available Settings . . . . . . . . . . . . . . . . . . . . . . . . . .

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

349
349
350
351
353

27 Appendix E: Built-in Template Tags and Filters
365
27.1 Built-in Tag Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365
27.2 Built-in Filter Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376
28 Appendix F: The django-admin Utility
28.1 Usage . . . . . . . . . . . . . . . .
28.2 Available subcommands . . . . . .
28.3 Default options . . . . . . . . . . .
28.4 Extra niceties . . . . . . . . . . . .

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

389
389
390
398
399

29 Appendix G: Request and Response Objects
401
29.1 HttpRequest . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
29.2 HttpResponse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406
30 License & Copyright
411
30.1 GNU Free Documentation License . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411

v

vi

The Django Book, Release 2.0

Welcome to the online version of The Django Book, a free book about the Django Web framework for the Python
programming language.
A warning about this edition
The community edition of The Django Book is in transition. While the book mentions Django version 1.4 in places,
the vast majority of the book is for Django version 1.0, which was released over four years ago. Therefore this resource
is extremely out of date and, until the book is finished being updated, we ask that, at this time, djangobook.com not
be used for educational purposes.
This book was originally published by Apress in 2009 and covered Django version 1.0. Since then it has languished
and, in places, is extremely out of date. We are working on getting the book updated to cover Django versions 1.4,
1.5, and beyond. But we need your help, we’re making this book — warts and all — open source in the hopes that it
will find love as a community project.
So, if you’d like to help out, hop on over to GitHub and send us a pull request!

Contents

1

The Django Book, Release 2.0

2

Contents

CHAPTER 1

About this book

You’re reading The Django Book, first published in December 2007 (and updated in 2009) by Apress as The Definitive
Guide to Django: Web Development Done Right.
We’ve released this book freely for a couple of reasons. First, we love Django and we want it to be as accessible as
possible. Many programmers learn their craft from well-written technical material, so we set out to create a top-notch
guide and reference to Django.
Second, it turns out that writing books about technology is fundamentally difficult: your words are often outdated
before the book even reaches the printer. On the web, however, “the ink is never dry” — we can (and will!) keep the
book updated.

1.1 Acknowledgements
The most gratifying aspect of working on Django is the community. We’ve been especially lucky that Django has
attracted such a smart, motivated, and friendly bunch. A segment of that community followed us over to the online
“beta” release of this book. Their reviews and comments were indispensable; this book wouldn’t have been possible
without all that wonderful peer review. Almost a thousand people left comments that helped us improve the clarity,
quality, and flow of the final book; we’d like to thank each and every one of them.
We’re especially grateful to those who took the time to review the book in depth and left dozens (sometimes hundreds)
of comments apiece: Marty Alchin, Max Battcher, Oliver Beat- tie, Rod Begbie, Paul Bissex, Matt Boersma, Robbin
Bonthond, Peter Bowyer, Nesta Campbell, Jon Colverson, Jeff Croft, Chris Dary, Alex Dong, Matt Drew, Robert
Dzikowski, Nick Efford, Ludvig Ericson, Eric Floehr, Brad Fults, David Grant, Simon Greenhill, Robert Haveman, Kent Johnson, Andrew Kember, Marek Kubica, Eduard Kucera, Anand Kumria, Scott Lamb, Fredrik Lundh,
Vadim Macagon, Markus Majer, Orestis Markou, R. Mason, Yasushi Masuda, Kevin Menard, Carlo Miron, James
Mulholland, R.D. Nielsen, Michael O’Keefe, Lawrence Oluyede, Andreas Pfrengle, Frankie Robertson, Mike Robinson, Armin Ronacher, Daniel Roseman, Johan Samyn, Ross Shannon, Carolina F. Silva, Paul Smith, Björn Stabell,
Bob Stepno, Graeme Stevenson, Justin Stockton, Kevin Teague, Daniel Tietze, Brooks Travis, Peter Tripp, Matthias
Urlichs, Peter van Kampen, Alexandre Vassalotti, Jay Wang, Brian Will, and Joshua Works.
Many thanks to our technical editor, Jeremy Dunck. Without Jeremy this book would be littered with errors, inaccuracies, and broken code. We feel very lucky that someone as talented as Jeremy found the time to help us out.
Specials thanks go to Simon Willison for writing the chapter on form processing. We really appreciate the help, and
we’re thrilled that Simon’s excellent writing can be part of this book.
We’re grateful for all the hard work the folks at Apress put into this book. They’ve been amazingly supportive and
patient; this book wouldn’t have come together without a lot of work on their part. We’re especially happy that Apress
supported and even encouraged the free release of this book online; it’s wonderful seeing a publisher so embracing the
spirit of open source.

3

The Django Book, Release 2.0

Finally, of course, thanks to our friends, families, and coworkers who’ve graciously tolerated our mental absence while
we finished this work.

1.2 About the Authors
Adrian Holovaty is a Web developer with a background in journalism. He’s known in journalism circles as one of the
pioneers of “journalism via computer programming”, and in technical circles as “the guy who invented Django.”
He was lead developer at World Online for 2.5 years, during which time Django was developed and implemented on
World Online’s sites. He’s the founder of EveryBlock, a “news feed for your block”.
Adrian lives in Chicago, USA.
Jacob Kaplan-Moss is a partner at Revolution Systems which provides support services around Django and related
open source technologies. Jacob previously worked at World Online, where Django was invented, where he was the
lead developer of Ellington, a commercial Web publishing platform for media companies.
Jacob lives in Lawrence, Kansas, USA.

1.3 About the Technical Reviewer
Jeremy Dunck was rescued from corporate IT drudgery by Free Software and, in part, Django. Many of Jeremy’s
interests center around access to information.
Jeremy was the lead developer of Pegasus News, one of the first uses of Django outside World Online, and has since
joined Votizen, a startup intent on reducing the influence of money in politics.
He serves as DSF Secretary, organizes and helps organize sprints, cares about the health and equity of the Django
community. He has gone an embarrassingly long time without a working blog.
Jeremy lives in Mountain View, CA, USA.

4

Chapter 1. About this book

CHAPTER 2

Introduction

In the early days, Web developers wrote every page by hand. Updating a Web site meant editing HTML; a “redesign”
involved redoing every single page, one at a time.
As Web sites grew and became more ambitious, it quickly became obvious that that situation was tedious, timeconsuming, and ultimately untenable. A group of enterprising hackers at NCSA (the National Center for Supercomputing Applications, where Mosaic, the first graphical Web browser, was developed) solved this problem by letting the
Web server spawn external programs that could dynamically generate HTML. They called this protocol the Common
Gateway Interface, or CGI, and it changed the Web forever.
It’s hard now to imagine what a revelation CGI must have been: instead of treating HTML pages as simple files on
disk, CGI allows you to think of your pages as resources generated dynamically on demand. The development of CGI
ushered in the first generation of dynamic Web sites.
However, CGI has its problems: CGI scripts need to contain a lot of repetitive “boilerplate” code, they make code
reuse difficult, and they can be difficult for first-time developers to write and understand.
PHP fixed many of these problems, and it took the world by storm – it’s now by far the most popular tool used to
create dynamic Web sites, and dozens of similar languages and environments (ASP, JSP, etc.) followed PHP’s design
closely. PHP’s major innovation is its ease of use: PHP code is simply embedded into plain HTML; the learning curve
for someone who already knows HTML is extremely shallow.
But PHP has its own problems; its very ease of use encourages sloppy, repetitive, ill-conceived code. Worse, PHP does
little to protect programmers from security vulnerabilities, and thus many PHP developers found themselves learning
about security only once it was too late.
These and similar frustrations led directly to the development of the current crop of “third-generation” Web development frameworks. These frameworks – Django and Ruby on Rails appear to be the most popular these days –
recognize that the Web’s importance has escalated of late. With this new explosion of Web development comes yet
another increase in ambition; Web developers are expected to do more and more every day.
Django was invented to meet these new ambitions. Django lets you build deep, dynamic, interesting sites in an
extremely short time. Django is designed to let you focus on the fun, interesting parts of your job while easing the pain
of the repetitive bits. In doing so, it provides high-level abstractions of common Web development patterns, shortcuts
for frequent programming tasks, and clear conventions on how to solve problems. At the same time, Django tries to
stay out of your way, letting you work outside the scope of the framework as needed. We wrote this book because
we firmly believe that Django makes Web development better. It’s designed to quickly get you moving on your own
Django projects, and then ultimately teach you everything you need to know to successfully design, develop, and
deploy a site that you’ll be proud of.
We’re extremely interested in your feedback. This book is open source and all are welcome to improve it. If you
prefer to suggest changes, please drop us a line at feedback@djangobook.com. Either way, we’d love to hear from
you! We’re glad you’re here, and we hope that you find Django as exciting, fun and useful as we do.

5

The Django Book, Release 2.0

6

Chapter 2. Introduction

CHAPTER 3

Chapter 1: Introduction to Django

This book is about Django, a Web development framework that saves you time and makes Web development a joy.
Using Django, you can build and maintain high-quality Web applications with minimal fuss.
At its best, Web development is an exciting, creative act; at its worst, it can be a repetitive, frustrating nuisance.
Django lets you focus on the fun stuff – the crux of your Web application – while easing the pain of the repetitive
bits. In doing so, it provides high-level abstractions of common Web development patterns, shortcuts for frequent
programming tasks, and clear conventions for how to solve problems. At the same time, Django tries to stay out of
your way, letting you work outside the scope of the framework as needed.
The goal of this book is to make you a Django expert. The focus is twofold. First, we explain, in depth, what
Django does and how to build Web applications with it. Second, we discuss higher-level concepts where appropriate,
answering the question “How can I apply these tools effectively in my own projects?” By reading this book, you’ll
learn the skills needed to develop powerful Web sites quickly, with code that is clean and easy to maintain.

3.1 What Is a Web Framework?
Django is a prominent member of a new generation of Web frameworks – but what does that term mean, precisely?
To answer that question, let’s consider the design of a Web application written in Python without a framework.
Throughout this book, we’ll take this approach of showing you basic ways of getting work done without shortcuts, in
the hope that you’ll recognize why shortcuts are so helpful. (It’s also valuable to know how to get things done without
shortcuts because shortcuts aren’t always available. And most importantly, knowing why things work the way they do
makes you a better Web developer.)
One of the simplest, most direct ways to build a Python Web app from scratch is to use the Common Gateway Interface
(CGI) standard, which was a popular technique circa 1998. Here’s a high-level explanation of how it works: just create
a Python script that outputs HTML, then save the script to a Web server with a ”.cgi” extension and visit the page in
your Web browser. That’s it.
Here’s an example Python CGI script that displays the ten most recently published books from a database. Don’t
worry about syntax details; just get a feel for the basic things it’s doing:
#!/usr/bin/env python
import MySQLdb
print
print
print
print
print

"Content-Type: text/html\n"
"Books"
""
"

Books

" "
    " 7 The Django Book, Release 2.0 connection = MySQLdb.connect(user=’me’, passwd=’letmein’, db=’my_db’) cursor = connection.cursor() cursor.execute("SELECT name FROM books ORDER BY pub_date DESC LIMIT 10") for row in cursor.fetchall(): print "
  • %s
  • " % row[0] print "
" print "" connection.close() First, to fulfill the requirements of CGI, this code prints a “Content-Type” line, followed by a blank line. It prints some introductory HTML, connects to a database and runs a query to retrieve the names of the latest ten books. Looping over those books, it generates an HTML list of the titles. Finally, it prints the closing HTML and closes the database connection. With a one-off page like this one, the write-it-from-scratch approach isn’t necessarily bad. For one thing, this code is simple to comprehend – even a novice developer can read these 16 lines of Python and understand everything it does, from start to finish. There’s nothing else to learn, no other code to read. It’s also simple to deploy: just save this code in a file that ends with ”.cgi”, upload that file to a Web server, and visit that page with a browser. But despite its simplicity, this approach has a number of problems and annoyances. Ask yourself these questions: • What happens when multiple parts of your application need to connect to the database? Surely that databaseconnecting code shouldn’t need to be duplicated in each individual CGI script. The pragmatic thing to do would be to refactor it into a shared function. • Should a developer really have to worry about printing the “Content-Type” line and remembering to close the database connection? This sort of boilerplate reduces programmer productivity and introduces opportunities for mistakes. These setup- and teardown-related tasks would best be handled by some common infrastructure. • What happens when this code is reused in multiple environments, each with a separate database and password? At this point, some environment-specific configuration becomes essential. • What happens when a Web designer who has no experience coding Python wishes to redesign the page? One wrong character could crash the entire application. Ideally, the logic of the page – the retrieval of book titles from the database – would be separate from the HTML display of the page, so that a designer could edit the latter without affecting the former. These problems are precisely what a Web framework intends to solve. A Web framework provides a programming infrastructure for your applications, so that you can focus on writing clean, maintainable code without having to reinvent the wheel. In a nutshell, that’s what Django does. 3.2 The MVC Design Pattern Let’s dive in with a quick example that demonstrates the difference between the previous approach and a Web framework’s approach. Here’s how you might write the previous CGI code using Django. The first thing to note is that that we split it over four Python files (models.py, views.py, urls.py) and an HTML template (latest_books.html): # models.py (the database tables) from django.db import models class Book(models.Model): name = models.CharField(max_length=50) 8 Chapter 3. Chapter 1: Introduction to Django The Django Book, Release 2.0 pub_date = models.DateField() # views.py (the business logic) from django.shortcuts import render from models import Book def latest_books(request): book_list = Book.objects.order_by(’-pub_date’)[:10] return render(request, ’latest_books.html’, {’book_list’: book_list}) # urls.py (the URL configuration) from django.conf.urls.defaults import * import views urlpatterns = patterns(’’, (r’^latest/$’, views.latest_books), ) # latest_books.html (the template) Books

Books

    {% for book in book_list %}
  • {{ book.name }}
  • {% endfor %}
Again, don’t worry about the particulars of syntax; just get a feel for the overall design. The main thing to note here is the separation of concerns: • The models.py file contains a description of the database table, represented by a Python class. This class is called a model. Using it, you can create, retrieve, update and delete records in your database using simple Python code rather than writing repetitive SQL statements. • The views.py file contains the business logic for the page. The latest_books() function is called a view. • The urls.py file specifies which view is called for a given URL pattern. In this case, the URL /latest/ will be handled by the latest_books() function. In other words, if your domain is example.com, any visit to the URL http://example.com/latest/ will call the latest_books() function. • The latest_books.html file is an HTML template that describes the design of the page. It uses a template language with basic logic statements – e.g., {% for book in book_list %}. Taken together, these pieces loosely follow a pattern called Model-View-Controller (MVC). Simply put, MVC is way of developing software so that the code for defining and accessing data (the model) is separate from request-routing logic (the controller), which in turn is separate from the user interface (the view). (We’ll discuss MVC in more depth in Chapter 5.) A key advantage of such an approach is that components are loosely coupled. Each distinct piece of a Django-powered Web application has a single key purpose and can be changed independently without affecting the other pieces. For example, a developer can change the URL for a given part of the application without affecting the underlying imple- 3.2. The MVC Design Pattern 9 The Django Book, Release 2.0 mentation. A designer can change a page’s HTML without having to touch the Python code that renders it. A database administrator can rename a database table and specify the change in a single place, rather than having to search and replace through a dozen files. In this book, each component of MVC gets its own chapter. Chapter 3 covers views, Chapter 4 covers templates, and Chapter 5 covers models. 3.3 Django’s History Before we dive into more code, we should take a moment to explain Django’s history. We noted above that we’ll be showing you how to do things without shortcuts so that you more fully understand the shortcuts. Similarly, it’s useful to understand why Django was created, because knowledge of the history will put into context why Django works the way it does. If you’ve been building Web applications for a while, you’re probably familiar with the problems in the CGI example we presented earlier. The classic Web developer’s path goes something like this: 1. Write a Web application from scratch. 2. Write another Web application from scratch. 3. Realize the application from step 1 shares much in common with the application from step 2. 4. Refactor the code so that application 1 shares code with application 2. 5. Repeat steps 2-4 several times. 6. Realize you’ve invented a framework. This is precisely how Django itself was created! Django grew organically from real-world applications written by a Web development team in Lawrence, Kansas, USA. It was born in the fall of 2003, when the Web programmers at the Lawrence Journal-World newspaper, Adrian Holovaty and Simon Willison, began using Python to build applications. The World Online team, responsible for the production and maintenance of several local news sites, thrived in a development environment dictated by journalism deadlines. For the sites – including LJWorld.com, Lawrence.com and KUsports.com – journalists (and management) demanded that features be added and entire applications be built on an intensely fast schedule, often with only days’ or hours’ notice. Thus, Simon and Adrian developed a time-saving Web development framework out of necessity – it was the only way they could build maintainable applications under the extreme deadlines. In summer 2005, after having developed this framework to a point where it was efficiently powering most of World Online’s sites, the team, which now included Jacob Kaplan-Moss, decided to release the framework as open source software. They released it in July 2005 and named it Django, after the jazz guitarist Django Reinhardt. Now, several years later, Django is a well-established open source project with tens of thousands of users and contributors spread across the planet. Two of the original World Online developers (the “Benevolent Dictators for Life,” Adrian and Jacob) still provide central guidance for the framework’s growth, but it’s much more of a collaborative team effort. This history is relevant because it helps explain two key things. The first is Django’s “sweet spot.” Because Django was born in a news environment, it offers several features (such as its admin site, covered in Chapter 6) that are particularly well suited for “content” sites – sites like Amazon.com, craigslist.org, and washingtonpost.com that offer dynamic, database-driven information. Don’t let that turn you off, though – although Django is particularly good for developing those sorts of sites, that doesn’t preclude it from being an effective tool for building any sort of dynamic Web site. (There’s a difference between being particularly effective at something and being ineffective at other things.) The second matter to note is how Django’s origins have shaped the culture of its open source community. Because Django was extracted from real-world code, rather than being an academic exercise or commercial product, it is acutely 10 Chapter 3. Chapter 1: Introduction to Django The Django Book, Release 2.0 focused on solving Web development problems that Django’s developers themselves have faced – and continue to face. As a result, Django itself is actively improved on an almost daily basis. The framework’s maintainers have a vested interest in making sure Django saves developers time, produces applications that are easy to maintain and performs well under load. If nothing else, the developers are motivated by their own selfish desires to save themselves time and enjoy their jobs. (To put it bluntly, they eat their own dog food.) 3.4 How to Read This Book In writing this book, we tried to strike a balance between readability and reference, with a bias toward readability. Our goal with this book, as stated earlier, is to make you a Django expert, and we believe the best way to teach is through prose and plenty of examples, rather than providing an exhaustive but bland catalog of Django features. (As the saying goes, you can’t expect to teach somebody how to speak a language merely by teaching them the alphabet.) With that in mind, we recommend that you read Chapters 1 through 12 in order. They form the foundation of how to use Django; once you’ve read them, you’ll be able to build and deploy Django-powered Web sites. Specifically, Chapters 1 through 7 are the “core curriculum,” Chapters 8 through 11 cover more advanced Django usage, and Chapter 12 covers deployment. The remaining chapters, 13 through 20, focus on specific Django features and can be read in any order. The appendixes are for reference. They, along with the free documentation at http://www.djangoproject.com/, are probably what you’ll flip back to occasionally to recall syntax or find quick synopses of what certain parts of Django do. 3.4.1 Required Programming Knowledge Readers of this book should understand the basics of procedural and object-oriented programming: control structures (e.g., if, while, for), data structures (lists, hashes/dictionaries), variables, classes and objects. Experience in Web development is, as you may expect, very helpful, but it’s not required to understand this book. Throughout the book, we try to promote best practices in Web development for readers who lack this experience. 3.4.2 Required Python Knowledge At its core, Django is simply a collection of libraries written in the Python programming language. To develop a site using Django, you write Python code that uses these libraries. Learning Django, then, is a matter of learning how to program in Python and understanding how the Django libraries work. If you have experience programming in Python, you should have no trouble diving in. By and large, the Django code doesn’t perform a lot of “magic” (i.e., programming trickery whose implementation is difficult to explain or understand). For you, learning Django will be a matter of learning Django’s conventions and APIs. If you don’t have experience programming in Python, you’re in for a treat. It’s easy to learn and a joy to use! Although this book doesn’t include a full Python tutorial, it highlights Python features and functionality where appropriate, particularly when code doesn’t immediately make sense. Still, we recommend you read the official Python tutorial, available online at http://docs.python.org/tut/. We also recommend Mark Pilgrim’s free book Dive Into Python, available at http://www.diveintopython.net/ and published in print by Apress. 3.4.3 Required Django Version This book covers Django 1.4. 3.4. How to Read This Book 11 The Django Book, Release 2.0 Django’s developers maintain backwards compatibility as much as possible, but occasionally introduce some backwards incompatible changes. The changes in each release are always covered in the release notes, which you can find here: https://docs.djangoproject.com/en/dev/releases/1.X 3.4.4 Getting Help One of the greatest benefits of Django is its kind and helpful user community. For help with any aspect of Django – from installation, to application design, to database design, to deployment – feel free to ask questions online. • The django-users mailing list is where thousands of Django users hang out to ask and answer questions. Sign up for free at http://www.djangoproject.com/r/django-users. • The Django IRC channel is where Django users hang out to chat and help each other in real time. Join the fun by logging on to #django on the Freenode IRC network. 3.4.5 What’s Next In Chapter 2, we’ll get started with Django, covering installation and initial setup. 12 Chapter 3. Chapter 1: Introduction to Django CHAPTER 4 Chapter 2: Getting Started Installing Django is a multi-step process, due to the multiple moving parts in modern Web development environments. In this chapter, we’ll walk you through how to install the framework and its few dependencies. Because Django is “just” Python code, it runs anywhere Python does – including on some cell phones! But this chapter just covers the common scenarios for Django installations. We’ll assume you’re installing it either on a desktop/laptop machine or a server. Later, in Chapter 12, we’ll cover how to deploy Django to a production site. 4.1 Installing Python Django itself is written purely in Python, so the first step in installing the framework is to make sure you have Python installed. 4.1.1 Python Versions The core Django framework (version 1.4+) works with any Python version from 2.5 to 2.7, inclusive. Django’s optional GIS (Geographic Information Systems) support requires Python 2.5 to 2.7. If you’re not sure which version of Python to install and you have complete freedom over the decision, pick the latest one in the 2.x series: version 2.7. Although Django works equally well with any version from 2.5 to 2.7, the later versions of Python have performance improvements and additional language features you might like to use in your applications. Plus, certain third-party Django add-ons that you might want to use might require a version newer than Python 2.5, so using a later version of Python keeps your options open. Django and Python 3.x At the time of writing, Python 3.3 has been released, but Django only supports it experimentally. This is because the Python 3.x series introduces a substantial number of backwards-incompatible changes to the language itself, and, as a result, many major Python libraries and frameworks, including Django (as of version 1.4), have not yet caught up. Django 1.5 is slated to support Python 2.6, 2.7, and 3.2. However, support for Python 3.2 is considered a “preview”, which means the Django developers are not yet confident enough to promise stability in production. For that, they suggest you wait until Django 1.6. 13 The Django Book, Release 2.0 4.1.2 Installation If you’re on Linux or Mac OS X, you probably have Python already installed. Type python at a command prompt (or in Applications/Utilities/Terminal, in OS X). If you see something like this, then Python is installed: Python 2.7.3rc2 (default, Apr 22 2012, 22:30:17) [GCC 4.6.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> Otherwise, you’ll need to download and install Python. It’s fast and easy, and detailed instructions are available at http://www.python.org/download/ 4.2 Installing Django At any given time, two distinct versions of Django are available to you: the latest official release and the bleeding-edge development version. The version you decide to install depends on your priorities. Do you want a stable and tested version of Django, or do you want a version containing the latest features, perhaps so you can contribute to Django itself, at the expense of stability? We’d recommend sticking with an official release, but it’s important to know that the development version exists, because you’ll find it mentioned in the documentation and by members of the community. 4.2.1 Installing an Official Release Official releases have a version number, such as 1.4.2, 1.4.1 or 1.4, and the latest one is always available at http://www.djangoproject.com/download/. If you’re on a Linux distribution that includes a package of Django, it’s a good idea to use the distributor’s version. That way, you’ll get security updates along with the rest of your system packages. If you don’t have access to a prepackaged version, you can download and install the framework manually. To do so, first download the tarball, which will be named something like Django-1.4.2.tar.gz. (It doesn’t matter which local directory you download this file into; the installation process will put Django’s files in the right place.) Then, unzip it and run setup.py install, as you do with most Python libraries. Here’s how that process looks on Unix systems: 1. tar xzvf Django-1.4.2.tar.gz 2. cd Django-* 3. sudo python setup.py install On Windows, we recommend using 7-Zip (http://www.djangoproject.com/r/7zip/) to unzip .tar.gz files. Once you’ve unzipped the file, start up a DOS shell (the “Command Prompt”) with administrator privileges and run the following command from within the directory whose name starts with Django-: python setup.py install In case you’re curious: Django’s files will be installed into your Python installation’s site-packages directory – a directory where Python looks for third-party libraries. Usually it’s in a place like /usr/lib/python2.7/site-packages. 14 Chapter 4. Chapter 2: Getting Started The Django Book, Release 2.0 4.2.2 Installing the “Development” Version Django uses Git (http://git-scm.com) for its source control. The latest and greatest Django development version available from Django’s official Git repository (https://github.com/django/django). You should consider installing this version if you want to work on the bleeding edge, or if you want to contribute code to Django itself. Git is a free, open source distributed revision-control system, and the Django team uses it to manage changes to the Django codebase. You can download and install Git from http://git-scm.com/download but it is easier to install with your operating system’s package manager. You can use Git to grab the very latest Django source code and, at any given time, you can update your local version of the Django code to get the latest changes and improvements made by Django developers. When using the development version, keep in mind there’s no guarantee things won’t be broken at any given moment. With that said, though, some members of the Django team run production sites on the development version, so they have an incentive to keep it stable. To grab the latest Django, follow these steps: 1. Make sure you have Git installed. You can get the software free from http://git-scm.com/, and you can find excellent documentation at http://git-scm.com/documentation. 2. Clone the repository using the command git clone https://github.com/django/django djmaster 3. Locate your Python installation’s site-packages directory. Usually it’s in a place like /usr/lib/python2.7/site-packages. If you have no idea, type this command from a command prompt: python -c ’import sys, pprint; pprint.pprint(sys.path)’ The resulting output should include your site-packages directory. 4. Within the site-packages directory, create a file called djmaster.pth and edit it to contain the full path to your djmaster directory to it. For example, the file could just contain this line: /path/to/djmaster 5. Place djmaster/django/bin on your system PATH. This directory includes management utilities such as django-admin.py. Tip: If .pth files are new to you, you can learn more about them at http://www.djangoproject.com/r/python/site-module/. After downloading from Git and following the preceding steps, there’s no need to run python setup.py install– you’ve just done the work by hand! Because the Django code changes often with bug fixes and feature additions, you’ll probably want to update it every once in a while. To update the code, just run the command git pull origin master from within the djmaster directory. When you run that command, Git will contact https://github.com/django/django, determine whether any of Django’s code has changed, and update your local version of the code with any changes that have been made since you last updated. It’s quite slick. Finally, if you use Django development version, you should know how to figure out which version of Django you’re running. Knowing your version number is important if you ever need to reach out to the community for help, or if you submit improvements to the framework. In these cases, you should tell people the revision, also known as a “commit,” that you’re using. To find out your current commit, type “git log -1” from within the django directory, and look for the identifier after “commit”. This number changes each time Django is changed, whether through a bug fix, feature addition, documentation improvement or anything else. 4.2. Installing Django 15 The Django Book, Release 2.0 4.3 Testing the Django installation For some post-installation positive feedback, take a moment to test whether the installation worked. In a command shell, change into another directory (e.g., not the directory that contains the django directory) and start the Python interactive interpreter by typing python. If the installation was successful, you should be able to import the module django: >>> import django >>> django.VERSION (1, 4, 2, ’final’, 0) Interactive Interpreter Examples The Python interactive interpreter is a command-line program that lets you write a Python program interactively. To start it, run the command python at the command line. Throughout this book, we feature example Python interactive interpreter sessions. You can recognize these examples by the triple greater-than signs (>>>), which designate the interpreter’s prompt. If you’re copying examples from this book, don’t copy those greater-than signs. Multiline statements in the interactive interpreter are padded with three dots (...). For example: >>> print """This is a ... string that spans ... three lines.""" This is a string that spans three lines. >>> def my_function(value): ... print value >>> my_function(’hello’) hello Those three dots at the start of the additional lines are inserted by the Python shell – they’re not part of our input. We include them here to be faithful to the actual output of the interpreter. If you copy our examples to follow along, don’t copy those dots. 4.4 Setting Up a Database At this point, you could very well begin writing a Web application with Django, because Django’s only hard-and-fast prerequisite is a working Python installation. However, odds are you’ll be developing a database-driven Web site, in which case you’ll need to configure a database server. If you just want to start playing with Django, skip ahead to the “Starting a Project” section – but keep in mind that all the examples in this book assume you have a working database set up. Django supports four database engines: • PostgreSQL (http://www.postgresql.org/) • SQLite 3 (http://www.sqlite.org/) • MySQL (http://www.mysql.com/) • Oracle (http://www.oracle.com/) For the most part, all the engines here work equally well with the core Django framework. (A notable exception is Django’s optional GIS support, which is much more powerful with PostgreSQL than with other databases.) If you’re 16 Chapter 4. Chapter 2: Getting Started The Django Book, Release 2.0 not tied to any legacy system and have the freedom to choose a database backend, we recommend PostgreSQL, which achieves a fine balance between cost, features, speed and stability. Setting up the database is a two-step process: • First, you’ll need to install and configure the database server itself. This process is beyond the scope of this book, but each of the four database backends has rich documentation on its Web site. (If you’re on a shared hosting provider, odds are that they’ve set this up for you already.) • Second, you’ll need to install the Python library for your particular database backend. This is a third-party bit of code that allows Python to interface with the database. We outline the specific, per-database requirements in the following sections. If you’re just playing around with Django and don’t want to install a database server, consider using SQLite. SQLite is unique in the list of supported databases in that it doesn’t require either of the above steps. It merely reads and writes its data to a single file on your filesystem, and Python versions 2.5 and higher include built-in support for it. On Windows, obtaining database driver binaries can be frustrating. If you’re eager to jump in, we recommend using Python 2.7 and its built-in support for SQLite. 4.4.1 Using Django with PostgreSQL If you’re using PostgreSQL, you’ll need to install either the psycopg or psycopg2 package from http://www.djangoproject.com/r/python-pgsql/. We recommend psycopg2, as it’s newer, more actively developed and can be easier to install. Either way, take note of whether you’re using version 1 or 2; you’ll need this information later. If you’re using PostgreSQL on Windows, you http://www.djangoproject.com/r/python-pgsql/windows/. can find precompiled binaries of psycopg at If you’re on Linux, check whether your distribution’s package-management system offers a package called “pythonpsycopg2”, “psycopg2-python”, “python-postgresql” or something similar. 4.4.2 Using Django with SQLite 3 You’re in luck: no database-specific installation is required, because Python ships with SQLite support. Skip ahead to the next section. 4.4.3 Using Django with MySQL Django requires MySQL 4.0 or above. The 3.x versions don’t support nested subqueries and some other fairly standard SQL statements. You’ll also need to install the MySQLdb package from http://www.djangoproject.com/r/python-mysql/. If you’re on Linux, check whether your distribution’s package-management system offers a package called “pythonmysql”, “python-mysqldb”, “mysql-python” or something similar. 4.4.4 Using Django with Oracle Django works with Oracle Database Server versions 9i and higher. If you’re using Oracle, you’ll need to install the cx_Oracle library, available at http://cx-oracle.sourceforge.net/. Use version 4.3.1 or higher, but avoid version 5.0 due to a bug in that version of the driver. Version 5.0.1 resolved the bug, however, so you can choose a higher version as well. 4.4. Setting Up a Database 17 The Django Book, Release 2.0 4.4.5 Using Django Without a Database As mentioned earlier, Django doesn’t actually require a database. If you just want to use it to serve dynamic pages that don’t hit a database, that’s perfectly fine. With that said, bear in mind that some of the extra tools bundled with Django do require a database, so if you choose not to use a database, you’ll miss out on those features. (We highlight these features throughout this book.) 4.5 Starting a Project Once you’ve installed Python, Django and (optionally) your database server/library, you can take the first step in developing a Django application by creating a project. A project is a collection of settings for an instance of Django, including database configuration, Django-specific options and application-specific settings. If this is your first time using Django, you’ll have to take care of some initial setup. Create a new directory to start working in, perhaps something like /home/username/djcode/. Where Should This Directory Live? If your background is in PHP, you’re probably used to putting code under the Web server’s document root (in a place such as /var/www). With Django, you don’t do that. It’s not a good idea to put any of this Python code within your Web server’s document root, because in doing so you risk the possibility that people will be able to view your raw source code over the Web. That’s not good. Put your code in some directory outside of the document root. Change into the directory you created, and run the command django-admin.py startproject mysite. This will create a mysite directory in your current directory. Note: django-admin.py should be on your system path if you installed Django via its setup.py utility. If you’re using the development version, you’ll find django-admin.py in djmaster/django/bin. Because you’ll be using django-admin.py often, consider adding it to your system path. On Unix, you can do so by symlinking from /usr/local/bin, using a command such as sudo ln -s /path/to/django/bin/django-admin.py /usr/local/bin/django-admin.py. On Windows, you’ll need to update your PATH environment variable. If you installed Django from a packaged version for your Linux distribution, django-admin.py might be called django-admin instead. If you see a “permission denied” message when running django-admin.py startproject, you’ll need to change the file’s permissions. To do this, navigate to the directory where django-admin.py is installed (e.g., cd /usr/local/bin) and run the command chmod +x django-admin.py. The startproject command creates a directory containing five files: mysite/ manage.py mysite/ __init__.py settings.py urls.py wsgi.py 18 Chapter 4. Chapter 2: Getting Started The Django Book, Release 2.0 Note: Doesn’t match what you see? The default project layout recently changed. If you’re seeing a “flat” layout (with no inner mysite/ directory), you’re probably using a version of Django that doesn’t match this tutorial version. This book covers Django 1.4 and above, so if you’re using an older version you probably want to consult Django’s official documentation. The documentation for Django 1.X version is available at https://docs.djangoproject.com/en/1.X/. These files are as follows: • mysite/: The outer mysite/ directory is just a container for your project. Its name doesn’t matter to Django; you can rename it to anything you like. • manage.py: A command-line utility that lets you interact with this Django project in various ways. Type python manage.py help to get a feel for what it can do. You should never have to edit this file; it’s created in this directory purely for convenience. • mysite/mysite/: The inner mysite/ directory is the actual Python package for your project. Its name is the Python package name you’ll need to use to import anything inside it (e.g. import mysite.settings). • __init__.py: A file required for Python to treat the mysite directory as a package (i.e., a group of Python modules). It’s an empty file, and generally you won’t add anything to it. • settings.py: Settings/configuration for this Django project. Take a look at it to get an idea of the types of settings available, along with their default values. • urls.py: The URLs for this Django project. Think of this as the “table of contents” of your Django-powered site. • wsgi.py: An entry-point for WSGI-compatible webservers to serve your project. See How to deploy with WSGI (https://docs.djangoproject.com/en/1.4/howto/deployment/wsgi/) for more details. Despite their small size, these files already constitute a working Django application. 4.5.1 Running the Development Server For some more post-installation positive feedback, let’s run the Django development server to see our barebones application in action. The Django development server (also called the “runserver” after the command that launches it) is a built-in, lightweight Web server you can use while developing your site. It’s included with Django so you can develop your site rapidly, without having to deal with configuring your production server (e.g., Apache) until you’re ready for production. The development server watches your code and automatically reloads it, making it easy for you to change your code without needing to restart anything. To start the server, change into your project container directory (cd mysite), if you haven’t already, and run this command: python manage.py runserver You’ll see something like this: Validating models... 0 errors found. Django version 1.4.2, using settings ’mysite.settings’ Development server is running at http://127.0.0.1:8000/ Quit the server with CONTROL-C. 4.5. Starting a Project 19 The Django Book, Release 2.0 This launches the server locally, on port 8000, accessible only to connections from your own computer. Now that it’s running, visit http://127.0.0.1:8000/ with your Web browser. You might see a different Django version depending on which version of Django you have installed. You’ll see a “Welcome to Django” page shaded in a pleasant pastel blue. It worked! One final, important note about the development server is worth mentioning before proceeding. Although this server is convenient for development, resist the temptation to use it in anything resembling a production environment. The development server can handle only a single request at a time reliably, and it has not gone through a security audit of any sort. When the time comes to launch your site, see Chapter 12 for information on how to deploy Django. Changing the Development Server’s Host or Port By default, the runserver command starts the development server on port 8000, listening only for local connections. If you want to change the server’s port, pass it as a command-line argument: python manage.py runserver 8080 By specifying an IP address, you can tell the server to allow non-local connections. This is especially helpful if you’d like to share a development site with other members of your team. The IP address 0.0.0.0 tells the server to listen on any network interface: python manage.py runserver 0.0.0.0:8000 When you’ve done this, other computers on your local network will be able to view your Django site by visiting your IP address in their Web browsers, e.g., http://192.168.1.103:8000/ . (Note that you’ll have to consult your network settings to determine your IP address on the local network. Unix users, try running “ifconfig” in a command prompt to get this information. Windows users, try “ipconfig”.) 4.6 What’s Next? Now that you have everything installed and the development server running, you’re ready to :doc: learn the basics Chapter 3, of serving Web pages with Django. 20 Chapter 4. Chapter 2: Getting Started CHAPTER 5 Chapter 3: Views and URLconfs In the previous chapter, we explained how to set up a Django project and run the Django development server. In this chapter, you’ll learn the basics of creating dynamic Web pages with Django. 5.1 Your First Django-Powered Page: Hello World As our first goal, let’s create a Web page that outputs that famous example message: “Hello world.” If you were publishing a simple “Hello world” Web page without a Web framework, you’d simply type “Hello world” into a text file, call it hello.html, and upload it to a directory on a Web server somewhere. Notice, in that process, you’ve specified two key pieces of information about that Web page: its contents (the string "Hello world") and its URL ( http://www.example.com/hello.html, or maybe http://www.example.com/files/hello.html if you put it in a subdirectory). With Django, you specify those same two things, but in a different way. The contents of the page are produced by a view function, and the URL is specified in a URLconf. First, let’s write our “Hello world” view function. 5.1.1 Your First View Within the mysite directory that django-admin.py startproject made in the last chapter, create an empty file called views.py. This Python module will contain our views for this chapter. Note that there’s nothing special about the name views.py – Django doesn’t care what the file is called, as you’ll see in a bit – but it’s a good idea to call it views.py as a convention, for the benefit of other developers reading your code. Our “Hello world” view is simple. Here’s the entire function, plus import statements, which you should type into the views.py file: from django.http import HttpResponse def hello(request): return HttpResponse("Hello world") Let’s step through this code one line at a time: • First, we import the class HttpResponse, which lives in the django.http module. We need to import this class because it’s used later in our code. • Next, we define a function called hello – the view function. Each view function takes at least one parameter, called request by convention. This is an object that contains information about the current Web request that has triggered this view, and it’s an instance of the class 21 The Django Book, Release 2.0 django.http.HttpRequest. In this example, we don’t do anything with request, but it must be the first parameter of the view nonetheless. Note that the name of the view function doesn’t matter; it doesn’t have to be named in a certain way in order for Django to recognize it. We’re calling it hello here, because that name clearly indicates the gist of the view, but it could just as well be named hello_wonderful_beautiful_world, or something equally revolting. The next section, “Your First URLconf”, will shed light on how Django finds this function. • The function is a simple one-liner: it merely returns an HttpResponse object that has been instantiated with the text "Hello world". The main lesson here is this: a view is just a Python function that takes an HttpRequest as its first parameter and returns an instance of HttpResponse. In order for a Python function to be a Django view, it must do these two things. (There are exceptions, but we’ll get to those later.) 5.1.2 Your First URLconf If, at this point, you ran python manage.py runserver again, you’d still see the “Welcome to Django” message, with no trace of our “Hello world” view anywhere. That’s because our mysite project doesn’t yet know about the hello view; we need to tell Django explicitly that we’re activating this view at a particular URL. (Continuing our previous analogy of publishing static HTML files, at this point we’ve created the HTML file but haven’t uploaded it to a directory on the server yet.) To hook a view function to a particular URL with Django, use a URLconf. A URLconf is like a table of contents for your Django-powered Web site. Basically, it’s a mapping between URLs and the view functions that should be called for those URLs. It’s how you tell Django, “For this URL, call this code, and for that URL, call that code.” For example, “When somebody visits the URL /foo/, call the view function foo_view(), which lives in the Python module views.py.” When you executed django-admin.py startproject in the previous chapter, the script created a URLconf for you automatically: the file urls.py. By default, it looks something like this: from django.conf.urls import patterns, include, url # Uncomment the next two lines to enable the admin: # from django.contrib import admin # admin.autodiscover() urlpatterns = patterns(’’, # Examples: # url(r’^$’, ’mysite.views.home’, name=’home’), # url(r’^mysite/’, include(’mysite.foo.urls’)), # Uncomment the admin/doc line below to enable admin documentation: # url(r’^admin/doc/’, include(’django.contrib.admindocs.urls’)), # Uncomment the next line to enable the admin: # url(r’^admin/’, include(admin.site.urls)), ) This default URLconf includes some commonly used Django features commented out, so that activating those features is as easy as uncommenting the appropriate lines. If we ignore the commented-out code, here’s the essence of a URLconf: from django.conf.urls.defaults import patterns, include, url urlpatterns = patterns(’’, ) 22 Chapter 5. Chapter 3: Views and URLconfs The Django Book, Release 2.0 Let’s step through this code one line at a time: • The first line imports three functions from the django.conf.urls.defaults module, which is Django’s URLconf infrastructure: patterns, include, and urls. • The second line calls the function patterns and saves the result into a variable called urlpatterns. The patterns function gets passed only a single argument – the empty string. (The string can be used to supply a common prefix for view functions, which we’ll cover in Chapter 8: Advanced Views and URLconfs.) The main thing to note here is the variable urlpatterns, which Django expects to find in your URLconf module. This variable defines the mapping between URLs and the code that handles those URLs. By default, as we can see, the URLconf is empty – your Django application is a blank slate. (As a side note, that’s how Django knew to show you the “Welcome to Django” page in the last chapter. If your URLconf is empty, Django assumes you just started a new project and, hence, displays that message.) To add a URL and view to the URLconf, just add a mapping between a URL pattern and the view function. Here’s how to hook in our hello view: from django.conf.urls.defaults import patterns, include, url from mysite.views import hello urlpatterns = patterns(’’, url(r’^hello/$’, hello), ) (Note that we’ve removed the commented-out code for brevity. You can choose to leave those lines in, if you’d like.) We made two changes here: • First, we imported the hello view from its module – mysite/views.py, which translates into mysite.views in Python import syntax. (This assumes mysite/views.py is on your Python path; see the sidebar for details.) • Next, we added the line url(r’^hello/$’, hello), to urlpatterns. This line is referred to as a URLpattern. The url() function tells Django how to handle the url that you are configuring. The first argument is a pattern-matching string (a regular expression; more on this in a bit) and the second argument is the view function to use for that pattern. url() can take other optional arguments as well, which we’ll cover in more depth in Chapter 8: Advanced Views and URLconfs. Note: One more important detail we’ve introduced here is that r character in front of the regular expression string. This tells Python that the string is a “raw string” – its contents should not interpret backslashes. In normal Python strings, backslashes are used for escaping special characters – such as in the string ’\n’, which is a one-character string containing a newline. When you add the r to make it a raw string, Python does not apply its backslash escaping – so, r’\n’ is a two-character string containing a literal backslash and a lowercase “n”. There’s a natural collision between Python’s usage of backslashes and the backslashes that are found in regular expressions, so it’s strongly suggested that you use raw strings any time you’re defining a regular expression in Python. All of the URLpatterns in this book will be raw strings. In a nutshell, we just told Django that any request to the URL /hello/ should be handled by the hello view function. Your Python Path Your Python path is the list of directories on your system where Python looks when you use the Python import statement. For example, let’s say your Python path is set to [’’, ’/usr/lib/python2.7/site-packages’, ’/home/username/djcode’]. If you execute the Python statement from foo import bar, Python will look for a module called foo.py in the current directory. (The first entry in the Python 5.1. Your First Django-Powered Page: Hello World 23 The Django Book, Release 2.0 path, an empty string, means “the current directory.”) If that file doesn’t exist, Python will look for the file /usr/lib/python2.7/site-packages/foo.py. If that file doesn’t exist, it will try /home/username/djcode/foo.py. Finally, if that file doesn’t exist, it will raise ImportError. If you’re interested in seeing the value of your Python path, start the Python interactive interpreter and type this: >>> import sys >>> print sys.path Generally you don’t have to worry about setting your Python path – Python and Django take care of things for you automatically behind the scenes. (Setting the Python path is one of the things that the manage.py script does.) It’s worth discussing the syntax of this URLpattern, as it may not be immediately obvious. Although we want to match the URL /hello/, the pattern looks a bit different than that. Here’s why: • Django removes the slash from the front of every incoming URL before it checks the URLpatterns. This means that our URLpattern doesn’t include the leading slash in /hello/. (At first, this may seem unintuitive, but this requirement simplifies things – such as the inclusion of URLconfs within other URLconfs, which we’ll cover in Chapter 8.) • The pattern includes a caret (^) and a dollar sign ($). These are regular expression characters that have a special meaning: 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.” This concept is best explained by example. If we had instead used the pattern ’^hello/’ (without a dollar sign at the end), then any URL starting with /hello/ would match, such as /hello/foo and /hello/bar, not just /hello/. Similarly, if we had left off the initial caret character (i.e., ’hello/$’), Django would match any URL that ends with hello/, such as /foo/bar/hello/. If we had simply used hello/, without a caret or dollar sign, then any URL containing hello/ would match, such as /foo/hello/bar. Thus, we use both the caret and dollar sign to ensure that only the URL /hello/ matches – nothing more, nothing less. Most of your URLpatterns will start with carets and end with dollar signs, but it’s nice to have the flexibility to perform more sophisticated matches. You may be wondering what happens if someone requests the URL /hello (that is, without a trailing slash). Because our URLpattern requires a trailing slash, that URL would not match. However, by default, any request to a URL that doesn’t match a URLpattern and doesn’t end with a slash will be redirected to the same URL with a trailing slash. (This is regulated by the APPEND_SLASH Django setting, which is covered in Appendix D.) If you’re the type of person who likes all URLs to end with slashes (which is the preference of Django’s developers), all you’ll need to do is add a trailing slash to each URLpattern and leave APPEND_SLASH set to True. If you prefer your URLs not to have trailing slashes, or if you want to decide it on a per-URL basis, set APPEND_SLASH to False and put trailing slashes in your URLpatterns as you see fit. The other thing to note about this URLconf is that we’ve passed the hello view function as an object without calling the function. This is a key feature of Python (and other dynamic languages): functions are first-class objects, which means you can pass them around just like any other variables. Cool stuff, eh? To test our changes to the URLconf, start the Django development server, as you did in Chapter 2, by running the command python manage.py runserver. (If you left it running, that’s fine, too. The development server automatically detects changes to your Python code and reloads as necessary, so you don’t have to restart the server between changes.) The server is running at the address http://127.0.0.1:8000/, so open up a Web browser and go to http://127.0.0.1:8000/hello/. You should see the text “Hello world” – the output of your Django view. Hooray! You’ve made your first Django-powered Web page. Regular Expressions 24 Chapter 5. Chapter 3: Views and URLconfs The Django Book, Release 2.0 Regular expressions (or regexes) are a compact way of specifying patterns in text. While Django URLconfs allow arbitrary regexes for powerful URL matching, you’ll probably only use a few regex symbols in practice. Here’s a selection of common symbols: Symbol . (dot) \d [A-Z] [a-z] [A-Za-z] + [^/]+ ? * {1,3} Matches Any single character Any single digit Any character between A and Z (uppercase) Any character between a and z (lowercase) Any character between a and z (case-insensitive) One or more of the previous expression (e.g., \d+ matches one or more digits) One or more characters until (and not including) a forward slash Zero or one of the previous expression (e.g., \d? matches zero or one digits) Zero or more of the previous expression (e.g., \d* matches zero, one or more than one digit) Between one and three (inclusive) of the previous expression (e.g., \d{1,3} matches one, two or three digits) For more on regular expressions, see http://www.djangoproject.com/r/python/re-module/. 5.1.3 A Quick Note About 404 Errors At this point, our URLconf defines only a single URLpattern: the one that handles requests to the URL /hello/. What happens when you request a different URL? To find out, try running the Django development server and visiting a page such as http://127.0.0.1:8000/goodbye/ or http://127.0.0.1:8000/hello/subdirectory/, or even http://127.0.0.1:8000/ (the site “root”). You should see a “Page not found” message (see Figure 3-1). Django displays this message because you requested a URL that’s not defined in your URLconf. The utility of this page goes beyond the basic 404 error message. It also tells you precisely which URLconf Django used and every pattern in that URLconf. From that information, you should be able to tell why the requested URL threw a 404. Naturally, this is sensitive information intended only for you, the Web developer. If this were a production site deployed live on the Internet, you wouldn’t want to expose that information to the public. For that reason, this “Page not found” page is only displayed if your Django project is in debug mode. We’ll explain how to deactivate debug mode later. For now, just know that every Django project is in debug mode when you first create it, and if the project is not in debug mode, Django outputs a different 404 response. 5.1.4 A Quick Note About The Site Root As explained in the last section, you’ll see a 404 error message if you view the site root – http://127.0.0.1:8000/. Django doesn’t add magically anything to the site root; that URL is not specialcased in any way. It’s up to you to assign it to a URLpattern, just like every other entry in your URLconf. The URLpattern to match the site root is a bit unintuitive, though, so it’s worth mentioning. When you’re ready to implement a view for the site root, use the URLpattern ’^$’, which matches an empty string. For example: from mysite.views import hello, my_homepage_view urlpatterns = patterns(’’, url(r’^$’, my_homepage_view), # ... ) 5.1. Your First Django-Powered Page: Hello World 25 The Django Book, Release 2.0 Figure 5.1: Figure 3-1. Django’s 404 page 26 Chapter 5. Chapter 3: Views and URLconfs The Django Book, Release 2.0 5.2 How Django Processes a Request Before continuing to our second view function, let’s pause to learn a little more about how Django works. Specifically, when you view your “Hello world” message by visiting http://127.0.0.1:8000/hello/ in your Web browser, what does Django do behind the scenes? It all starts with the settings file. When you run python manage.py runserver, the script looks for a file called settings.py in the inner mysite directory. This file contains all sorts of configuration for this particular Django project, all in uppercase: TEMPLATE_DIRS, DATABASES, etc. The most important setting is called ROOT_URLCONF. ROOT_URLCONF tells Django which Python module should be used as the URLconf for this Web site. Remember when django-admin.py startproject created the files settings.py and urls.py? The autogenerated settings.py contains a ROOT_URLCONF setting that points to the autogenerated urls.py. Open the settings.py file and see for yourself; it should look like this: ROOT_URLCONF = ’mysite.urls’ This corresponds to the file mysite/urls.py. When a request comes in for a particular URL – say, a request for /hello/ – Django loads the URLconf pointed to by the ROOT_URLCONF setting. Then it checks each of the URLpatterns in that URLconf, in order, comparing the requested URL with the patterns one at a time, until it finds one that matches. When it finds one that matches, it calls the view function associated with that pattern, passing it an HttpRequest object as the first parameter. (We’ll cover the specifics of HttpRequest later.) As we saw in our first view example, a view function must return an HttpResponse. Once it does this, Django does the rest, converting the Python object to a proper Web response with the appropriate HTTP headers and body (i.e., the content of the Web page). In summary: 1. A request comes in to /hello/. 2. Django determines the root URLconf by looking at the ROOT_URLCONF setting. 3. Django looks at all of the URLpatterns in the URLconf for the first one that matches /hello/. 4. If it finds a match, it calls the associated view function. 5. The view function returns an HttpResponse. 6. Django converts the HttpResponse to the proper HTTP response, which results in a Web page. You now know the basics of how to make Django-powered pages. It’s quite simple, really – just write view functions and map them to URLs via URLconfs. 5.3 Your Second View: Dynamic Content Our “Hello world” view was instructive in demonstrating the basics of how Django works, but it wasn’t an example of a dynamic Web page, because the content of the page are always the same. Every time you view /hello/, you’ll see the same thing; it might as well be a static HTML file. For our second view, let’s create something more dynamic – a Web page that displays the current date and time. This is a nice, simple next step, because it doesn’t involve a database or any user input – just the output of your server’s internal clock. It’s only marginally more exciting than “Hello world,” but it’ll demonstrate a few new concepts. 5.2. How Django Processes a Request 27 The Django Book, Release 2.0 This view needs to do two things: calculate the current date and time, and return an HttpResponse containing that value. If you have experience with Python, you know that Python includes a datetime module for calculating dates. Here’s how to use it: >>> import datetime >>> now = datetime.datetime.now() >>> now datetime.datetime(2008, 12, 13, 14, 9, 39, 2731) >>> print now 2008-12-13 14:09:39.002731 That’s simple enough, and it has nothing to do with Django. It’s just Python code. (We want to emphasize that you should be aware of what code is “just Python” vs. code that is Django-specific. As you learn Django, we want you to be able to apply your knowledge to other Python projects that don’t necessarily use Django.) To make a Django view that displays the current date and time, then, we just need to hook this datetime.datetime.now() statement into a view and return an HttpResponse. Here’s how that looks: from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() html = "It is now %s." % now return HttpResponse(html) As with our hello view function, this should live in views.py. Note that we’ve hidden the hello function from this example for brevity, but for the sake of completeness, here’s what the entire views.py looks like: from django.http import HttpResponse import datetime def hello(request): return HttpResponse("Hello world") def current_datetime(request): now = datetime.datetime.now() html = "It is now %s." % now return HttpResponse(html) (From now on, we won’t display previous code in code examples, except when necessary. You should be able to tell from context which parts of an example are new vs. old.) Let’s step through the changes we’ve made to views.py to accommodate the current_datetime view. • We’ve added an import datetime to the top of the module, so we can calculate dates. • The new current_datetime function calculates the current date and time, as a datetime.datetime object, and stores that as the local variable now. • The second line of code within the view 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 in the preceding string with the value of the variable now.” The now variable is technically a datetime.datetime object, not a string, but the %s format character converts it to its string representation, which is something like "2008-12-13 14:09:39.002731". This will result in an HTML string such as "It is now 2008-12-13 14:09:39.002731.". (Yes, our HTML is invalid, but we’re trying to keep the example simple and short.) • Finally, the view returns an HttpResponse object that contains the generated response – just as we did in hello. 28 Chapter 5. Chapter 3: Views and URLconfs The Django Book, Release 2.0 After adding that to views.py, add the URLpattern to urls.py to tell Django which URL should handle this view. Something like /time/ would make sense: from django.conf.urls.defaults import patterns, include, url from mysite.views import hello, current_datetime urlpatterns = patterns(’’, url(r’^hello/$’, hello), url(r’^time/$’, current_datetime), ) We’ve made two changes here. First, we imported the current_datetime function at the top. Second, and more importantly, we added a URLpattern mapping the URL /time/ to that new view. Getting the hang of this? With the view written and URLconf updated, fire up the runserver http://127.0.0.1:8000/time/ in your browser. You should see the current date and time. and visit Django’s Time Zone Depending on your computer, the date and time may be a few hours off. That’s because Django is time zone-aware and defaults to the America/Chicago time zone. (It has to default to something, and that’s the time zone where the original developers live.) If you live elsewhere, you’ll want to change it in settings.py. See the comment in that file for a link to an up-to-date list of worldwide time zone options. 5.4 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. This lets you switch out one piece without affecting the other. For example, consider our current_datetime view. If we wanted to change the URL for the application – say, to move it from /time/ to /current-time/ – we could make a quick change to the URLconf, without having to worry about the view itself. 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. In this example, our current_datetime is available at two URLs. It’s a contrived example, but this technique can come in handy: urlpatterns = patterns(’’, url(r’^hello/$’, hello), url(r’^time/$’, current_datetime), url(r’^another-time-page/$’, current_datetime), ) URLconfs and views are loose coupling in action. We’ll continue to point out examples of this important philosophy throughout this book. 5.4. URLconfs and Loose Coupling 29 The Django Book, Release 2.0 5.5 Your Third View: Dynamic URLs In our current_datetime view, 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. For example, an online bookstore might give each book its own URL, like /books/243/ and /books/81196/. Let’s create a third 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, the page /time/plus/3/ displays the date/time three hours into the future, and so on. A novice might think to code a separate view function for each hour offset, which might result in a URLconf like this: urlpatterns = patterns(’’, url(r’^time/$’, current_datetime), url(r’^time/plus/1/$’, one_hour_ahead), url(r’^time/plus/2/$’, two_hours_ahead), url(r’^time/plus/3/$’, three_hours_ahead), url(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 predefined hour ranges – one, two, three or four hours. If we decided to create a page that displayed the time five hours into the future, we’d have to create a separate view and URLconf line for that, furthering the duplication. We need to do some abstraction here. 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 in Chapter 7), 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 characteristic of a quality Web application. Django’s URLconf system encourages pretty URLs by making it easier to use pretty URLs than not to. How, then do we design our application to handle arbitrary hour offsets? The key is to use wildcard URLpatterns. 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: urlpatterns = patterns(’’, # ... url(r’^time/plus/\d+/$’, hours_ahead), # ... ) (We’re using the # ... to imply there might be other URLpatterns that we trimmed from this example.) This new URLpattern will match any URL such as /time/plus/2/, /time/plus/25/, or even /time/plus/100000000000/. Come to think of it, let’s limit it so that the maximum allowed offset is 99 hours. That means we want to allow either one- or two-digit numbers – and in regular expression syntax, that translates into \d{1,2}: 30 Chapter 5. Chapter 3: Views and URLconfs The Django Book, Release 2.0 url(r’^time/plus/\d{1,2}/$’, hours_ahead), Note: When building Web applications, it’s always important to consider the most outlandish data input possible, and decide whether or not the application should support that input. We’ve curtailed the outlandishness here by limiting the offset to 99 hours. Now that we’ve designated a wildcard for the URL, we need a way of passing that wildcard 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}, like this: url(r’^time/plus/(\d{1,2})/$’, hours_ahead), If you’re familiar with regular expressions, you’ll be right at home here; we’re using parentheses to capture data from the matched text. The final URLconf, including our previous two views, looks like this: from django.conf.urls.defaults import * from mysite.views import hello, current_datetime, hours_ahead urlpatterns = patterns(’’, url(r’^hello/$’, hello), url(r’^time/$’, current_datetime), url(r’^time/plus/(\d{1,2})/$’, hours_ahead), ) With that taken care of, let’s write the hours_ahead view. 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. Here’s the view code: from django.http import Http404, HttpResponse import datetime def hours_ahead(request, offset): try: offset = int(offset) except ValueError: raise Http404() dt = datetime.datetime.now() + datetime.timedelta(hours=offset) html = "In %s hour(s), it will be %s." % (offset, dt) return HttpResponse(html) Let’s step through this code one line at a time: • The view function, hours_ahead, takes two parameters: request and offset. – request is an HttpRequest object, just as in hello and current_datetime. We’ll say it again: each view always takes an HttpRequest object as its first parameter. – offset is the string captured by the parentheses in the URLpattern. For example, if the requested URL were /time/plus/3/, then offset would be the string ’3’. If the requested URL were /time/plus/21/, then offset would be the string ’21’. Note that captured values will always be strings, not integers, even if the string is composed of only digits, such as ’21’. (Technically, captured values will always be Unicode objects, not plain Python bytestrings, but don’t worry about this distinction at the moment.) 5.5. Your Third View: Dynamic URLs 31 The Django Book, Release 2.0 We decided to call the variable offset, but you can call it whatever you’d like, as long as it’s a valid Python identifier. The variable name doesn’t matter; all that matters is that it’s the second argument to the function, after request. (It’s also possible to use keyword, rather than positional, arguments in an URLconf. We cover that in Chapter 8.) • The first thing we do within the function is call int() on offset. This converts the string value to an integer. Note that Python will raise a ValueError exception if you call int() on a value that cannot be converted to an integer, such as the string ’foo’. In this example, if we encounter the ValueError, we raise the exception django.http.Http404, which, as you can imagine, results in a 404 “Page not found” error. Astute readers will wonder: how could we ever reach the ValueError case, anyway, given that the regular expression in our URLpattern – (\d{1,2}) – captures only digits, and therefore offset will only ever be a string composed of digits? The answer is, we won’t, because the URLpattern provides a modest but useful level of input validation, but we still check for the ValueError in case this view function ever gets called in some other way. It’s good practice to implement view functions such that they don’t make any assumptions about their parameters. Loose coupling, remember? • In the next line of the function, we calculate the current date/time and add the appropriate number of hours. We’ve already seen datetime.datetime.now() from the current_datetime view; the new concept here is that you can perform date/time arithmetic by creating a datetime.timedelta object and adding to a datetime.datetime object. Our result is stored in the variable dt. This line also shows why we called int() on offset – the datetime.timedelta function requires the hours parameter to be an integer. • Next, we construct the HTML output of this view function, just as we did in current_datetime. A small difference in this line from the previous line is that it uses Python’s format-string capability with two values, not just one. Hence, there are two %s symbols in the string and a tuple of values to insert: (offset, dt). • Finally, we return an HttpResponse of the HTML. By now, this is old hat. With that view function and URLconf written, start the Django development server (if it’s not already running), and visit http://127.0.0.1:8000/time/plus/3/ to verify it works. Then try http://127.0.0.1:8000/time/plus/5/. Then http://127.0.0.1:8000/time/plus/24/. Finally, visit http://127.0.0.1:8000/time/plus/100/ to verify that the pattern in your URLconf only accepts one- or two-digit numbers; Django should display a “Page not found” error in this case, just as we saw in the section “A Quick Note About 404 Errors” earlier. The URL http://127.0.0.1:8000/time/plus/ (with no hour designation) should also throw a 404. Coding Order In this example, we wrote the URLpattern first and the view second, but in the previous examples, we wrote the view first, then the URLpattern. Which technique is better? Well, every developer is different. If you’re a big-picture type of person, it may make the most sense to you to write all of the URLpatterns for your application at the same time, at the start of your project, and then code up the views. This has the advantage of giving you a clear to-do list, and it essentially defines the parameter requirements for the view functions you’ll need to write. If you’re more of a bottom-up developer, you might prefer to write the views first, and then anchor them to URLs afterward. That’s OK, too. In the end, it comes down to which technique fits your brain the best. Both approaches are valid. 32 Chapter 5. Chapter 3: Views and URLconfs The Django Book, Release 2.0 5.6 Django’s Pretty Error Pages Take a moment to admire the fine Web application we’ve made so far . . . now let’s break it! Let’s deliberately introduce a Python error into our views.py file by commenting out the offset = int(offset) lines in the hours_ahead view: def hours_ahead(request, offset): # try: # offset = int(offset) # except ValueError: # raise Http404() dt = datetime.datetime.now() + datetime.timedelta(hours=offset) html = "In %s hour(s), it will be %s." % (offset, dt) return HttpResponse(html) Load up the development server and navigate to /time/plus/3/. You’ll see an error page with a significant amount of information, including a TypeError message displayed at the very top: "unsupported type for timedelta hours component: unicode". What happened? Well, the datetime.timedelta function expects the hours parameter to be an integer, and we commented out the bit of code that converted offset to an integer. That caused datetime.timedelta to raise the TypeError. It’s the typical kind of small bug that every programmer runs into at some point. The point of this example was to demonstrate Django’s error pages. Take some time to explore the error page and get to know the various bits of information it gives you. Here are some things to notice: • At the top of the page, you get the key information about the exception: the type of exception, any parameters to the exception (the "unsupported type" message in this case), the file in which the exception was raised, and the offending line number. • Under the key exception information, the page displays the full Python traceback for this exception. This is similar to the standard traceback you get in Python’s command-line interpreter, except it’s more interactive. For each level (“frame”) in the stack, Django displays the name of the file, the function/method name, the line number, and the source code of that line. Click the line of source code (in dark gray), and you’ll see several lines from before and after the erroneous line, to give you context. Click “Local vars” under any frame in the stack to view a table of all local variables and their values, in that frame, at the exact point in the code at which the exception was raised. This debugging information can be a great help. • Note the “Switch to copy-and-paste view” text under the “Traceback” header. Click those words, and the traceback will switch to a alternate version that can be easily copied and pasted. Use this when you want to share your exception traceback with others to get technical support – such as the kind folks in the Django IRC chat room or on the Django users mailing list. Underneath, the “Share this traceback on a public Web site” button will do this work for you in just one click. Click it to post the traceback to http://www.dpaste.com/, where you’ll get a distinct URL that you can share with other people. • Next, the “Request information” section includes a wealth of information about the incoming Web request that spawned the error: GET and POST information, cookie values, and meta information, such as CGI headers. Appendix G has a complete reference of all the information a request object contains. Below the “Request information” section, the “Settings” section lists all of the settings for this particular Django installation. (We’ve already mentioned ROOT_URLCONF, and we’ll show you various Django settings throughout the book. All the available settings are covered in detail in Appendix D.) 5.6. Django’s Pretty Error Pages 33 The Django Book, Release 2.0 The Django error page is capable of displaying more information in certain special cases, such as the case of template syntax errors. We’ll get to those later, when we discuss the Django template system. For now, uncomment the offset = int(offset) lines to get the view function working properly again. 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. Here’s an example, using the hours_ahead view: def hours_ahead(request, offset): try: offset = int(offset) except ValueError: raise Http404() dt = datetime.datetime.now() + datetime.timedelta(hours=offset) assert False html = "In %s hour(s), it will be %s." % (offset, dt) return HttpResponse(html) Finally, it’s obvious that much of this information is sensitive – it exposes the innards of your Python code and Django configuration – and it would be foolish to show this information on the public Internet. A malicious person could use it to attempt to reverse-engineer your Web application and do nasty things. For that reason, the Django error page is only displayed when your Django project is in debug mode. We’ll explain how to deactivate debug mode in Chapter 12. For now, just know that every Django project is in debug mode automatically when you start it. (Sound familiar? The “Page not found” errors, described earlier in this chapter, work the same way.) 5.7 What’s next? So far, we’ve been writing our view functions with HTML hard-coded directly in the Python code. We’ve done that to keep things simple while we demonstrated core concepts, but in the real world, this is nearly always a bad idea. Django ships with a simple yet powerful template engine that allows you to separate the design of the page from the underlying code. We’ll dive into Django’s template engine in the next chapter Chapter 4. 34 Chapter 5. Chapter 3: Views and URLconfs CHAPTER 6 Chapter 4: Templates In the previous chapter, you may have noticed something peculiar in how we returned the text in our example views. Namely, the HTML was hard-coded directly in our Python code, like this: def current_datetime(request): now = datetime.datetime.now() html = "It is now %s." % now return HttpResponse(html) Although this technique was convenient for the purpose of explaining how views work, it’s not a good idea to hardcode HTML directly in your views. Here’s why: • Any change to the design of the page requires a change to the Python code. The design of a site tends to change far more frequently than the underlying Python code, so it would be convenient if the design could change without needing to modify the Python code. • Writing Python code and designing HTML are two different disciplines, and most professional Web development environments split these responsibilities between separate people (or even separate departments). Designers and HTML/CSS coders shouldn’t be required to edit Python code to get their job done. • It’s most efficient if programmers can work on Python code and designers can work on templates at the same time, rather than one person waiting for the other to finish editing a single file that contains both Python and HTML. For these reasons, it’s much cleaner and more maintainable to separate the design of the page from the Python code itself. We can do this with Django’s template system, which we discuss in this chapter. 6.1 Template System Basics A Django template 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 (template tags) that regulate how the document should be displayed. Usually, templates are used for producing HTML, but Django templates are equally capable of generating any text-based format. Let’s start with a simple example template. This Django template describes an HTML page that thanks a person for placing an order with a company. Think of it as a form letter: Ordering notice

Ordering notice

35 The Django Book, Release 2.0

Dear {{ person_name }},

Thanks for placing an order from {{ company }}. It’s scheduled to ship on {{ ship_date|date:"F j, Y" }}.

Here are the items you’ve ordered:

    {% for item in item_list %}
  • {{ item }}
  • {% endfor %}
{% if ordered_warranty %}

Your warranty information will be included in the packaging.

{% else %}

You didn’t order a warranty, so you’re on your own when the products inevitably stop working.

{% endif %}

Sincerely,
{{ company }}

This template is basic HTML with some variables and template tags thrown in. Let’s step through it: • Any text surrounded by a pair of braces (e.g., {{ person_name }}) is a variable. This means “insert the value of the variable with the given name.” (How do we specify the values of the variables? We’ll get to that in a moment.) • Any text that’s surrounded by curly braces and percent signs (e.g., {% if ordered_warranty %}) is a template tag. The definition of a tag is quite broad: a tag just tells the template system to “do something.” This example template contains a for tag ({% for item in item_list %}) and an if tag ({% if ordered_warranty %}). A for tag works very much like a for statement in Python, letting you loop over each item in a sequence. An if tag, as you may expect, acts as a logical “if” statement. In this particular case, the tag checks whether the value of the ordered_warranty variable evaluates to True. If it does, the template system will display everything between the {% if ordered_warranty %} and {% else %}. If not, the template system will display everything between {% else %} and {% endif %}. Note that the {% else %} is optional. • Finally, the second paragraph of this template contains an example of a filter, which is the most convenient way to alter the formatting of a variable. In this example, {{ ship_date|date:"F j, Y" }}, we’re passing the ship_date variable to the date filter, giving the date filter the argument "F j, Y". The date filter formats dates in a given format, as specified by that argument. Filters are attached using a pipe character (|), as a reference to Unix pipes. Each Django template has access to several built-in tags and filters, many of which are discussed in the sections that follow. Appendix E contains the full list of tags and filters, and it’s a good idea to familiarize yourself with that list so you know what’s possible. It’s also possible to create your own filters and tags; we’ll cover that in Chapter 9. 6.2 Using the Template System Let’s dive into Django’s template system so you can see how it works – but we’re not yet going to integrate it with the views that we created in the previous chapter. Our goal here is to show you how the system works independently of 36 Chapter 6. Chapter 4: Templates The Django Book, Release 2.0 the rest of Django. (Put another way: usually you’ll be using the template system within a Django view, but we want to make it clear that the template system is just a Python library that you can use anywhere, not just in Django views.) Here is the most basic way you can use Django’s template system in Python code: 1. Create a Template object by providing the raw template code as a string. 2. Call the render() method of the Template object with a given set of variables (the context). This returns a fully rendered template as a string, with all of the variables and template tags evaluated according to the context. In code, here’s what that looks like: >>> from django import template >>> t = template.Template(’My name is {{ name }}.’) >>> c = template.Context({’name’: ’Adrian’}) >>> print t.render(c) My name is Adrian. >>> c = template.Context({’name’: ’Fred’}) >>> print t.render(c) My name is Fred. The following sections describe each step in much more detail. 6.2.1 Creating Template Objects The easiest way to create a Template object is to instantiate it directly. The Template class lives in the django.template module, and the constructor takes one argument, the raw template code. Let’s dip into the Python interactive interpreter to see how this works in code. From the mysite project directory created by django-admin.py startproject (as covered in Chapter 2), type python manage.py shell to start the interactive interpreter. A special Python prompt If you’ve used Python before, you may be wondering why we’re running python manage.py shell instead of just python. Both commands will start the interactive interpreter, but the manage.py shell command has one key difference: before starting the interpreter, it tells Django which settings file to use. Many parts of Django, including the template system, rely on your settings, and you won’t be able to use them unless the framework knows which settings to use. If you’re curious, here’s how it works behind the scenes. Django looks for an environment variable called DJANGO_SETTINGS_MODULE, which should be set to the import path of your settings.py. For example, DJANGO_SETTINGS_MODULE might be set to ’mysite.settings’, assuming mysite is on your Python path. When you run python manage.py shell, the command takes care of setting DJANGO_SETTINGS_MODULE for you. We’re encouraging you to use python manage.py shell in these examples so as to minimize the amount of tweaking and configuring you have to do. Let’s go through some template system basics: >>> from django.template import Template >>> t = Template(’My name is {{ name }}.’) >>> print t If you’re following along interactively, you’ll see something like this: 6.2. Using the Template System 37 The Django Book, Release 2.0 That 0xb7d5f24c will be different every time, and it isn’t relevant; it’s a Python thing (the Python “identity” of the Template object, if you must know). When you create a Template object, the template system compiles the raw template code into an internal, optimized form, ready for rendering. But if your template code includes any syntax errors, the call to Template() will cause a TemplateSyntaxError exception: >>> from django.template import Template >>> t = Template(’{% notatag %}’) Traceback (most recent call last): File "", line 1, in ? ... django.template.TemplateSyntaxError: Invalid block tag: ’notatag’ The term “block tag” here refers to {% notatag %}. “Block tag” and “template tag” are synonymous. The system raises a TemplateSyntaxError exception for any of the following cases: • Invalid tags • Invalid arguments to valid tags • Invalid filters • Invalid arguments to valid filters • Invalid template syntax • Unclosed tags (for tags that require closing tags) 6.2.2 Rendering a Template Once you have a Template object, you can pass it data by giving it a context. A context is simply a set of template variable names and their associated values. A template uses this to populate its variables and evaluate its tags. A context is represented in Django by the Context class, which lives in the django.template module. Its constructor takes one optional argument: a dictionary mapping variable names to variable values. Call the Template object’s render() method with the context to “fill” the template: >>> from django.template import Context, Template >>> t = Template(’My name is {{ name }}.’) >>> c = Context({’name’: ’Stephane’}) >>> t.render(c) u’My name is Stephane.’ One thing we should point out here is that the return value of t.render(c) is a Unicode object – not a normal Python string. You can tell this by the u in front of the string. Django uses Unicode objects instead of normal strings throughout the framework. If you understand the repercussions of that, be thankful for the sophisticated things Django does behind the scenes to make it work. If you don’t understand the repercussions of that, don’t worry for now; just know that Django’s Unicode support makes it relatively painless for your applications to support a wide variety of character sets beyond the basic “A-Z” of the English language. Dictionaries and Contexts A Python dictionary is a mapping between known keys and variable values. A Context is similar to a dictionary, but a Context provides additional functionality, as covered in Chapter 9. Variable names must begin with a letter (A-Z or a-z) and may contain more letters, digits, underscores, and dots. (Dots are a special case we’ll get to in a moment.) Variable names are case sensitive. 38 Chapter 6. Chapter 4: Templates The Django Book, Release 2.0 Here’s an example of template compilation and rendering, using a template similar to the example in the beginning of this chapter: >>> from django.template import Template, Context >>> raw_template = """

Dear {{ person_name }},

... ...

Thanks for placing an order from {{ company }}. It’s scheduled to ... ship on {{ ship_date|date:"F j, Y" }}.

... ... {% if ordered_warranty %} ...

Your warranty information will be included in the packaging.

... {% else %} ...

You didn’t order a warranty, so you’re on your own when ... the products inevitably stop working.

... {% endif %} ... ...

Sincerely,
{{ company }}

""" >>> t = Template(raw_template) >>> import datetime >>> c = Context({’person_name’: ’John Smith’, ... ’company’: ’Outdoor Equipment’, ... ’ship_date’: datetime.date(2009, 4, 2), ... ’ordered_warranty’: False}) >>> t.render(c) u"

Dear John Smith,

\n\n

Thanks for placing an order from Outdoor Equipment. It’s scheduled to\nship on April 2, 2009.

\n\n\n

You didn’t order a warranty, so you’re on your own when\nthe products inevitably stop working.

\n\n\n

Sincerely,
Outdoor Equipment

" Let’s step through this code one statement at a time: • First, we import the classes Template and Context, which both live in the module django.template. • We save the raw text of our template into the variable raw_template. Note that we use triple quote marks to designate the string, because it wraps over multiple lines; in contrast, strings within single quote marks cannot be wrapped over multiple lines. • Next, we create a template object, t, by passing raw_template to the Template class constructor. • We import the datetime module from Python’s standard library, because we’ll need it in the following statement. • Then, we create a Context object, c. The Context constructor takes a Python dictionary, which maps variable names to values. Here, for example, we specify that the person_name is ’John Smith’, company is ’Outdoor Equipment’, and so forth. • Finally, we call the render() method on our template object, passing it the context. This returns the rendered template – i.e., it replaces template variables with the actual values of the variables, and it executes any template tags. Note that the “You didn’t order a warranty” paragraph was displayed because the ordered_warranty variable evaluated to False. Also note the date, April 2, 2009, which is displayed according to the format string ’F j, Y’. (We’ll explain format strings for the date filter in a little while.) If you’re new to Python, you may wonder why this output includes newline characters (’\n’) rather than displaying the line breaks. That’s happening because of a subtlety in the Python interactive interpreter: the call to t.render(c) returns a string, and by default the interactive interpreter displays the representation of the string, rather than the printed value of the string. If you want to see the string with line breaks displayed as true line breaks rather than ’\n’ characters, use the print statement: print t.render(c). 6.2. Using the Template System 39 The Django Book, Release 2.0 Those are the fundamentals of using the Django template system: just write a template string, create a Template object, create a Context, and call the render() method. 6.2.3 Multiple Contexts, Same Template Once you have a Template object, you can render multiple contexts through it. For example: >>> from django.template import Template, Context >>> t = Template(’Hello, {{ name }}’) >>> print t.render(Context({’name’: ’John’})) Hello, John >>> print t.render(Context({’name’: ’Julie’})) Hello, Julie >>> print t.render(Context({’name’: ’Pat’})) Hello, Pat Whenever you’re using the same template source to render multiple contexts like this, it’s more efficient to create the Template object once, and then call render() on it multiple times: # Bad for name in (’John’, ’Julie’, ’Pat’): t = Template(’Hello, {{ name }}’) print t.render(Context({’name’: name})) # Good t = Template(’Hello, {{ name }}’) for name in (’John’, ’Julie’, ’Pat’): print t.render(Context({’name’: name})) Django’s template parsing is quite fast. Behind the scenes, most of the parsing happens via a call to a single regular expression. This is in stark contrast to XML-based template engines, which incur the overhead of an XML parser and tend to be orders of magnitude slower than Django’s template rendering engine. 6.2.4 Context Variable Lookup In the examples so far, we’ve passed simple values in the contexts – mostly strings, plus a datetime.date example. However, the template system elegantly handles more complex data structures, such as lists, dictionaries, and custom objects. The key to traversing complex data structures in Django templates is the dot character (.). Use a dot to access dictionary keys, attributes, methods, or indices of an object. This is best illustrated with a few examples. For instance, suppose you’re passing a Python dictionary to a template. To access the values of that dictionary by dictionary key, use a dot: >>> from django.template import Template, Context >>> person = {’name’: ’Sally’, ’age’: ’43’} >>> t = Template(’{{ person.name }} is {{ person.age }} years old.’) >>> c = Context({’person’: person}) >>> t.render(c) u’Sally is 43 years old.’ Similarly, dots also allow access of object attributes. For example, a Python datetime.date object has year, month, and day attributes, and you can use a dot to access those attributes in a Django template: 40 Chapter 6. Chapter 4: Templates The Django Book, Release 2.0 >>> from django.template import Template, Context >>> import datetime >>> d = datetime.date(1993, 5, 2) >>> d.year 1993 >>> d.month 5 >>> d.day 2 >>> t = Template(’The month is {{ date.month }} and the year is {{ date.year }}.’) >>> c = Context({’date’: d}) >>> t.render(c) u’The month is 5 and the year is 1993.’ This example uses a custom class, demonstrating that variable dots also allow attribute access on arbitrary objects: >>> from django.template import Template, Context >>> class Person(object): ... def __init__(self, first_name, last_name): ... self.first_name, self.last_name = first_name, last_name >>> t = Template(’Hello, {{ person.first_name }} {{ person.last_name }}.’) >>> c = Context({’person’: Person(’John’, ’Smith’)}) >>> t.render(c) u’Hello, John Smith.’ Dots can also refer to methods on objects. For example, each Python string has the methods upper() and isdigit(), and you can call those in Django templates using the same dot syntax: >>> from django.template import Template, Context >>> t = Template(’{{ var }} -- {{ var.upper }} -- {{ var.isdigit }}’) >>> t.render(Context({’var’: ’hello’})) u’hello -- HELLO -- False’ >>> t.render(Context({’var’: ’123’})) u’123 -- 123 -- True’ Note that you do not include parentheses in the method calls. Also, it’s not possible to pass arguments to the methods; you can only call methods that have no required arguments. (We explain this philosophy later in this chapter.) Finally, dots are also used to access list indices, for example: >>> from django.template import Template, Context >>> t = Template(’Item 2 is {{ items.2 }}.’) >>> c = Context({’items’: [’apples’, ’bananas’, ’carrots’]}) >>> t.render(c) u’Item 2 is carrots.’ Negative list indices are not allowed. For example, the template variable {{ items.-1 }} would cause a TemplateSyntaxError. Python Lists A reminder: Python lists have 0-based indices. The first item is at index 0, the second is at index 1, and so on. Dot lookups can be summarized like this: when the template system encounters a dot in a variable name, it tries the following lookups, in this order: • Dictionary lookup (e.g., foo["bar"]) • Attribute lookup (e.g., foo.bar) • Method call (e.g., foo.bar()) 6.2. Using the Template System 41 The Django Book, Release 2.0 • List-index lookup (e.g., foo[2]) The system uses the first lookup type that works. It’s short-circuit logic. Dot lookups can be nested multiple levels deep. For instance, the following example uses {{ person.name.upper }}, which translates into a dictionary lookup (person[’name’]) and then a method call (upper()): >>> from django.template import Template, Context >>> person = {’name’: ’Sally’, ’age’: ’43’} >>> t = Template(’{{ person.name.upper }} is {{ person.age }} years old.’) >>> c = Context({’person’: person}) >>> t.render(c) u’SALLY is 43 years old.’ Method Call Behavior Method calls are slightly more complex than the other lookup types. Here are some things to keep in mind: • If, during the method lookup, a method raises an exception, the exception will be propagated, unless the exception has an attribute silent_variable_failure whose value is True. If the exception does have a silent_variable_failure attribute, the variable will render as an empty string, for example: >>> t = Template("My name is {{ person.first_name }}.") >>> class PersonClass3: ... def first_name(self): ... raise AssertionError, "foo" >>> p = PersonClass3() >>> t.render(Context({"person": p})) Traceback (most recent call last): ... AssertionError: foo >>> class SilentAssertionError(AssertionError): ... silent_variable_failure = True >>> class PersonClass4: ... def first_name(self): ... raise SilentAssertionError >>> p = PersonClass4() >>> t.render(Context({"person": p})) u’My name is .’ • A method call will only work if the method has no required arguments. Otherwise, the system will move to the next lookup type (list-index lookup). • Obviously, some methods have side effects, and it would be foolish at best, and possibly even a security hole, to allow the template system to access them. Say, for instance, you have a BankAccount object that has a delete() method. If a template includes something like {{ account.delete }}, where account is a BankAccount object, the object would be deleted when the template is rendered! To prevent this, set the function attribute alters_data on the method: def delete(self): # Delete the account delete.alters_data = True 42 Chapter 6. Chapter 4: Templates The Django Book, Release 2.0 The template system won’t execute any method marked in this way. Continuing the above example, if a template includes {{ account.delete }} and the delete() method has the alters_data=True, then the delete() method will not be executed when the template is rendered. Instead, it will fail silently. How Invalid Variables Are Handled By default, if a variable doesn’t exist, the template system renders it as an empty string, failing silently. For example: >>> from django.template import Template, Context >>> t = Template(’Your name is {{ name }}.’) >>> t.render(Context()) u’Your name is .’ >>> t.render(Context({’var’: ’hello’})) u’Your name is .’ >>> t.render(Context({’NAME’: ’hello’})) u’Your name is .’ >>> t.render(Context({’Name’: ’hello’})) u’Your name is .’ The system fails silently rather than raising an exception because it’s intended to be resilient to human error. In this case, all of the lookups failed because variable names have the wrong case or name. In the real world, it’s unacceptable for a Web site to become inaccessible due to a small template syntax error. 6.2.5 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 django.template import Context >>> c = Context({"foo": "bar"}) >>> c[’foo’] ’bar’ >>> del c[’foo’] >>> c[’foo’] Traceback (most recent call last): ... KeyError: ’foo’ >>> c[’newvariable’] = ’hello’ >>> c[’newvariable’] ’hello’ 6.3 Basic Template Tags and Filters As we’ve mentioned already, the template system ships with built-in tags and filters. The sections that follow provide a rundown of the most common tags and filters. 6.3.1 Tags if/else The {% if %} tag evaluates a variable, and if that variable is “True” (i.e., it exists, is not empty, and is not a false Boolean value), the system will display everything between {% if %} and {% endif %}, for example: 6.3. Basic Template Tags and Filters 43 The Django Book, Release 2.0 {% if today_is_weekend %}

Welcome to the weekend!

{% endif %} An {% else %} tag is optional: {% if today_is_weekend %}

Welcome to the weekend!

{% else %}

Get back to work.

{% endif %} Python “Truthiness” In Python and in the Django template system, these objects evaluate to False in a Boolean context: • An empty list ([]) • An empty tuple (()) • An empty dictionary ({}) • An empty string (’’) • Zero (0) • The special object None • The object False (obviously) • Custom objects that define their own Boolean context behavior (this is advanced Python usage) Everything else evaluates to True. The {% if %} tag accepts and, or, or not for testing multiple variables, or to negate a given variable. For example: {% if athlete_list and coach_list %} Both athletes and coaches are available. {% endif %} {% if not athlete_list %} There are no athletes. {% endif %} {% if athlete_list or coach_list %} There are some athletes or some coaches. {% endif %} {% if not athlete_list or coach_list %} There are no athletes or there are some coaches. {% endif %} {% if athlete_list and not coach_list %} There are some athletes and absolutely no coaches. {% endif %} {% 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: {% if athlete_list and coach_list or cheerleader_list %} 44 Chapter 6. Chapter 4: Templates The Django Book, Release 2.0 The use of parentheses for controlling order of operations is not supported. If you find yourself needing parentheses, consider performing logic outside the template and passing the result of that as a dedicated template variable. Or, just use nested {% if %} tags, like this: {% if athlete_list %} {% if coach_list or cheerleader_list %} We have athletes, and either coaches or cheerleaders! {% endif %} {% endif %} Multiple uses of the same logical operator are fine, but you can’t combine different operators. For example, this is valid: {% if athlete_list or coach_list or parent_list or teacher_list %} There is no {% elif %} tag. Use nested {% if %} tags to accomplish the same thing: {% if athlete_list %}

Here are the athletes: {{ athlete_list }}.

{% else %}

No athletes are available.

{% if coach_list %}

Here are the coaches: {{ coach_list }}.

{% endif %} {% endif %} Make sure to close each {% if %} with an {% endif %}. TemplateSyntaxError. Otherwise, Django will throw a for The {% for %} tag allows you to loop over each item in a sequence. As in Python’s for statement, the syntax is for X in Y, where Y is the sequence to loop over and X is the name of the variable to use for a particular cycle of the loop. Each time through the loop, the template system will render everything between {% for %} and {% endfor %}. For example, you could use the following to display a list of athletes given a variable athlete_list:
    {% for athlete in athlete_list %}
  • {{ athlete.name }}
  • {% endfor %}
Add reversed to the tag to loop over the list in reverse: {% for athlete in athlete_list reversed %} ... {% endfor %} It’s possible to nest {% for %} tags: {% for athlete in athlete_list %}

{{ athlete.name }}

    {% for sport in athlete.sports_played %}
  • {{ sport }}
  • {% endfor %} 6.3. Basic Template Tags and Filters 45 The Django Book, Release 2.0
{% endfor %} A common pattern is to check the size of the list before looping over it, and outputting some special text if the list is empty: {% if athlete_list %} {% for athlete in athlete_list %}

{{ athlete.name }}

{% endfor %} {% else %}

There are no athletes. Only computer programmers.

{% endif %} Because this pattern is so common, the for tag supports an optional {% empty %} clause that lets you define what to output if the list is empty. This example is equivalent to the previous one: {% for athlete in athlete_list %}

{{ athlete.name }}

{% empty %}

There are no athletes. Only computer programmers.

{% endfor %} There is no support for “breaking out” of a loop before the loop is finished. If you want to accomplish this, change the variable you’re looping over so that it includes only the values you want to loop over. Similarly, there is no support for a “continue” statement that would instruct the loop processor to return immediately to the front of the loop. (See the section “Philosophies and Limitations” later in this chapter for the reasoning behind this design decision.) Within each {% for %} loop, you get access to a template variable called forloop. This variable has a few attributes that give you information about the progress of the loop: • forloop.counter is always set to an integer representing the number of times the loop has been entered. This is one-indexed, so the first time through the loop, forloop.counter will be set to 1. Here’s an example: {% for item in todo_list %}

{{ forloop.counter }}: {{ item }}

{% endfor %} • forloop.counter0 is like forloop.counter, except it’s zero-indexed. Its value will be set to 0 the first time through the loop. • forloop.revcounter is always set to an integer representing the number of remaining items in the loop. The first time through the loop, forloop.revcounter will be set to the total number of items in the sequence you’re traversing. The last time through the loop, forloop.revcounter will be set to 1. • forloop.revcounter0 is like forloop.revcounter, except it’s zero-indexed. The first time through the loop, forloop.revcounter0 will be set to the number of elements in the sequence minus 1. The last time through the loop, it will be set to 0. • forloop.first is a Boolean value set to True if this is the first time through the loop. This is convenient for special-casing: {% for object in objects %} {% if forloop.first %}
  • {% else %}
  • {% endif %} {{ object }}
  • {% endfor %} • forloop.last is a Boolean value set to True if this is the last time through the loop. A common use for this is to put pipe characters between a list of links: 46 Chapter 6. Chapter 4: Templates The Django Book, Release 2.0 {% for link in links %}{{ link }}{% if not forloop.last %} | {% endif %}{% endfor %} The above template code might output something like this: Link1 | Link2 | Link3 | Link4 Another common use for this is to put a comma between words in a list: Favorite places: {% for p in places %}{{ p }}{% if not forloop.last %}, {% endif %}{% endfor %} • forloop.parentloop is a reference to the forloop object for the parent loop, in case of nested loops. Here’s an example: {% for country in countries %} {% for city in country.city_list %} {% endfor %}
    Country #{{ forloop.parentloop.counter }} City #{{ forloop.counter }} {{ city }}
    {% endfor %} The magic forloop variable is only available within loops. After the template parser has reached {% endfor %}, forloop disappears. Context and the forloop Variable Inside the {% for %} block, the existing variables are moved out of the way to avoid overwriting the magic forloop variable. Django exposes this moved context in forloop.parentloop. You generally don’t need to worry about this, but if you supply a template variable named forloop (though we advise against it), it will be named forloop.parentloop while inside the {% for %} block. ifequal/ifnotequal The Django template system deliberately is not a full-fledged programming language and thus does not allow you to execute arbitrary Python statements. (More on this idea in the section “Philosophies and Limitations.”) However, it’s quite a common template requirement to compare two values and display something if they’re equal – and Django provides an {% ifequal %} tag for that purpose. The {% ifequal %} tag compares two values and displays everything between {% ifequal %} and {% endifequal %} if the values are equal. This example compares the template variables user and currentuser: {% ifequal user currentuser %}

    Welcome!

    {% endifequal %} The arguments can be hard-coded strings, with either single or double quotes, so the following is valid: {% ifequal section ’sitenews’ %}

    Site News

    {% endifequal %} 6.3. Basic Template Tags and Filters 47 The Django Book, Release 2.0 {% ifequal section "community" %}

    Community

    {% endifequal %} Just like {% if %}, the {% ifequal %} tag supports an optional {% else %}: {% ifequal section ’sitenews’ %}

    Site News

    {% else %}

    No News Here

    {% endifequal %} Only template variables, strings, integers, and decimal numbers are allowed as arguments to {% ifequal %}. These are valid examples: {% {% {% {% ifequal ifequal ifequal ifequal variable variable variable variable 1 %} 1.23 %} ’foo’ %} "foo" %} Any other types of variables, such as Python dictionaries, lists, or Booleans, can’t be hard-coded in {% ifequal %}. These are invalid examples: {% ifequal variable True %} {% ifequal variable [1, 2, 3] %} {% ifequal variable {’key’: ’value’} %} If you need to test whether something is true or false, use the {% if %} tags instead of {% ifequal %}. Comments Just as in HTML or Python, the Django template language allows for comments. To designate a comment, use {# #}: {# This is a comment #} The comment will not be output when the template is rendered. Comments using this syntax cannot span multiple lines. This limitation improves template parsing performance. In the following template, the rendered output will look exactly the same as the template (i.e., the comment tag will not be parsed as a comment): This is a {# this is not a comment #} test. If you want to use multi-line comments, use the {% comment %} template tag, like this: {% comment %} This is a multi-line comment. {% endcomment %} 6.3.2 Filters As explained earlier in this chapter, template filters are simple ways of altering the value of variables before they’re displayed. Filters use a pipe character, like this: 48 Chapter 6. Chapter 4: Templates The Django Book, Release 2.0 {{ name|lower }} This displays the value of the {{ name }} variable after being filtered through the lower filter, which converts text to lowercase. Filters can be chained – that is, they can be used in tandem such that the output of one filter is applied to the next. Here’s an example that takes the first element in a list and converts it to uppercase: {{ my_list|first|upper }} Some filters take arguments. A filter argument comes after a colon and is always in double quotes. For example: {{ bio|truncatewords:"30" }} This displays the first 30 words of the bio variable. The following are a few of the most important filters. Appendix E covers the rest. • addslashes: Adds a backslash before any backslash, single quote, or double quote. This is useful if the produced text is included in a JavaScript string. • date: Formats a date or datetime object according to a format string given in the parameter, for example: {{ pub_date|date:"F j, Y" }} Format strings are defined in Appendix E. • length: Returns the length of the value. For a list, this returns the number of elements. For a string, this returns the number of characters. (Python experts, take note that this works on any Python object that knows how to determine its length – i.e., any object that has a __len__() method.) 6.4 Philosophies and Limitations Now that you’ve gotten a feel for the Django template language, we should point out some of its intentional limitations, along with some philosophies behind why it works the way it works. More than any other component of Web applications, template syntax is highly subjective, and programmers’ opinions vary wildly. The fact that Python alone has dozens, if not hundreds, of open source template-language implementations supports this point. Each was likely created because its developer deemed all existing template languages inadequate. (In fact, it is said to be a rite of passage for a Python developer to write his or her own template language! If you haven’t done this yet, consider it. It’s a fun exercise.) With that in mind, you might be interested to know that Django doesn’t require that you use its template language. Because Django is intended to be a full-stack Web framework that provides all the pieces necessary for Web developers to be productive, many times it’s more convenient to use Django’s template system than other Python template libraries, but it’s not a strict requirement in any sense. As you’ll see in the upcoming section “Using Templates in Views”, it’s very easy to use another template language with Django. Still, it’s clear we have a strong preference for the way Django’s template language works. The template system has roots in how Web development is done at World Online and the combined experience of Django’s creators. Here are a few of those philosophies: • Business logic should be separated from presentation logic. Django’s developers see a template system as a tool that controls presentation and presentation-related logic – and that’s it. The template system shouldn’t support functionality that goes beyond this basic goal. For that reason, it’s impossible to call Python code directly within Django templates. All “programming” is fundamentally limited to the scope of what template tags can do. It is possible to write custom template tags that 6.4. Philosophies and Limitations 49 The Django Book, Release 2.0 do arbitrary things, but the out-of-the-box Django template tags intentionally do not allow for arbitrary Python code execution. • Syntax should be decoupled from HTML/XML. Although Django’s template system is used primarily to produce HTML, it’s intended to be just as usable for non-HTML formats, such as plain text. Some other template languages are XML based, placing all template logic within XML tags or attributes, but Django deliberately avoids this limitation. Requiring valid XML to write templates introduces a world of human mistakes and hardto-understand error messages, and using an XML engine to parse templates incurs an unacceptable level of overhead in template processing. • Designers are assumed to be comfortable with HTML code. The template system isn’t designed so that templates necessarily are displayed nicely in WYSIWYG editors such as Dreamweaver. That is too severe a limitation and wouldn’t allow the syntax to be as friendly as it is. Django expects template authors to be comfortable editing HTML directly. • Designers are assumed not to be Python programmers. The template system authors recognize that Web page templates are most often written by designers, not programmers, and therefore should not assume Python knowledge. However, the system also intends to accommodate small teams in which the templates are created by Python programmers. It offers a way to extend the system’s syntax by writing raw Python code. (More on this in Chapter 9.) • The goal is not to invent a programming language. The goal is to offer just enough programming-esque functionality, such as branching and looping, that is essential for making presentation-related decisions. 6.5 Using Templates in Views You’ve learned the basics of using the template system; now let’s use this knowledge to create a view. Recall the current_datetime view in mysite.views, which we started in the previous chapter. Here’s what it looks like: from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() html = "It is now %s." % now return HttpResponse(html) Let’s change this view to use Django’s template system. At first, you might think to do something like this: from django.template import Template, Context from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() t = Template("It is now {{ current_date }}.") html = t.render(Context({’current_date’: now})) return HttpResponse(html) Sure, that uses the template system, but it doesn’t solve the problems we pointed out in the introduction of this chapter. Namely, the template is still embedded in the Python code, so true separation of data and presentation isn’t achieved. Let’s fix that by putting the template in a separate file, which this view will load. You might first consider saving your template somewhere on your filesystem and using Python’s built-in file-opening functionality to read the contents of the template. Here’s what that might look like, assuming the template was saved 50 Chapter 6. Chapter 4: Templates The Django Book, Release 2.0 as the file /home/djangouser/templates/mytemplate.html: from django.template import Template, Context from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() # Simple way of using templates from the filesystem. # This is BAD because it doesn’t account for missing files! fp = open(’/home/djangouser/templates/mytemplate.html’) t = Template(fp.read()) fp.close() html = t.render(Context({’current_date’: now})) return HttpResponse(html) This approach, however, is inelegant for these reasons: • It doesn’t handle the case of a missing file. If the file mytemplate.html doesn’t exist or isn’t readable, the open() call will raise an IOError exception. • It hard-codes your template location. If you were to use this technique for every view function, you’d be duplicating the template locations. Not to mention it involves a lot of typing! • It includes a lot of boring boilerplate code. You’ve got better things to do than to write calls to open(), fp.read(), and fp.close() each time you load a template. To solve these issues, we’ll use template loading and template directories. 6.6 Template Loading Django provides a convenient and powerful API for loading templates from the filesystem, with the goal of removing redundancy both in your template-loading calls and in your templates themselves. In order to use this template-loading API, first you’ll need to tell the framework where you store your templates. The place to do this is in your settings file – the settings.py file that we mentioned last chapter, when we introduced the ROOT_URLCONF setting. If you’re following along, open your settings.py and find the TEMPLATE_DIRS setting. By default, it’s an empty tuple, likely containing some auto-generated comments: TEMPLATE_DIRS = ( # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". # Always use forward slashes, even on Windows. # Don’t forget to use absolute paths, not relative paths. ) This setting tells Django’s template-loading mechanism where to look for templates. Pick a directory where you’d like to store your templates and add it to TEMPLATE_DIRS, like so: TEMPLATE_DIRS = ( ’/home/django/mysite/templates’, ) There are a few things to note: • You can specify any directory you want, as long as the directory and templates within that directory are readable by the user account under which your Web server runs. If you can’t think of an appropriate place to put 6.6. Template Loading 51 The Django Book, Release 2.0 your templates, we recommend creating a templates directory within your project (i.e., within the mysite directory you created in Chapter 2). • If your TEMPLATE_DIRS contains only one directory, don’t forget the comma at the end of the directory string! Bad: # Missing comma! TEMPLATE_DIRS = ( ’/home/django/mysite/templates’ ) Good: # Comma correctly in place. TEMPLATE_DIRS = ( ’/home/django/mysite/templates’, ) The reason for this is that Python requires commas within single-element tuples to disambiguate the tuple from a parenthetical expression. This is a common newbie gotcha. • If you’re on Windows, include your drive letter and use Unix-style forward slashes rather than backslashes, as follows: TEMPLATE_DIRS = ( ’C:/www/django/templates’, ) • It’s simplest to use absolute paths (i.e., directory paths that start at the root of the filesystem). If you want to be a bit more flexible and decoupled, though, you can take advantage of the fact that Django settings files are just Python code by constructing the contents of TEMPLATE_DIRS dynamically. For example: import os.path TEMPLATE_DIRS = ( os.path.join(os.path.dirname(__file__), ’templates’).replace(’\\’,’/’), ) This example uses the “magic” Python variable __file__, which is automatically set to the file name of the Python module in which the code lives. It gets the name of the directory that contains settings.py (os.path.dirname), then joins that with templates in a cross-platform way (os.path.join), then ensures that everything uses forward slashes instead of backslashes (in case of Windows). While we’re on the topic of dynamic Python code in settings files, we should point out that it’s very important to avoid Python errors in your settings file. If you introduce a syntax error, or a runtime error, your Django-powered site will likely crash. With TEMPLATE_DIRS set, the next step is to change the view code to use Django’s template-loading functionality rather than hard-coding the template paths. Returning to our current_datetime view, let’s change it like so: from django.template.loader import get_template from django.template import Context from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() t = get_template(’current_datetime.html’) html = t.render(Context({’current_date’: now})) return HttpResponse(html) 52 Chapter 6. Chapter 4: Templates The Django Book, Release 2.0 In this example, we’re using the function django.template.loader.get_template() rather than loading the template from the filesystem manually. The get_template() function takes a template name as its argument, figures out where the template lives on the filesystem, opens that file, and returns a compiled Template object. Our template in this example is current_datetime.html, but there’s nothing special about that .html extension. You can give your templates whatever extension makes sense for your application, or you can leave off extensions entirely. To determine the location of the template on your filesystem, get_template() combines your template directories from TEMPLATE_DIRS with the template name that you pass to get_template(). For example, if your TEMPLATE_DIRS is set to ’/home/django/mysite/templates’, the above get_template() call would look for the template /home/django/mysite/templates/current_datetime.html. If get_template() cannot find the template with the given name, it raises a TemplateDoesNotExist exception. To see what that looks like, fire up the Django development server again by running python manage.py runserver within your Django project’s directory. Then, point your browser at the page that activates the current_datetime view (e.g., http://127.0.0.1:8000/time/). Assuming your DEBUG setting is set to True and you haven’t yet created a current_datetime.html template, you should see a Django error page highlighting the TemplateDoesNotExist error. Figure 6.1: Figure 4-1: The error page shown when a template cannot be found. This error page is similar to the one we explained in Chapter 3, with one additional piece of debugging information: a “Template-loader postmortem” section. This section tells you which templates Django tried to load, along with the reason each attempt failed (e.g., “File does not exist”). This information is invaluable when you’re trying to debug template-loading errors. Moving along, create the current_datetime.html file within your template directory using the following template code: It is now {{ current_date }}. Refresh the page in your Web browser, and you should see the fully rendered page. 6.6. Template Loading 53 The Django Book, Release 2.0 6.6.1 render() We’ve shown you how to load a template, fill a Context and return an HttpResponse object with the result of the rendered template. We’ve optimized it to use get_template() instead of hard-coding templates and template paths. But it still requires a fair amount of typing to do those things. Because this is such a common idiom, Django provides a shortcut that lets you load a template, render it and return an HttpResponse – all in one line of code. This shortcut is a function called render(), which lives in the module django.shortcuts. Most of the time, you’ll be using render() rather than loading templates and creating Context and HttpResponse objects manually – unless your employer judges your work by total lines of code written, that is. Here’s the ongoing current_datetime example rewritten to use render(): from django.shortcuts import render import datetime def current_datetime(request): now = datetime.datetime.now() return render(request, ’current_datetime.html’, {’current_date’: now}) What a difference! Let’s step through the code changes: • We no longer have to import get_template, Template, Context, or HttpResponse. Instead, we import django.shortcuts.render. The import datetime remains. • Within the current_datetime function, we still calculate now, but the template loading, context creation, template rendering, and HttpResponse creation are all taken care of by the render() call. Because render() returns an HttpResponse object, we can simply return that value in the view. The first argument to render() is the request, the second is the name of the template to use. The third argument, if given, should be a dictionary to use in creating a Context for that template. If you don’t provide a third argument, render() will use an empty dictionary. 6.6.2 Subdirectories in get_template() It can get unwieldy to store all of your templates in a single directory. You might like to store templates in subdirectories of your template directory, and that’s fine. In fact, we recommend doing so; some more advanced Django features (such as the generic views system, which we cover in Chapter 11) expect this template layout as a default convention. Storing templates in subdirectories of your template directory is easy. In your calls to get_template(), just include the subdirectory name and a slash before the template name, like so: t = get_template(’dateapp/current_datetime.html’) Because render() is a small wrapper around get_template(), you can do the same thing with the second argument to render(), like this: return render(request, ’dateapp/current_datetime.html’, {’current_date’: now}) There’s no limit to the depth of your subdirectory tree. Feel free to use as many subdirectories as you like. Note: Windows users, be sure to use forward slashes rather than backslashes. get_template() assumes a Unixstyle file name designation. 54 Chapter 6. Chapter 4: Templates The Django Book, Release 2.0 6.6.3 The include Template Tag Now that we’ve covered the template-loading mechanism, we can introduce a built-in template tag that takes advantage of it: {% include %}. This tag allows you to include the contents of another template. The argument to the tag should be the name of the template to include, and the template name can be either a variable or a hard-coded (quoted) string, in either single or double quotes. Anytime you have the same code in multiple templates, consider using an {% include %} to remove the duplication. These two examples include the contents of the template nav.html. The examples are equivalent and illustrate that either single or double quotes are allowed: {% include ’nav.html’ %} {% include "nav.html" %} This example includes the contents of the template includes/nav.html: {% include ’includes/nav.html’ %} This example includes the contents of the template whose name is contained in the variable template_name: {% include template_name %} As in get_template(), the file name of the template is determined by adding the template directory from TEMPLATE_DIRS to the requested template name. Included templates are evaluated with the context of the template that’s including them. For example, consider these two templates: # mypage.html {% include "includes/nav.html" %}

    {{ title }}

    # includes/nav.html If you render mypage.html with a context containing current_section, then the variable will be available in the “included” template, as you would expect. If, in an {% include %} tag, a template with the given name isn’t found, Django will do one of two things: • If DEBUG is set to True, you’ll see the TemplateDoesNotExist exception on a Django error page. • If DEBUG is set to False, the tag will fail silently, displaying nothing in the place of the tag. 6.7 Template Inheritance Our template examples so far have been tiny HTML snippets, but in the real world, you’ll be using Django’s template system to create entire HTML pages. This leads to a common Web development problem: across a Web site, how does one reduce the duplication and redundancy of common page areas, such as sitewide navigation? 6.7. Template Inheritance 55 The Django Book, Release 2.0 A classic way of solving this problem is to use server-side includes, directives you can embed within your HTML pages to “include” one Web page inside another. Indeed, Django supports that approach, with the {% include %} template tag just described. But the preferred way of solving this problem with Django is to use a more elegant strategy called template inheritance. In essence, template inheritance lets you build a base “skeleton” template that contains all the common parts of your site and defines “blocks” that child templates can override. Let’s see an example of this by creating a more complete template for our current_datetime view, by editing the current_datetime.html file: The current time

    My helpful timestamp site

    It is now {{ current_date }}.


    Thanks for visiting my site.

    That looks just fine, but what happens when we want to create a template for another view – say, the hours_ahead view from Chapter 3? If we want again to make a nice, valid, full HTML template, we’d create something like: Future time

    My helpful timestamp site

    In {{ hour_offset }} hour(s), it will be {{ next_time }}.


    Thanks for visiting my site.

    Clearly, we’ve just duplicated a lot of HTML. Imagine if we had a more typical site, including a navigation bar, a few style sheets, perhaps some JavaScript – we’d end up putting all sorts of redundant HTML into each template. The server-side include solution to this problem is to factor out the common bits in both templates and save them in separate template snippets, which are then included in each template. Perhaps you’d store the top bit of the template in a file called header.html: And perhaps you’d store the bottom bit in a file called footer.html:

    Thanks for visiting my site.

    56 Chapter 6. Chapter 4: Templates The Django Book, Release 2.0 With an include-based strategy, headers and footers are easy. It’s the middle ground that’s messy. In this example, both pages feature a title –

    My helpful timestamp site

    – but that title can’t fit into header.html because the on both pages is different. If we included the <h1> in the header, we’d have to include the <title>, which wouldn’t allow us to customize it per page. See where this is going? Django’s template inheritance system solves these problems. You can think of it as an “inside-out” version of serverside includes. Instead of defining the snippets that are common, you define the snippets that are different. The first step is to define a base template – a skeleton of your page that child templates will later fill in. Here’s a base template for our ongoing example: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="en"> <head> <title>{% block title %}{% endblock %}

    My helpful timestamp site

    {% block content %}{% endblock %} {% block footer %}

    Thanks for visiting my site.

    {% endblock %} This template, which we’ll call base.html, defines a simple HTML skeleton document that we’ll use for all the pages on the site. It’s the job of child templates to override, or add to, or leave alone the contents of the blocks. (If you’re following along, save this file to your template directory as base.html.) We’re using a template tag here that you haven’t seen before: the {% block %} tag. All the {% block %} tags do is tell the template engine that a child template may override those portions of the template. Now that we have this base template, we can modify our existing current_datetime.html template to use it: {% extends "base.html" %} {% block title %}The current time{% endblock %} {% block content %}

    It is now {{ current_date }}.

    {% endblock %} While we’re at it, let’s create a template for the hours_ahead view from Chapter 3. (If you’re following along with code, we’ll leave it up to you to change hours_ahead to use the template system instead of hard-coded HTML.) Here’s what that could look like: {% extends "base.html" %} {% block title %}Future time{% endblock %} {% block content %}

    In {{ hour_offset }} hour(s), it will be {{ next_time }}.

    {% endblock %} Isn’t this beautiful? Each template contains only the code that’s unique to that template. No redundancy needed. If you need to make a site-wide design change, just make the change to base.html, and all of the other templates will immediately reflect the change. Here’s how it works. When you load the template current_datetime.html, the template engine sees the {% 6.7. Template Inheritance 57 The Django Book, Release 2.0 extends %} tag, noting that this template is a child template. The engine immediately loads the parent template – in this case, base.html. At that point, the template engine notices the three {% block %} tags in base.html and replaces those blocks with the contents of the child template. So, the title we’ve defined in {% block title %} will be used, as will the {% block content %}. Note that since the child template doesn’t define the footer block, the template system uses the value from the parent template instead. Content within a {% block %} tag in a parent template is always used as a fallback. Inheritance doesn’t affect the template context. In other words, any template in the inheritance tree will have access to every one of your template variables from the context. You can use as many levels of inheritance as needed. One common way of using inheritance is the following three-level approach: 1. Create a base.html template that holds the main look and feel of your site. This is the stuff that rarely, if ever, changes. 2. Create a base_SECTION.html template for each “section” of your site (e.g., base_photos.html and base_forum.html). These templates extend base.html and include section-specific styles/design. 3. Create individual templates for each type of page, such as a forum page or a photo gallery. These templates extend the appropriate section template. This approach maximizes code reuse and makes it easy to add items to shared areas, such as section-wide navigation. Here are some guidelines for working with template inheritance: • If you use {% extends %} in a template, it must be the first template tag in that template. Otherwise, template inheritance won’t work. • Generally, the more {% block %} tags in your base templates, the better. Remember, child templates don’t have to define all parent blocks, so you can fill in reasonable defaults in a number of blocks, and then define only the ones you need in the child templates. It’s better to have more hooks than fewer hooks. • 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, use {{ block.super }}, which is a “magic” variable providing the rendered text of the parent template. This is useful if you want to add to the contents of a parent block instead of completely overriding it. • You may not define multiple {% block %} tags with the same name in the same template. This limitation exists because a block tag works in “both” directions. That is, a block tag doesn’t just provide a hole to fill, it also defines the content that fills the hole in the parent. If there were two similarly named {% block %} tags in a template, that template’s parent wouldn’t know which one of the blocks’ content to use. • 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. • In most cases, the argument to {% extends %} will be a string, but it can also be a variable, if you don’t know the name of the parent template until runtime. This lets you do some cool, dynamic stuff. 6.8 What’s next? You now have the basics of Django’s template system under your belt. What’s next? Many modern Web sites are database-driven: the content of the Web site is stored in a relational database. This allows a clean separation of data and logic (in the same way views and templates allow the separation of logic and display.) 58 Chapter 6. Chapter 4: Templates The Django Book, Release 2.0 The next chapter Chapter 5 covers the tools Django gives you to interact with a database. 6.8. What’s next? 59 The Django Book, Release 2.0 60 Chapter 6. Chapter 4: Templates CHAPTER 7 Chapter 5: Models In Chapter 3, we covered the fundamentals of building dynamic Web sites with Django: setting up views and URLconfs. As we explained, a view is responsible for doing some arbitrary logic, and then returning a response. In one of the examples, our arbitrary logic was to calculate the current date and time. In modern Web applications, the arbitrary logic often involves interacting with a database. Behind the scenes, a database-driven Web site connects to a database server, retrieves some data out of it, and displays that data on a Web page. The site might also provide ways for site visitors to populate the database on their own. Many complex Web sites provide some combination of the two. Amazon.com, for instance, is a great example of a database-driven site. Each product page is essentially a query into Amazon’s product database formatted as HTML, and when you post a customer review, it gets inserted into the database of reviews. Django is well suited for making database-driven Web sites, because it comes with easy yet powerful tools for performing database queries using Python. This chapter explains that functionality: Django’s database layer. (Note: While it’s not strictly necessary to know basic relational database theory and SQL in order to use Django’s database layer, it’s highly recommended. An introduction to those concepts is beyond the scope of this book, but keep reading even if you’re a database newbie. You’ll probably be able to follow along and grasp concepts based on the context.) 7.1 The “Dumb” Way to Do Database Queries in Views Just as Chapter 3 detailed a “dumb” way to produce output within a view (by hard-coding the text directly within the view), there’s a “dumb” way to retrieve data from a database in a view. It’s simple: just use any existing Python library to execute an SQL query and do something with the results. In this example view, we use the MySQLdb library (available via http://www.djangoproject.com/r/python-mysql/) to connect to a MySQL database, retrieve some records, and feed them to a template for display as a Web page: from django.shortcuts import render import MySQLdb def book_list(request): db = MySQLdb.connect(user=’me’, db=’mydb’, passwd=’secret’, host=’localhost’) cursor = db.cursor() cursor.execute(’SELECT name FROM books ORDER BY name’) names = [row[0] for row in cursor.fetchall()] db.close() return render(request, ’book_list.html’, {’names’: names}) This approach works, but some problems should jump out at you immediately: 61 The Django Book, Release 2.0 • We’re hard-coding the database connection parameters. Ideally, these parameters would be stored in the Django configuration. • We’re having to write a fair bit of boilerplate code: creating a connection, creating a cursor, executing a statement, and closing the connection. Ideally, all we’d have to do is specify which results we wanted. • It ties us to MySQL. If, down the road, we switch from MySQL to PostgreSQL, we’ll have to use a different database adapter (e.g., psycopg rather than MySQLdb), alter the connection parameters, and – depending on the nature of the SQL statement – possibly rewrite the SQL. Ideally, the database server we’re using would be abstracted, so that a database server change could be made in a single place. (This feature is particularly relevant if you’re building an open-source Django application that you want to be used by as many people as possible.) As you might expect, Django’s database layer aims to solve these problems. Here’s a sneak preview of how the previous view can be rewritten using Django’s database API: from django.shortcuts import render from mysite.books.models import Book def book_list(request): books = Book.objects.order_by(’name’) return render(request, ’book_list.html’, {’books’: books}) We’ll explain this code a little later in the chapter. For now, just get a feel for how it looks. 7.2 The MTV (or MVC) Development Pattern Before we delve into any more code, let’s take a moment to consider the overall design of a database-driven Django Web application. As we mentioned in previous chapters, Django is designed to encourage loose coupling and strict separation between pieces of an application. If you follow this philosophy, it’s easy to make changes to one particular piece of the application without affecting the other pieces. In view functions, for instance, we discussed the importance of separating the business logic from the presentation logic by using a template system. With the database layer, we’re applying that same philosophy to data access logic. Those three pieces together – data access logic, business logic, and presentation logic – comprise a concept that’s sometimes called the Model-View-Controller (MVC) pattern of software architecture. In this pattern, “Model” refers to the data access layer, “View” refers to the part of the system that selects what to display and how to display it, and “Controller” refers to the part of the system that decides which view to use, depending on user input, accessing the model as needed. Why the Acronym? The goal of explicitly defining patterns such as MVC is mostly to streamline communication among developers. Instead of having to tell your coworkers, “Let’s make an abstraction of the data access, then let’s have a separate layer that handles data display, and let’s put a layer in the middle that regulates this,” you can take advantage of a shared vocabulary and say, “Let’s use the MVC pattern here.” Django follows this MVC pattern closely enough that it can be called an MVC framework. Here’s roughly how the M, V, and C break down in Django: • M, the data-access portion, is handled by Django’s database layer, which is described in this chapter. • V, the portion that selects which data to display and how to display it, is handled by views and templates. • C, the portion that delegates to a view depending on user input, is handled by the framework itself by following your URLconf and calling the appropriate Python function for the given URL. 62 Chapter 7. Chapter 5: Models The Django Book, Release 2.0 Because the “C” is handled by the framework itself and most of the excitement in Django happens in models, templates and views, Django has been referred to as an MTV framework. In the MTV development pattern, • M stands for “Model,” the data access layer. This layer contains anything and everything about the data: how to access it, how to validate it, which behaviors it has, and the relationships between the data. • T stands for “Template,” the presentation layer. This layer contains presentation-related decisions: how something should be displayed on a Web page or other type of document. • V stands for “View,” the business logic layer. This layer contains the logic that access the model and defers to the appropriate template(s). You can think of it as the bridge between models and templates. If you’re familiar with other MVC Web-development frameworks, such as Ruby on Rails, you may consider Django views to be the “controllers” and Django templates to be the “views.” This is an unfortunate confusion brought about by differing interpretations of MVC. In Django’s interpretation of MVC, the “view” describes the data that gets presented to the user; it’s not necessarily just how the data looks, but which data is presented. In contrast, Ruby on Rails and similar frameworks suggest that the controller’s job includes deciding which data gets presented to the user, whereas the view is strictly how the data looks, not which data is presented. Neither interpretation is more “correct” than the other. The important thing is to understand the underlying concepts. 7.3 Configuring the Database With all of that philosophy in mind, let’s start exploring Django’s database layer. First, we need to take care of some initial configuration; we need to tell Django which database server to use and how to connect to it. We’ll assume you’ve set up a database server, activated it, and created a database within it (e.g., using a CREATE DATABASE statement). If you’re using SQLite, no such setup is required, because SQLite uses standalone files on the filesystem to store its data. As with TEMPLATE_DIRS in the previous chapter, database configuration lives in the Django settings file, called settings.py by default. Edit that file and look for the database settings: DATABASES = { ’default’: { ’ENGINE’: ’django.db.backends.’, ’NAME’: ’’, ’USER’: ’’, ’PASSWORD’: ’’, ’HOST’: ’’, ’PORT’: ’’, } } # # # # # # Add ’postgresql_psycopg2’, ’mysql’, ’sqlite3’ or ’oracle’. Or path to database file if using sqlite3. Not used with sqlite3. Not used with sqlite3. Set to empty string for localhost. Not used with sqlite3. Set to empty string for default. Not used with sqlite3. Here’s a rundown of each setting. • ENGINE tells Django which database engine to use. If you’re using a database with Django, ENGINE must be set to one of the strings shown in Table 5-1. 7.3. Configuring the Database 63 The Django Book, Release 2.0 Table 7.1: Table 5-1. Database Engine Settings Setting Database Required Adapter django.db.backends.postgresql_psycopg2 Postpsycopg version 2.x, greSQL http://www.djangoproject.com/r/python-pgsql/. django.db.backends.mysql MySQL MySQLdb, http://www.djangoproject.com/r/python-mysql/. django.db.backends.sqlite3 SQLite No adapter needed. django.db.backends.oracle Oracle cx_Oracle, http://www.djangoproject.com/r/python-oracle/. Note that for whichever database back-end you use, you’ll need to download and install the appropriate database adapter. Each one is available for free on the Web; just follow the links in the “Required Adapter” column in Table 5-1. If you’re on Linux, your distribution’s package-management system might offer convenient packages. (Look for packages called python-postgresql or python-psycopg, for example.) Example: ’ENGINE’: ’django.db.backends.postgresql_psycopg2’, • NAME tells Django the name of your database. For example: ’NAME’: ’mydb’, If you’re using SQLite, specify the full filesystem path to the database file on your filesystem. For example: ’NAME’: ’/home/django/mydata.db’, As for where you put that SQLite database, we’re using the /home/django directory in this example, but you should pick a directory that works best for you. • USER tells Django which username to use when connecting to your database. For example: If you’re using SQLite, leave this blank. • PASSWORD tells Django which password to use when connecting to your database. If you’re using SQLite or have an empty password, leave this blank. • HOST tells Django which host to use when connecting to your database. If your database is on the same computer as your Django installation (i.e., localhost), leave this blank. If you’re using SQLite, leave this blank. MySQL is a special case here. If this value starts with a forward slash (’/’) and you’re using MySQL, MySQL will connect via a Unix socket to the specified socket, for example: ’HOST’: ’/var/run/mysql’, • PORT tells Django which port to use when connecting to your database. If you’re using SQLite, leave this blank. Otherwise, if you leave this blank, the underlying database adapter will use whichever port is default for your given database server. In most cases, the default port is fine, so you can leave this blank. Once you’ve entered those settings and saved settings.py, it’s a good idea to test your configuration. To do this, run python manage.py shell as in the last chapter, from within the mysite project directory. (As we pointed out last chapter manage.py shell is a way to run the Python interpreter with the correct Django settings activated. This is necessary in our case, because Django needs to know which settings file to use in order to get your database connection information.) In the shell, type these commands to test your database configuration: >>> from django.db import connection >>> cursor = connection.cursor() 64 Chapter 7. Chapter 5: Models The Django Book, Release 2.0 If nothing happens, then your database is configured properly. Otherwise, check the error message for clues about what’s wrong. Table 5-2 shows some common errors. Table 7.2: Table 5-2. Database Configuration Error Messages Error Message You haven’t set the ENGINE setting yet. Environment variable DJANGO_SETTINGS_MODULE is undefined. Error loading _____ module: No module named _____. _____ isn’t an available database backend. database _____ does not exist role _____ does not exist could not connect to server Solution Set the ENGINE setting to something other than an empty string. Valid values are in Table 5-1. Run the command python manage.py shell rather than python. You haven’t installed the appropriate database-specific adapter (e.g., psycopg or MySQLdb). Adapters are not bundled with Django, so it’s your responsibility to download and install them on your own. Set your ENGINE setting to one of the valid engine settings described previously. Perhaps you made a typo? Change the NAME setting to point to a database that exists, or execute the appropriate CREATE DATABASE statement in order to create it. Change the USER setting to point to a user that exists, or create the user in your database. Make sure HOST and PORT are set correctly, and make sure the database server is running. 7.4 Your First App Now that you’ve verified the connection is working, it’s time to create a Django app – a bundle of Django code, including models and views, that lives together in a single Python package and represents a full Django application. It’s worth explaining the terminology here, because this tends to trip up beginners. We’d already created a project, in Chapter 2, so what’s the difference between a project and an app? The difference is that of configuration vs. code: • A project is an instance of a certain set of Django apps, plus the configuration for those apps. Technically, the only requirement of a project is that it supplies a settings file, which defines the database connection information, the list of installed apps, the TEMPLATE_DIRS, and so forth. • An app is a portable set of Django functionality, usually including models and views, that lives together in a single Python package. For example, Django comes with a number of apps, such as a commenting system and an automatic admin interface. A key thing to note about these apps is that they’re portable and reusable across multiple projects. There are very few hard-and-fast rules about how you fit your Django code into this scheme. If you’re building a simple Web site, you may use only a single app. If you’re building a complex Web site with several unrelated pieces such as an e-commerce system and a message board, you’ll probably want to split those into separate apps so that you’ll be able to reuse them individually in the future. Indeed, you don’t necessarily need to create apps at all, as evidenced by the example view functions we’ve created so far in this book. In those cases, we simply created a file called views.py, filled it with view functions, and pointed our URLconf at those functions. No “apps” were needed. However, there’s one requirement regarding the app convention: if you’re using Django’s database layer (models), you must create a Django app. Models must live within apps. Thus, in order to start writing our models, we’ll need to create a new app. Within the mysite project directory, type this command to create a books app: 7.4. Your First App 65 The Django Book, Release 2.0 python manage.py startapp books This command does not produce any output, but it does create a books directory within the mysite directory. Let’s look at the contents of that directory: books/ __init__.py models.py tests.py views.py These files will contain the models and views for this app. Have a look at models.py and views.py in your favorite text editor. Both files are empty, except for comments and an import in models.py. This is the blank slate for your Django app. 7.5 Defining Models in Python As we discussed earlier in this chapter, the “M” in “MTV” stands for “Model.” A Django model is a description of the data in your database, represented as Python code. It’s your data layout – the equivalent of your SQL CREATE TABLE statements – except it’s in Python instead of SQL, and it includes more than just database column definitions. Django uses a model to execute SQL code behind the scenes and return convenient Python data structures representing the rows in your database tables. Django also uses models to represent higher-level concepts that SQL can’t necessarily handle. If you’re familiar with databases, your immediate thought might be, “Isn’t it redundant to define data models in Python instead of in SQL?” Django works the way it does for several reasons: • Introspection requires overhead and is imperfect. In order to provide convenient data-access APIs, Django needs to know the database layout somehow, and there are two ways of accomplishing this. The first way would be to explicitly describe the data in Python, and the second way would be to introspect the database at runtime to determine the data models. This second way seems cleaner, because the metadata about your tables lives in only one place, but it introduces a few problems. First, introspecting a database at runtime obviously requires overhead. If the framework had to introspect the database each time it processed a request, or even only when the Web server was initialized, this would incur an unacceptable level of overhead. (While some believe that level of overhead is acceptable, Django’s developers aim to trim as much framework overhead as possible.) Second, some databases, notably older versions of MySQL, do not store sufficient metadata for accurate and complete introspection. • Writing Python is fun, and keeping everything in Python limits the number of times your brain has to do a “context switch.” It helps productivity if you keep yourself in a single programming environment/mentality for as long as possible. Having to write SQL, then Python, and then SQL again is disruptive. • Having data models stored as code rather than in your database makes it easier to keep your models under version control. This way, you can easily keep track of changes to your data layouts. • SQL allows for only a certain level of metadata about a data layout. Most database systems, for example, do not provide a specialized data type for representing email addresses or URLs. Django models do. The advantage of higher-level data types is higher productivity and more reusable code. • SQL is inconsistent across database platforms. If you’re distributing a Web application, for example, it’s much more pragmatic to distribute a Python module that describes your data layout than separate sets of CREATE TABLE statements for MySQL, PostgreSQL, and SQLite. A drawback of this approach, however, is that it’s possible for the Python code to get out of sync with what’s actually in the database. If you make changes to a Django model, you’ll need to make the same changes inside your database 66 Chapter 7. Chapter 5: Models The Django Book, Release 2.0 to keep your database consistent with the model. We’ll discuss some strategies for handling this problem later in this chapter. Finally, we should note that Django includes a utility that can generate models by introspecting an existing database. This is useful for quickly getting up and running with legacy data. We’ll cover this in Chapter 18. 7.6 Your First Model As an ongoing example in this chapter and the next chapter, we’ll focus on a basic book/author/publisher data layout. We use this as our example because the conceptual relationships between books, authors, and publishers are well known, and this is a common data layout used in introductory SQL textbooks. You’re also reading a book that was written by authors and produced by a publisher! We’ll suppose the following concepts, fields, and relationships: • An author has a first name, a last name and an email address. • A publisher has a name, a street address, a city, a state/province, a country, and a Web site. • A book has a title and a publication date. It also has one or more authors (a many-to-many relationship with authors) and a single publisher (a one-to-many relationship – aka foreign key – to publishers). The first step in using this database layout with Django is to express it as Python code. In the models.py file that was created by the startapp command, enter the following: from django.db import models class Publisher(models.Model): name = models.CharField(max_length=30) address = models.CharField(max_length=50) city = models.CharField(max_length=60) state_province = models.CharField(max_length=30) country = models.CharField(max_length=50) website = models.URLField() class Author(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40) email = models.EmailField() class Book(models.Model): title = models.CharField(max_length=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField() Let’s quickly examine this code to cover the basics. The first thing to notice is that 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 that leaves our models responsible solely for defining their fields, in a nice and compact syntax. Believe it or not, this is all the code we need to write to have basic data access with Django. Each model generally corresponds to a single database table, and each attribute on a model generally corresponds to a column in that database table. The attribute name corresponds to the column’s name, and the type of field (e.g., CharField) corresponds to the database column type (e.g., varchar). For example, the Publisher model is equivalent to the following table (assuming PostgreSQL CREATE TABLE syntax): 7.6. Your First Model 67 The Django Book, Release 2.0 CREATE TABLE "books_publisher" ( "id" serial NOT NULL PRIMARY KEY, "name" varchar(30) NOT NULL, "address" varchar(50) NOT NULL, "city" varchar(60) NOT NULL, "state_province" varchar(30) NOT NULL, "country" varchar(50) NOT NULL, "website" varchar(200) NOT NULL ); Indeed, Django can generate that CREATE TABLE statement automatically, as we’ll show you in a moment. The exception to the one-class-per-database-table rule is the case of many-to-many relationships. In our example models, Book has a ManyToManyField called authors. This designates that a book has one or many authors, but the Book database table doesn’t get an authors column. Rather, Django creates an additional table – a manyto-many “join table” – that handles the mapping of books to authors. For a full list of field types and model syntax options, see Appendix B. Finally, note we haven’t explicitly defined a primary key in any of these models. Unless you instruct it otherwise, Django automatically gives every model an auto-incrementing integer primary key field called id. Each Django model is required to have a single-column primary key. 7.7 Installing the Model We’ve written the code; now let’s create the tables in our database. In order to do that, the first step is to activate these models in our Django project. We do that by adding the books app to the list of “installed apps” in the settings file. Edit the settings.py file again, and look for the INSTALLED_APPS setting. INSTALLED_APPS tells Django which apps are activated for a given project. By default, it looks something like this: INSTALLED_APPS = ( ’django.contrib.auth’, ’django.contrib.contenttypes’, ’django.contrib.sessions’, ’django.contrib.sites’, ’django.contrib.messages’, ’django.contrib.staticfiles’, ) Temporarily comment out all six of those strings by putting a hash character (#) in front of them. (They’re included by default as a common-case convenience, but we’ll activate and discuss them in subsequent chapters.) While you’re at it, comment out the default MIDDLEWARE_CLASSES setting, too; the default values in MIDDLEWARE_CLASSES depend on some of the apps we just commented out. Then, add ’books’ to the INSTALLED_APPS list, so the setting ends up looking like this: MIDDLEWARE_CLASSES = ( # ’django.middleware.common.CommonMiddleware’, # ’django.contrib.sessions.middleware.SessionMiddleware’, # ’django.middleware.csrf.CsrfViewMiddleware’, # ’django.contrib.auth.middleware.AuthenticationMiddleware’, # ’django.contrib.messages.middleware.MessageMiddleware’, ) INSTALLED_APPS = ( # ’django.contrib.auth’, # ’django.contrib.contenttypes’, 68 Chapter 7. Chapter 5: Models The Django Book, Release 2.0 # ’django.contrib.sessions’, # ’django.contrib.sites’, ’books’, ) (As we mentioned last chapter when setting TEMPLATE_DIRS, you’ll need to be sure to include the trailing comma in INSTALLED_APPS, because it’s a single-element tuple. By the way, this book’s authors prefer to put a comma after every element of a tuple, regardless of whether the tuple has only a single element. This avoids the issue of forgetting commas, and there’s no penalty for using that extra comma.) ’mysite.books’ refers to the books app we’re working on. Each app in INSTALLED_APPS is represented by its full Python path – that is, the path of packages, separated by dots, leading to the app package. Now that the Django app has been activated in the settings file, we can create the database tables in our database. First, let’s validate the models by running this command: python manage.py validate The validate command checks whether your models’ syntax and logic are correct. If all is well, you’ll see the message 0 errors found. If you don’t, make sure you typed in the model code correctly. The error output should give you helpful information about what was wrong with the code. Any time you think you have problems with your models, run python manage.py validate. It tends to catch all the common model problems. If your models are valid, run the following command for Django to generate CREATE TABLE statements for your models in the books app (with colorful syntax highlighting available, if you’re using Unix): python manage.py sqlall books In this command, books is the name of the app. It’s what you specified when you ran the command manage.py startapp. When you run the command, you should see something like this: BEGIN; CREATE TABLE "books_publisher" ( "id" serial NOT NULL PRIMARY KEY, "name" varchar(30) NOT NULL, "address" varchar(50) NOT NULL, "city" varchar(60) NOT NULL, "state_province" varchar(30) NOT NULL, "country" varchar(50) NOT NULL, "website" varchar(200) NOT NULL ) ; CREATE TABLE "books_author" ( "id" serial NOT NULL PRIMARY KEY, "first_name" varchar(30) NOT NULL, "last_name" varchar(40) NOT NULL, "email" varchar(75) NOT NULL ) ; CREATE TABLE "books_book" ( "id" serial NOT NULL PRIMARY KEY, "title" varchar(100) NOT NULL, "publisher_id" integer NOT NULL REFERENCES "books_publisher" ("id") DEFERRABLE INITIALLY DEFERRED "publication_date" date NOT NULL ) ; CREATE TABLE "books_book_authors" ( "id" serial NOT NULL PRIMARY KEY, 7.7. Installing the Model 69 The Django Book, Release 2.0 "book_id" integer NOT NULL REFERENCES "books_book" ("id") DEFERRABLE INITIALLY DEFERRED, "author_id" integer NOT NULL REFERENCES "books_author" ("id") DEFERRABLE INITIALLY DEFERRED, UNIQUE ("book_id", "author_id") ) ; CREATE INDEX "books_book_publisher_id" ON "books_book" ("publisher_id"); COMMIT; Note the following: • Table names are automatically generated by combining the name of the app (books) and the lowercase name of the model (publisher, book, and author). You can override this behavior, as detailed in Appendix B. • As we mentioned earlier, Django adds a primary key for each table automatically – the id fields. You can override this, too. • By convention, Django appends "_id" to the foreign key field name. As you might have guessed, you can override this behavior, too. • The foreign key relationship is made explicit by a REFERENCES statement. • These CREATE TABLE statements are tailored to the database you’re using, so database-specific field types such as auto_increment (MySQL), serial (PostgreSQL), or integer primary key (SQLite) are handled for you automatically. The same goes for quoting of column names (e.g., using double quotes or single quotes). This example output is in PostgreSQL syntax. The sqlall command doesn’t actually create the tables or otherwise touch your database – it just prints output to the screen so you can see what SQL Django would execute if you asked it. If you wanted to, you could copy and paste this SQL into your database client, or use Unix pipes to pass it directly (e.g., python manage.py sqlall books | psql mydb). However, Django provides an easier way of committing the SQL to the database: the syncdb command: python manage.py syncdb Run that command, and you’ll see something like this: Creating table books_publisher Creating table books_author Creating table books_book Installing index for books.Book model The syncdb command is a simple “sync” of your models to your database. It 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. (More on this in the “Making Changes to a Database Schema” section toward the end of this chapter.) If you run python manage.py syncdb again, nothing happens, because you haven’t added any models to the books app or added any apps to INSTALLED_APPS. Ergo, it’s always safe to run python manage.py syncdb – it won’t clobber things. If you’re interested, take a moment to dive into your database server’s command-line client and see the database tables Django created. You can manually run the command-line client (e.g., psql for PostgreSQL) or you can run the command python manage.py dbshell, which will figure out which command-line client to run, depending on your DATABASE_SERVER setting. The latter is almost always more convenient. 70 Chapter 7. Chapter 5: Models The Django Book, Release 2.0 7.8 Basic Data Access Once you’ve created a model, Django automatically provides a high-level Python API for working with those models. Try it out by running python manage.py shell and typing the following: >>> from books.models import Publisher >>> p1 = Publisher(name=’Apress’, address=’2855 Telegraph Avenue’, ... city=’Berkeley’, state_province=’CA’, country=’U.S.A.’, ... website=’http://www.apress.com/’) >>> p1.save() >>> p2 = Publisher(name="O’Reilly", address=’10 Fawcett St.’, ... city=’Cambridge’, state_province=’MA’, country=’U.S.A.’, ... website=’http://www.oreilly.com/’) >>> p2.save() >>> publisher_list = Publisher.objects.all() >>> publisher_list [, ] These few lines of code accomplish quite a bit. Here are the highlights: • First, we import our Publisher model class. This lets us interact with the database table that contains publishers. • We create a Publisher object by instantiating it with values for each field – name, address, etc. • To save the object to the database, call its save() method. Behind the scenes, Django executes an SQL INSERT statement here. • To retrieve publishers from the database, use the attribute Publisher.objects, which you can think of as a set of all publishers. Fetch a list of all Publisher objects in the database with the statement Publisher.objects.all(). Behind the scenes, Django executes an SQL SELECT statement here. One thing is worth mentioning, in case it wasn’t clear from this example. When you’re creating objects using the Django model API, Django doesn’t save the objects to the database until you call the save() method: p1 = Publisher(...) # At this point, p1 is not saved to the database yet! p1.save() # Now it is. If you want to create an object and save it to the database in a single step, use the objects.create() method. This example is equivalent to the example above: >>> ... ... ... >>> ... ... ... >>> >>> p1 = Publisher.objects.create(name=’Apress’, address=’2855 Telegraph Avenue’, city=’Berkeley’, state_province=’CA’, country=’U.S.A.’, website=’http://www.apress.com/’) p2 = Publisher.objects.create(name="O’Reilly", address=’10 Fawcett St.’, city=’Cambridge’, state_province=’MA’, country=’U.S.A.’, website=’http://www.oreilly.com/’) publisher_list = Publisher.objects.all() publisher_list Naturally, you can do quite a lot with the Django database API – but first, let’s take care of a small annoyance. 7.8. Basic Data Access 71 The Django Book, Release 2.0 7.9 Adding Model String Representations When we printed out the list of publishers, all we got was this unhelpful display that makes it difficult to tell the Publisher objects apart: [, ] We can fix this easily by adding a method called __unicode__() to our Publisher class. A __unicode__() method tells Python how to display the “unicode” representation of an object. You can see this in action by adding a __unicode__() method to the three models: from django.db import models class Publisher(models.Model): name = models.CharField(max_length=30) address = models.CharField(max_length=50) city = models.CharField(max_length=60) state_province = models.CharField(max_length=30) country = models.CharField(max_length=50) website = models.URLField() def __unicode__(self): return self.name class Author(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40) email = models.EmailField() def __unicode__(self): return u’%s %s’ % (self.first_name, self.last_name) class Book(models.Model): title = models.CharField(max_length=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField() def __unicode__(self): return self.title As you can see, a __unicode__() method can do whatever it needs to do in order to return a representation of an object. Here, the __unicode__() methods for Publisher and Book simply return the object’s name and title, respectively, but the __unicode__() for Author is slightly more complex – it pieces together the first_name and last_name fields, separated by a space. The only requirement for __unicode__() is that it return a Unicode object. If __unicode__() doesn’t return a Unicode object – if it returns, say, an integer – then Python will raise a TypeError with a message like "coercing to Unicode: need string or buffer, int found". Unicode objects What are Unicode objects? You can think of a Unicode object as a Python string that can handle more than a million different types of characters, from accented versions of Latin characters to non-Latin characters to curly quotes and obscure symbols. 72 Chapter 7. Chapter 5: Models The Django Book, Release 2.0 Normal Python strings are encoded, which means they use an encoding such as ASCII, ISO-8859-1 or UTF-8. If you’re storing fancy characters (anything beyond the standard 128 ASCII characters such as 0-9 and A-Z) in a normal Python string, you have to keep track of which encoding your string is using, or the fancy characters might appear messed up when they’re displayed or printed. Problems occur when you have data that’s stored in one encoding and you try to combine it with data in a different encoding, or you try to display it in an application that assumes a certain encoding. We’ve all seen Web pages and e-mails that are littered with ”??? ??????” or other characters in odd places; that generally suggests there’s an encoding problem. Unicode objects, however, have no encoding; they use a consistent, universal set of characters called, well, “Unicode.” When you deal with Unicode objects in Python, you can mix and match them safely without having to worry about encoding issues. Django uses Unicode objects throughout the framework. Model objects are retrieved as Unicode objects, views interact with Unicode data, and templates are rendered as Unicode. Generally, you won’t have to worry about making sure your encodings are right; things should just work. Note that this has been a very high-level, dumbed down overview of Unicode objects, and you owe it to yourself to learn more about the topic. A good place to start is http://www.joelonsoftware.com/articles/Unicode.html . For the __unicode__() changes to take effect, exit out of the Python shell and enter it again with python manage.py shell. (This is the simplest way to make code changes take effect.) Now the list of Publisher objects is much easier to understand: >>> from books.models import Publisher >>> publisher_list = Publisher.objects.all() >>> publisher_list [, ] Make sure any model you define has a __unicode__() method – not only for your own convenience when using the interactive interpreter, but also because Django uses the output of __unicode__() in several places when it needs to display objects. Finally, note that __unicode__() is a good example of adding behavior to models. A Django model describes more than the database table layout for an object; it also describes any functionality that object knows how to do. __unicode__() is one example of such functionality – a model knows how to display itself. 7.10 Inserting and Updating Data You’ve already seen this done: to insert a row into your database, first create an instance of your model using keyword arguments, like so: >>> p = Publisher(name=’Apress’, ... address=’2855 Telegraph Ave.’, ... city=’Berkeley’, ... state_province=’CA’, ... country=’U.S.A.’, ... website=’http://www.apress.com/’) As we noted above, this act of instantiating a model class does not touch the database. The record isn’t saved into the database until you call save(), like this: >>> p.save() In SQL, this can roughly be translated into the following: 7.10. Inserting and Updating Data 73 The Django Book, Release 2.0 INSERT INTO books_publisher (name, address, city, state_province, country, website) VALUES (’Apress’, ’2855 Telegraph Ave.’, ’Berkeley’, ’CA’, ’U.S.A.’, ’http://www.apress.com/’); Because the Publisher model uses an autoincrementing primary key id, the initial call to save() does one more thing: it calculates the primary key value for the record and sets it to the id attribute on the instance: >>> p.id 52 # this will differ based on your own data Subsequent calls to save() will save the record in place, without creating a new record (i.e., performing an SQL UPDATE statement instead of an INSERT): >>> p.name = ’Apress Publishing’ >>> p.save() The preceding save() statement will result in roughly the following SQL: UPDATE books_publisher SET name = ’Apress Publishing’, address = ’2855 Telegraph Ave.’, city = ’Berkeley’, state_province = ’CA’, country = ’U.S.A.’, website = ’http://www.apress.com’ WHERE id = 52; Yes, note that all of the fields will be updated, not just the ones that have been changed. Depending on your application, this may cause a race condition. See “Updating Multiple Objects in One Statement” below to find out how to execute this (slightly different) query: UPDATE books_publisher SET name = ’Apress Publishing’ WHERE id=52; 7.11 Selecting Objects Knowing how to create and update database records is essential, but chances are that the Web applications you’ll build will be doing more querying of existing objects than creating new ones. We’ve already seen a way to retrieve every record for a given model: >>> Publisher.objects.all() [, ] This roughly translates to this SQL: SELECT id, name, address, city, state_province, country, website FROM books_publisher; Note: Notice that Django doesn’t use SELECT * when looking up data and instead lists all fields explicitly. This is by design: in certain circumstances SELECT * can be slower, and (more important) listing fields more closely follows one tenet of the Zen of Python: “Explicit is better than implicit.” For more on the Zen of Python, try typing import this at a Python prompt. 74 Chapter 7. Chapter 5: Models The Django Book, Release 2.0 Let’s take a close look at each part of this Publisher.objects.all() line: • First, we have the model we defined, Publisher. No surprise here: when you want to look up data, you use the model for that data. • Next, we have the objects attribute. This is called a manager. Managers are discussed in detail in Chapter 10. For now, all you need to know is that managers take care of all “table-level” operations on data including, most important, data lookup. All models automatically get a objects manager; you’ll use it any time you want to look up model instances. • Finally, we have all(). This is a method on the objects manager that returns all the rows in the database. Though this object looks like a list, it’s actually a QuerySet – an object that represents a specific set of rows from the database. Appendix C deals with QuerySets in detail. For the rest of this chapter, we’ll just treat them like the lists they emulate. Any database lookup is going to follow this general pattern – we’ll call methods on the manager attached to the model we want to query against. 7.11.1 Filtering Data Naturally, it’s rare to want to select everything from a database at once; in most cases, you’ll want to deal with a subset of your data. In the Django API, you can filter your data using the filter() method: >>> Publisher.objects.filter(name=’Apress’) [] filter() takes keyword arguments that get translated into the appropriate SQL WHERE clauses. The preceding example would get translated into something like this: SELECT id, name, address, city, state_province, country, website FROM books_publisher WHERE name = ’Apress’; You can pass multiple arguments into filter() to narrow down things further: >>> Publisher.objects.filter(country="U.S.A.", state_province="CA") [] Those multiple arguments get translated into SQL AND clauses. Thus, the example in the code snippet translates into the following: SELECT id, name, address, city, state_province, country, website FROM books_publisher WHERE country = ’U.S.A.’ AND state_province = ’CA’; Notice that by default the lookups use the SQL = operator to do exact match lookups. Other lookup types are available: >>> Publisher.objects.filter(name__contains="press") [] That’s a double underscore there between name and contains. Like Python itself, Django uses the double underscore to signal that something “magic” is happening – here, the __contains part gets translated by Django into a SQL LIKE statement: SELECT id, name, address, city, state_province, country, website FROM books_publisher WHERE name LIKE ’%press%’; 7.11. Selecting Objects 75 The Django Book, Release 2.0 Many other types of lookups are available, including icontains (case-insensitive LIKE), startswith and endswith, and range (SQL BETWEEN queries). Appendix C describes all of these lookup types in detail. 7.11.2 Retrieving Single Objects The filter() examples above all returned a QuerySet, which you can treat like a list. Sometimes it’s more convenient to fetch only a single object, as opposed to a list. That’s what the get() method is for: >>> Publisher.objects.get(name="Apress") Instead of a list (rather, QuerySet), only a single object is returned. Because of that, a query resulting in multiple objects will cause an exception: >>> Publisher.objects.get(country="U.S.A.") Traceback (most recent call last): ... MultipleObjectsReturned: get() returned more than one Publisher -it returned 2! Lookup parameters were {’country’: ’U.S.A.’} A query that returns no objects also causes an exception: >>> Publisher.objects.get(name="Penguin") Traceback (most recent call last): ... DoesNotExist: Publisher matching query does not exist. The DoesNotExist exception is an attribute of the model’s class – Publisher.DoesNotExist. In your applications, you’ll want to trap these exceptions, like this: try: p = Publisher.objects.get(name=’Apress’) except Publisher.DoesNotExist: print "Apress isn’t in the database yet." else: print "Apress is in the database." 7.11.3 Ordering Data As you play around with the previous examples, you might discover that the objects are being returned in a seemingly random order. You aren’t imagining things; so far we haven’t told the database how to order its results, so we’re simply getting back data in some arbitrary order chosen by the database. In your Django applications, you’ll probably want to order your results according to a certain value – say, alphabetically. To do this, use the order_by() method: >>> Publisher.objects.order_by("name") [, ] This doesn’t look much different from the earlier all() example, but the SQL now includes a specific ordering: SELECT id, name, address, city, state_province, country, website FROM books_publisher ORDER BY name; You can order by any field you like: 76 Chapter 7. Chapter 5: Models The Django Book, Release 2.0 >>> Publisher.objects.order_by("address") [, ] >>> Publisher.objects.order_by("state_province") [, ] To order by multiple fields (where the second field is used to disambiguate ordering in cases where the first is the same), use multiple arguments: >>> Publisher.objects.order_by("state_province", "address") [, ] You can also specify reverse ordering by prefixing the field name with a - (that’s a minus character): >>> Publisher.objects.order_by("-name") [, ] While this flexibility is useful, using order_by() all the time can be quite repetitive. Most of the time you’ll have a particular field you usually want to order by. In these cases, Django lets you specify a default ordering in the model: class Publisher(models.Model): name = models.CharField(max_length=30) address = models.CharField(max_length=50) city = models.CharField(max_length=60) state_province = models.CharField(max_length=30) country = models.CharField(max_length=50) website = models.URLField() def __unicode__(self): return self.name class Meta: ordering = [’name’] Here, we’ve introduced a new concept: the class Meta, which is a class that’s embedded within the Publisher class definition (i.e., it’s indented to be within class Publisher). You can use this Meta class on any model to specify various model-specific options. A full reference of Meta options is available in Appendix B, but for now, we’re concerned with the ordering option. If you specify this, it tells Django that unless an ordering is given explicitly with order_by(), all Publisher objects should be ordered by the name field whenever they’re retrieved with the Django database API. 7.11.4 Chaining Lookups You’ve seen how you can filter data, and you’ve seen how you can order it. Often, of course, you’ll need to do both. In these cases, you simply “chain” the lookups together: >>> Publisher.objects.filter(country="U.S.A.").order_by("-name") [, ] As you might expect, this translates to a SQL query with both a WHERE and an ORDER BY: SELECT id, name, address, city, state_province, country, website FROM books_publisher WHERE country = ’U.S.A’ ORDER BY name DESC; 7.11. Selecting Objects 77 The Django Book, Release 2.0 7.11.5 Slicing Data Another common need is to look up only a fixed number of rows. Imagine you have thousands of publishers in your database, but you want to display only the first one. You can do this using Python’s standard list slicing syntax: >>> Publisher.objects.order_by(’name’)[0] This translates roughly to: SELECT id, name, address, city, state_province, country, website FROM books_publisher ORDER BY name LIMIT 1; Similarly, you can retrieve a specific subset of data using Python’s range-slicing syntax: >>> Publisher.objects.order_by(’name’)[0:2] This returns two objects, translating roughly to: SELECT id, name, address, city, state_province, country, website FROM books_publisher ORDER BY name OFFSET 0 LIMIT 2; Note that negative slicing is not supported: >>> Publisher.objects.order_by(’name’)[-1] Traceback (most recent call last): ... AssertionError: Negative indexing is not supported. This is easy to get around, though. Just change the order_by() statement, like this: >>> Publisher.objects.order_by(’-name’)[0] 7.11.6 Updating Multiple Objects in One Statement We pointed out in the “Inserting and Updating Data” section that the model save() method updates all columns in a row. Depending on your application, you may want to update only a subset of columns. For example, let’s say we want to update the Apress Publisher to change the name from ’Apress’ to ’Apress Publishing’. Using save(), it would look something like this: >>> p = Publisher.objects.get(name=’Apress’) >>> p.name = ’Apress Publishing’ >>> p.save() This roughly translates to the following SQL: SELECT id, name, address, city, state_province, country, website FROM books_publisher WHERE name = ’Apress’; UPDATE books_publisher SET name = ’Apress Publishing’, address = ’2855 Telegraph Ave.’, city = ’Berkeley’, 78 Chapter 7. Chapter 5: Models The Django Book, Release 2.0 state_province = ’CA’, country = ’U.S.A.’, website = ’http://www.apress.com’ WHERE id = 52; (Note that this example assumes Apress has a publisher ID of 52.) You can see in this example that Django’s save() method sets all of the column values, not just the name column. If you’re in an environment where other columns of the database might change due to some other process, it’s smarter to change only the column you need to change. To do this, use the update() method on QuerySet objects. Here’s an example: >>> Publisher.objects.filter(id=52).update(name=’Apress Publishing’) The SQL translation here is much more efficient and has no chance of race conditions: UPDATE books_publisher SET name = ’Apress Publishing’ WHERE id = 52; The update() method works on any QuerySet, which means you can edit multiple records in bulk. Here’s how you might change the country from ’U.S.A.’ to USA in each Publisher record: >>> Publisher.objects.all().update(country=’USA’) 2 The update() method has a return value – an integer representing how many records changed. In the above example, we got 2. 7.12 Deleting Objects To delete an object from your database, simply call the object’s delete() method: >>> p = Publisher.objects.get(name="O’Reilly") >>> p.delete() >>> Publisher.objects.all() [] You can also delete objects in bulk by calling delete() on the result of any QuerySet. This is similar to the update() method we showed in the last section: >>> Publisher.objects.filter(country=’USA’).delete() >>> Publisher.objects.all().delete() >>> Publisher.objects.all() [] Be careful deleting your data! As a precaution against deleting all of the data in a particular table, Django requires you to explicitly use all() if you want to delete everything in your table. For example, this won’t work: >>> Publisher.objects.delete() Traceback (most recent call last): File "", line 1, in AttributeError: ’Manager’ object has no attribute ’delete’ But it’ll work if you add the all() method: >>> Publisher.objects.all().delete() 7.12. Deleting Objects 79 The Django Book, Release 2.0 If you’re just deleting a subset of your data, you don’t need to include all(). To repeat a previous example: >>> Publisher.objects.filter(country=’USA’).delete() 7.13 What’s Next? Having read this chapter, you have enough knowledge of Django models to be able to write basic database applications. Chapter 10 will provide some information on more advanced usage of Django’s database layer. Once you’ve defined your models, the next step is to populate your database with data. You might have legacy data, in which case Chapter 18 will give you advice about integrating with legacy databases. You might rely on site users to supply your data, in which case Chapter 7 will teach you how to process user-submitted form data. But in some cases, you or your team might need to enter data manually, in which case it would be helpful to have a Web-based interface for entering and managing data. The next chapter Chapter 6 covers Django’s admin interface, which exists precisely for that reason. 80 Chapter 7. Chapter 5: Models CHAPTER 8 Chapter 6: The Django Admin Site For a certain class of Web sites, an admin interface is an essential part of the infrastructure. This is a Web-based interface, limited to trusted site administrators, that enables the adding, editing and deletion of site content. Some common examples: the interface you use to post to your blog, the backend site managers use to moderate usergenerated comments, the tool your clients use to update the press releases on the Web site you built for them. There’s a problem with admin interfaces, though: it’s boring to build them. Web development is fun when you’re developing public-facing functionality, but building admin interfaces is always the same. You have to authenticate users, display and handle forms, validate input, and so on. It’s boring, and it’s repetitive. So what’s Django’s approach to these boring, repetitive tasks? It does it all for you – in just a couple of lines of code, no less. With Django, building an admin interface is a solved problem. This chapter is about Django’s automatic admin interface. The feature works by reading metadata in your model to provide a powerful and production-ready interface that site administrators can start using immediately. Here, we discuss how to activate, use, and customize this feature. Note that we recommend reading this chapter even if you don’t intend to use the Django admin site, because we introduce a few concepts that apply to all of Django, regardless of admin-site usage. 8.1 The django.contrib packages Django’s automatic admin is part of a larger suite of Django functionality called django.contrib – the part of the Django codebase that contains various useful add-ons to the core framework. You can think of django.contrib as Django’s equivalent of the Python standard library – optional, de facto implementations of common patterns. They’re bundled with Django so that you don’t have to reinvent the wheel in your own applications. The admin site is the first part of django.contrib that we’re covering in this book; technically, it’s called django.contrib.admin. Other available features in django.contrib include a user authentication system (django.contrib.auth), support for anonymous sessions (django.contrib.sessions) and even a system for user comments (django.contrib.comments). You’ll get to know the various django.contrib features as you become a Django expert, and we’ll spend some more time discussing them in Chapter 16. For now, just know that Django ships with many nice add-ons, and django.contrib is generally where they live. 8.2 Activating the Admin Interface The Django admin site is entirely optional, because only certain types of sites need this functionality. That means you’ll need to take a few steps to activate it in your project. First, make a few changes to your settings file: 81 The Django Book, Release 2.0 1. Add ’django.contrib.admin’ to the INSTALLED_APPS setting. (The order of INSTALLED_APPS doesn’t matter, but we like to keep things alphabetical so it’s easy for a human to read.) 2. Make sure INSTALLED_APPS contains ’django.contrib.auth’, ’django.contrib.contenttypes’, ’django.contrib.messages’ and ’django.contrib.sessions’. The Django admin site requires these three packages. (If you’re following along with our ongoing mysite project, note that we commented out these four INSTALLED_APPS entries in Chapter 5. Uncomment them now.) 3. Make sure MIDDLEWARE_CLASSES contains ’django.middleware.common.CommonMiddleware’, ’django.contrib.messages.middleware.MessageMiddleware’, ’django.contrib.sessions.middleware.SessionMiddleware’ and ’django.contrib.auth.middleware.AuthenticationMiddleware’. (Again, if you’re following along, note that we commented them out in Chapter 5, so uncomment them.) Second, run python manage.py syncdb. This step will install the extra database tables that the admin interface uses. The first time you run syncdb with ’django.contrib.auth’ in INSTALLED_APPS, you’ll be asked about creating a superuser. If you don’t do this, you’ll need to run python manage.py createsuperuser separately to create an admin user account; otherwise, you won’t be able to log in to the admin site. (Potential gotcha: the python manage.py createsuperuser command is only available if ’django.contrib.auth’ is in your INSTALLED_APPS.) Third, add the admin site to your URLconf (in urls.py, remember). By default, the urls.py generated by django-admin.py startproject contains commented-out code for the Django admin, and all you have to do is uncomment it. For the record, here are the bits you need to make sure are in there: # Include these import statements... from django.contrib import admin admin.autodiscover() # And include this URLpattern... urlpatterns = patterns(’’, # ... (r’^admin/’, include(admin.site.urls)), # ... ) With that bit of configuration out of the way, now you can see the Django admin site in action. Just run the development server (python manage.py runserver, as in previous chapters) and visit http://127.0.0.1:8000/admin/ in your Web browser. 8.3 Using the Admin Site The admin site is designed to be used by nontechnical users, and as such it should be pretty self-explanatory. Nevertheless, we’ll give you a quick walkthrough of the basic features. The first thing you’ll see is a login screen, as shown in Figure 6-1. Log in with the username and password you set up when you added your superuser. If you’re unable to log in, make sure you’ve actually created a superuser – try running python manage.py createsuperuser. Once you’re logged in, the first thing you’ll see will be the admin home page. This page lists all the available types of data that can be edited on the admin site. At this point, because we haven’t activated any of our own models yet, the list is sparse: it includes only Groups and Users, which are the two default admin-editable models. Each type of data in the Django admin site has a change list and an edit form. Change lists show you all the available objects in the database, and edit forms let you add, change or delete particular records in your database. 82 Chapter 8. Chapter 6: The Django Admin Site The Django Book, Release 2.0 Figure 8.1: Figure 6-1. Django’s login screen 8.3. Using the Admin Site 83 The Django Book, Release 2.0 Figure 8.2: Figure 6-2. The Django admin home page 84 Chapter 8. Chapter 6: The Django Admin Site The Django Book, Release 2.0 Other languages If your primary language is not English and your Web browser is configured to prefer a language other than English, you can make a quick change to see whether the Django admin site has been translated into your language. Just add ’django.middleware.locale.LocaleMiddleware’ to your MIDDLEWARE_CLASSES setting, making sure it appears after ’django.contrib.sessions.middleware.SessionMiddleware’. When you’ve done that, reload the admin index page. If a translation for your language is available, then the various parts of the interface – from the “Change password” and “Log out” links at the top of the page, to the “Groups” and “Users” links in the middle – will appear in your language instead of English. Django ships with translations for dozens of languages. For much more on Django’s internationalization features, see Chapter 19. Click the “Change” link in the “Users” row to load the change list page for users. Figure 8.3: Figure 6-3. The user change list page This page displays all users in the database; you can think of it as a prettied-up Web version of a SELECT * FROM auth_user; SQL query. If you’re following along with our ongoing example, you’ll only see one user here, assuming you’ve added only one, but once you have more users, you’ll probably find the filtering, sorting and searching options useful. Filtering options are at right, sorting is available by clicking a column header, and the search box at the top lets you search by username. 8.3. Using the Admin Site 85 The Django Book, Release 2.0 Click the username of the user you created, and you’ll see the edit form for that user. Figure 8.4: Figure 6-4. The user edit form This page lets you change the attributes of the user, like the first/last names and various permissions. (Note that to change a user’s password, you should click “change password form” under the password field rather than editing the hashed code.) Another thing to note here is that fields of different types get different widgets – for example, date/time fields have calendar controls, boolean fields have checkboxes, character fields have simple text input fields. You can delete a record by clicking the delete button at the bottom left of its edit form. That’ll take you to a confirmation page, which, in some cases, will display any dependent objects that will be deleted, too. (For example, if you delete a publisher, any book with that publisher will be deleted, too!) You can add a record by clicking “Add” in the appropriate column of the admin home page. This will give you an empty version of the edit page, ready for you to fill out. You’ll also notice that the admin interface also handles input validation for you. Try leaving a required field blank or putting an invalid date into a date field, and you’ll see those errors when you try to save, as shown in Figure 6-5. When you edit an existing object, you’ll notice a History link in the upper-right corner of the window. Every change made through the admin interface is logged, and you can examine this log by clicking the History link (see Figure 6-6). 86 Chapter 8. Chapter 6: The Django Admin Site The Django Book, Release 2.0 Figure 8.5: Figure 6-5. An edit form displaying errors 8.3. Using the Admin Site 87 The Django Book, Release 2.0 Figure 8.6: Figure 6-6. An object history page 88 Chapter 8. Chapter 6: The Django Admin Site The Django Book, Release 2.0 8.4 Adding Your Models to the Admin Site There’s one crucial part we haven’t done yet. Let’s add our own models to the admin site, so we can add, change and delete objects in our custom database tables using this nice interface. We’ll continue the books example from Chapter 5, where we defined three models: Publisher, Author and Book. Within the books directory (mysite/books), create a file called admin.py, and type in the following lines of code: from django.contrib import admin from mysite.books.models import Publisher, Author, Book admin.site.register(Publisher) admin.site.register(Author) admin.site.register(Book) This code tells the Django admin site to offer an interface for each of these models. Once you’ve done this, go to your admin home page in your Web browser (http://127.0.0.1:8000/admin/), and you should see a “Books” section with links for Authors, Books and Publishers. (You might have to stop and start the runserver for the changes to take effect.) You now have a fully functional admin interface for each of those three models. That was easy! Take some time to add and change records, to populate your database with some data. If you followed Chapter 5’s examples of creating Publisher objects (and you didn’t delete them), you’ll already see those records on the publisher change list page. One feature worth mentioning here is the admin site’s handling of foreign keys and many-to-many relationships, both of which appear in the Book model. As a reminder, here’s what the Book model looks like: class Book(models.Model): title = models.CharField(max_length=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField() def __unicode__(self): return self.title On the Django admin site’s “Add book” page (http://127.0.0.1:8000/admin/books/book/add/), the publisher (a ForeignKey) is represented by a select box, and the authors field (a ManyToManyField) is represented by a multiple-select box. Both fields sit next to a green plus sign icon that lets you add related records of that type. For example, if you click the green plus sign next to the “Publisher” field, you’ll get a pop-up window that lets you add a publisher. After you successfully create the publisher in the pop-up, the “Add book” form will be updated with the newly created publisher. Slick. 8.5 How the Admin Site Works Behind the scenes, how does the admin site work? It’s pretty straightforward. When Django loads your URLconf from urls.py at server startup, it executes the admin.autodiscover() statement that we added as part of activating the admin. This function iterates over your INSTALLED_APPS setting and looks for a file called admin.py in each installed app. If an admin.py exists in a given app, it executes the code in that file. 8.4. Adding Your Models to the Admin Site 89 The Django Book, Release 2.0 In the admin.py in our books app, each call to admin.site.register() simply registers the given model with the admin. The admin site will only display an edit/change interface for models that have been explicitly registered. The app django.contrib.auth includes its own admin.py, which is why Users and Groups showed up automatically in the admin. Other django.contrib apps, such as django.contrib.redirects, also add themselves to the admin, as do many third-party Django applications you might download from the Web. Beyond that, the Django admin site is just a Django application, with its own models, templates, views and URLpatterns. You add it to your application by hooking it into your URLconf, just as you hook in your own views. You can inspect its templates, views and URLpatterns by poking around in django/contrib/admin in your copy of the Django codebase – but don’t be tempted to change anything directly in there, as there are plenty of hooks for you to customize the way the admin site works. (If you do decide to poke around the Django admin application, keep in mind it does some rather complicated things in reading metadata about models, so it would probably take a good amount of time to read and understand the code.) 8.6 Making Fields Optional After you play around with the admin site for a while, you’ll probably notice a limitation – the edit forms require every field to be filled out, whereas in many cases you’d want certain fields to be optional. Let’s say, for example, that we want our Author model’s email field to be optional – that is, a blank string should be allowed. In the real world, you might not have an e-mail address on file for every author. To specify that the email field is optional, edit the Author model (which, as you’ll recall from Chapter 5, lives in mysite/books/models.py). Simply add blank=True to the email field, like so: class Author(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40) email = models.EmailField(blank=True) This tells Django that a blank value is indeed allowed for authors’ e-mail addresses. By default, all fields have blank=False, which means blank values are not allowed. There’s something interesting happening here. Until now, with the exception of the __unicode__() method, our models have served as definitions of our database tables – Pythonic expressions of SQL CREATE TABLE statements, essentially. In adding blank=True, we have begun expanding our model beyond a simple definition of what the database table looks like. Now, our model class is starting to become a richer collection of knowledge about what Author objects are and what they can do. Not only is the email field represented by a VARCHAR column in the database; it’s also an optional field in contexts such as the Django admin site. Once you’ve added that blank=True, reload the “Add author” edit form (http://127.0.0.1:8000/admin/books/author/add/), and you’ll notice the field’s label – “Email” – is no longer bolded. This signifies it’s not a required field. You can now add authors without needing to provide e-mail addresses; you won’t get the loud red “This field is required” message anymore, if the field is submitted empty. 8.6.1 Making Date and Numeric Fields Optional A common gotcha related to blank=True has to do with date and numeric fields, but it requires a fair amount of background explanation. SQL has its own way of specifying blank values – a special value called NULL. NULL could mean “unknown,” or “invalid,” or some other application-specific meaning. 90 Chapter 8. Chapter 6: The Django Admin Site The Django Book, Release 2.0 In SQL, a value of NULL is different than an empty string, just as the special Python object None is different than an empty Python string (""). This means it’s possible for a particular character field (e.g., a VARCHAR column) to contain both NULL values and empty string values. This can cause unwanted ambiguity and confusion: “Why does this record have a NULL but this other one has an empty string? Is there a difference, or was the data just entered inconsistently?” And: “How do I get all the records that have a blank value – should I look for both NULL records and empty strings, or do I only select the ones with empty strings?” To help avoid such ambiguity, Django’s automatically generated CREATE TABLE statements (which were covered in Chapter 5) add an explicit NOT NULL to each column definition. For example, here’s the generated statement for our Author model, from Chapter 5: CREATE TABLE "books_author" ( "id" serial NOT NULL PRIMARY KEY, "first_name" varchar(30) NOT NULL, "last_name" varchar(40) NOT NULL, "email" varchar(75) NOT NULL ) ; In most cases, this default behavior is optimal for your application and will save you from data-inconsistency headaches. And it works nicely with the rest of Django, such as the Django admin site, which inserts an empty string (not a NULL value) when you leave a character field blank. But there’s an exception with database column types that do not accept empty strings as valid values – such as dates, times and numbers. If you try to insert an empty string into a date or integer column, you’ll likely get a database error, depending on which database you’re using. (PostgreSQL, which is strict, will raise an exception here; MySQL might accept it or might not, depending on the version you’re using, the time of day and the phase of the moon.) In this case, NULL is the only way to specify an empty value. In Django models, you can specify that NULL is allowed by adding null=True to a field. So that’s a long way of saying this: if you want to allow blank values in a date field (e.g., DateField, TimeField, DateTimeField) or numeric field (e.g., IntegerField, DecimalField, FloatField), you’ll need to use both null=True and blank=True. For sake of example, let’s change our Book model to allow a blank publication_date. Here’s the revised code: class Book(models.Model): title = models.CharField(max_length=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField(blank=True, null=True) Adding null=True is more complicated than adding blank=True, because null=True changes the semantics of the database – that is, it changes the CREATE TABLE statement to remove the NOT NULL from the publication_date field. To complete this change, we’ll need to update the database. For a number of reasons, Django does not attempt to automate changes to database schemas, so it’s your own responsibility to execute the appropriate ALTER TABLE statement whenever you make such a change to a model. Recall that you can use manage.py dbshell to enter your database server’s shell. Here’s how to remove the NOT NULL in this particular case: ALTER TABLE books_book ALTER COLUMN publication_date DROP NOT NULL; (Note that this SQL syntax is specific to PostgreSQL.) We’ll cover schema changes in more depth in Chapter 10. Bringing this back to the admin site, now the “Add book” edit form should allow for empty publication date values. 8.6. Making Fields Optional 91 The Django Book, Release 2.0 8.7 Customizing Field Labels On the admin site’s edit forms, each field’s label is generated from its model field name. The algorithm is simple: Django just replaces underscores with spaces and capitalizes the first character, so, for example, the Book model’s publication_date field has the label “Publication date.” However, field names don’t always lend themselves to nice admin field labels, so in some cases you might want to customize a label. You can do this by specifying verbose_name in the appropriate model field. For example, here’s how we can change the label of the Author.email field to “e-mail,” with a hyphen: class Author(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40) email = models.EmailField(blank=True, verbose_name=’e-mail’) Make that change and reload the server, and you should see the field’s new label on the author edit form. Note that you shouldn’t capitalize the first letter of a verbose_name unless it should always be capitalized (e.g., "USA state"). Django will automatically capitalize it when it needs to, and it will use the exact verbose_name value in other places that don’t require capitalization. Finally, note that you can pass the verbose_name as a positional argument, for a slightly more compact syntax. This example is equivalent to the previous one: class Author(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40) email = models.EmailField(‘e-mail’, blank=True) This won’t work with ManyToManyField or ForeignKey fields, though, because they require the first argument to be a model class. In those cases, specifying verbose_name explicitly is the way to go. 8.8 Custom ModelAdmin classes The changes we’ve made so far – blank=True, null=True and verbose_name – are really model-level changes, not admin-level changes. That is, these changes are fundamentally a part of the model and just so happen to be used by the admin site; there’s nothing admin-specific about them. Beyond these, the Django admin site offers a wealth of options that let you customize how the admin site works for a particular model. Such options live in ModelAdmin classes, which are classes that contain configuration for a specific model in a specific admin site instance. 8.8.1 Customizing change lists Let’s dive into admin customization by specifying the fields that are displayed on the change list for our Author model. By default, the change list displays the result of __unicode__() for each object. In Chapter 5, we defined the __unicode__() method for Author objects to display the first name and last name together: class Author(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40) email = models.EmailField(blank=True, verbose_name=’e-mail’) def __unicode__(self): return u’%s %s’ % (self.first_name, self.last_name) 92 Chapter 8. Chapter 6: The Django Admin Site The Django Book, Release 2.0 As a result, the change list for Author objects displays each other’s first name and last name together, as you can see in Figure 6-7. Figure 8.7: Figure 6-7. The author change list page We can improve on this default behavior by adding a few other fields to the change list display. It’d be handy, for example, to see each author’s e-mail address in this list, and it’d be nice to be able to sort by first and last name. To make this happen, we’ll define a ModelAdmin class for the Author model. This class is the key to customizing the admin, and one of the most basic things it lets you do is specify the list of fields to display on change list pages. Edit admin.py to make these changes: from django.contrib import admin from mysite.books.models import Publisher, Author, Book class AuthorAdmin(admin.ModelAdmin): list_display = (‘first_name’, ‘last_name’, ‘email’) admin.site.register(Publisher) admin.site.register(Author, AuthorAdmin) admin.site.register(Book) Here’s what we’ve done: 8.8. Custom ModelAdmin classes 93 The Django Book, Release 2.0 • We created the class AuthorAdmin. This class, which subclasses django.contrib.admin.ModelAdmin, holds custom configuration for a specific admin model. We’ve only specified one customization – list_display, which is set to a tuple of field names to display on the change list page. These field names must exist in the model, of course. • We altered the admin.site.register() call to add AuthorAdmin after Author. You can read this as: “Register the Author model with the AuthorAdmin options.” The admin.site.register() function takes a ModelAdmin subclass as an optional second argument. If you don’t specify a second argument (as is the case for Publisher and Book), Django will use the default admin options for that model. With that tweak made, reload the author change list page, and you’ll see it’s now displaying three columns – the first name, last name and e-mail address. In addition, each of those columns is sortable by clicking on the column header. (See Figure 6-8.) Figure 8.8: Figure 6-8. The author change list page after list_display Next, let’s add a simple search bar. Add search_fields to the AuthorAdmin, like so: class AuthorAdmin(admin.ModelAdmin): list_display = (‘first_name’, ‘last_name’, ‘email’) search_fields = (‘first_name’, ‘last_name’) 94 Chapter 8. Chapter 6: The Django Admin Site The Django Book, Release 2.0 Reload the page in your browser, and you should see a search bar at the top. (See Figure 6-9.) We’ve just told the admin change list page to include a search bar that searches against the first_name and last_name fields. As a user might expect, this is case-insensitive and searches both fields, so searching for the string "bar" would find both an author with the first name Barney and an author with the last name Hobarson. Figure 8.9: Figure 6-9. The author change list page after search_fields Next, let’s add some date filters to our Book model’s change list page: from django.contrib import admin from mysite.books.models import Publisher, Author, Book class AuthorAdmin(admin.ModelAdmin): list_display = (‘first_name’, ‘last_name’, ‘email’) search_fields = (‘first_name’, ‘last_name’) class BookAdmin(admin.ModelAdmin): list_display = (‘title’, ‘publisher’, ‘publication_date’) list_filter = (‘publication_date’,) admin.site.register(Publisher) admin.site.register(Author, AuthorAdmin) admin.site.register(Book, BookAdmin) 8.8. Custom ModelAdmin classes 95 The Django Book, Release 2.0 Here, because we’re dealing with a different set of options, we created a separate ModelAdmin class – BookAdmin. First, we defined a list_display just to make the change list look a bit nicer. Then, we used list_filter, which is set to a tuple of fields to use to create filters along the right side of the change list page. For date fields, Django provides shortcuts to filter the list to “Today,” “Past 7 days,” “This month” and “This year” – shortcuts that Django’s developers have found hit the common cases for filtering by date. Figure 6-10 shows what that looks like. Figure 8.10: Figure 6-10. The book change list page after list_filter list_filter also works on fields of other types, not just DateField. (Try it with BooleanField and ForeignKey fields, for example.) The filters show up as long as there are at least 2 values to choose from. Another way to offer date filters is to use the date_hierarchy admin option, like this: class BookAdmin(admin.ModelAdmin): list_display = (‘title’, ‘publisher’, ‘publication_date’) list_filter = (‘publication_date’,) date_hierarchy = ‘publication_date’ With this in place, the change list page gets a date drill-down navigation bar at the top of the list, as shown in Figure 6-11. It starts with a list of available years, then drills down into months and individual days. Note that date_hierarchy takes a string, not a tuple, because only one date field can be used to make the hierarchy. Finally, let’s change the default ordering so that books on the change list page are always ordered descending by their publication date. By default, the change list orders objects according to their model’s ordering within class 96 Chapter 8. Chapter 6: The Django Admin Site The Django Book, Release 2.0 Figure 8.11: Figure 6-11. The book change list page after date_hierarchy 8.8. Custom ModelAdmin classes 97 The Django Book, Release 2.0 Meta (which we covered in Chapter 5) – but you haven’t specified this ordering value, then the ordering is undefined. class BookAdmin(admin.ModelAdmin): list_display = (‘title’, ‘publisher’, ‘publication_date’) list_filter = (‘publication_date’,) date_hierarchy = ‘publication_date’ ordering = (‘-publication_date’,) This admin ordering option works exactly as the ordering in models’ class Meta, except that it only uses the first field name in the list. Just pass a list or tuple of field names, and add a minus sign to a field to use descending sort order. Reload the book change list to see this in action. Note that the “Publication date” header now includes a small arrow that indicates which way the records are sorted. (See Figure 6-12.) Figure 8.12: Figure 6-12. The book change list page after ordering We’ve covered the main change list options here. Using these options, you can make a very powerful, production-ready data-editing interface with only a few lines of code. 98 Chapter 8. Chapter 6: The Django Admin Site The Django Book, Release 2.0 8.8.2 Customizing edit forms Just as the change list can be customized, edit forms can be customized in many ways. First, let’s customize the way fields are ordered. By default, the order of fields in an edit form corresponds to the order they’re defined in the model. We can change that using the fields option in our ModelAdmin subclass: class BookAdmin(admin.ModelAdmin): list_display = (‘title’, ‘publisher’, ‘publication_date’) list_filter = (‘publication_date’,) date_hierarchy = ‘publication_date’ ordering = (‘-publication_date’,) fields = (‘title’, ‘authors’, ‘publisher’, ‘publication_date’) After this change, the edit form for books will use the given ordering for fields. It’s slightly more natural to have the authors after the book title. Of course, the field order should depend on your data-entry workflow. Every form is different. Another useful thing the fields option lets you do is to exclude certain fields from being edited entirely. Just leave out the field(s) you want to exclude. You might use this if your admin users are only trusted to edit a certain segment of your data, or if part of your fields are changed by some outside, automated process. For example, in our book database, we could hide the publication_date field from being editable: class BookAdmin(admin.ModelAdmin): list_display = (‘title’, ‘publisher’, ‘publication_date’) list_filter = (‘publication_date’,) date_hierarchy = ‘publication_date’ ordering = (‘-publication_date’,) fields = (‘title’, ‘authors’, ‘publisher’) As a result, the edit form for books doesn’t offer a way to specify the publication date. This could be useful, say, if you’re an editor who prefers that his authors not push back publication dates. (This is purely a hypothetical example, of course.) When a user uses this incomplete form to add a new book, Django will simply set the publication_date to None – so make sure that field has null=True. Another commonly used edit-form customization has to do with many-to-many fields. As we’ve seen on the edit form for books, the admin site represents each ManyToManyField as a multiple-select boxes, which is the most logical HTML input widget to use – but multiple-select boxes can be difficult to use. If you want to select multiple items, you have to hold down the control key, or command on a Mac, to do so. The admin site helpfully inserts a bit of text that explains this, but, still, it gets unwieldy when your field contains hundreds of options. The admin site’s solution is filter_horizontal. Let’s add that to BookAdmin and see what it does. class BookAdmin(admin.ModelAdmin): list_display = (‘title’, ‘publisher’, ‘publication_date’) list_filter = (‘publication_date’,) date_hierarchy = ‘publication_date’ ordering = (‘-publication_date’,) filter_horizontal = (‘authors’,) (If you’re following along, note that we’ve also removed the fields option to restore all the fields in the edit form.) Reload the edit form for books, and you’ll see that the “Authors” section now uses a fancy JavaScript filter interface that lets you search through the options dynamically and move specific authors from “Available authors” to the “Chosen authors” box, and vice versa. We’d highly recommend using filter_horizontal for any ManyToManyField that has more than 10 items. It’s far easier to use than a simple multiple-select widget. Also, note you can use filter_horizontal for multiple 8.8. Custom ModelAdmin classes 99 The Django Book, Release 2.0 Figure 8.13: Figure 6-13. The book edit form after adding filter_horizontal 100 Chapter 8. Chapter 6: The Django Admin Site The Django Book, Release 2.0 fields – just specify each name in the tuple. ModelAdmin classes also support a filter_vertical option. This works exactly as filter_horizontal, but the resulting JavaScript interface stacks the two boxes vertically instead of horizontally. It’s a matter of personal taste. filter_horizontal and filter_vertical only work on ManyToManyField fields, not ForeignKey fields. By default, the admin site uses simple box. The way to fix this is to use an option called raw_id_fields. Set this to a tuple of ForeignKey field names, and those fields will be displayed in the admin with a simple text input box () instead of a 9.2. A Simple Form-Handling Example 107 The Django Book, Release 2.0 The URLpattern in urls.py could look like this: from mysite.books import views urlpatterns = patterns(’’, # ... url(r’^search-form/$’, views.search_form), # ... ) (Note that we’re importing the views module directly, instead of something like from mysite.views import search_form, because the former is less verbose. We’ll cover this importing approach in more detail in Chapter 8.) Now, if you run the runserver and visit http://127.0.0.1:8000/search-form/, you’ll see the search interface. Simple enough. Try submitting the form, though, and you’ll get a Django 404 error. The form points to the URL /search/, which hasn’t yet been implemented. Let’s fix that with a second view function: # urls.py urlpatterns = patterns(’’, # ... (r’^search-form/$’, views.search_form), (r’^search/$’, views.search), # ... ) # views.py def search(request): if ’q’ in request.GET: message = ’You searched for: %r’ % request.GET[’q’] else: message = ’You submitted an empty form.’ return HttpResponse(message) For the moment, this merely displays the user’s search term, so we can make sure the data is being submitted to Django properly, and so you can get a feel for how the search term flows through the system. In short: 1. The HTML
    defines a variable q. (method="get") to the URL /search/. When it’s submitted, the value of q is sent via GET 2. The Django view that handles the URL /search/ (search()) has access to the q value in request.GET. An important thing to point out here is that we explicitly check that ’q’ exists in request.GET. As we pointed out in the request.META section above, you shouldn’t trust anything submitted by users or even assume that they’ve submitted anything in the first place. If we didn’t add this check, any submission of an empty form would raise KeyError in the view: # BAD! def bad_search(request): # The following line will raise KeyError if ’q’ hasn’t # been submitted! message = ’You searched for: %r’ % request.GET[’q’] return HttpResponse(message) 108 Chapter 9. Chapter 7: Forms The Django Book, Release 2.0 Query string parameters Because GET data is passed in the query string (e.g., /search/?q=django), you can use request.GET to access query string variables. In Chapter 3’s introduction of Django’s URLconf system, we compared Django’s pretty URLs to more traditional PHP/Java URLs such as /time/plus?hours=3 and said we’d show you how to do the latter in Chapter 7. Now you know how to access query string parameters in your views (like hours=3 in this example) – use request.GET. POST data works the same way as GET data – just use request.POST instead of request.GET. What’s the difference between GET and POST? Use GET when the act of submitting the form is just a request to “get” data. Use POST whenever the act of submitting the form will have some side effect – changing data, or sending an e-mail, or something else that’s beyond simple display of data. In our book-search example, we’re using GET because the query doesn’t change any data on our server. (See http://www.w3.org/2001/tag/doc/whenToUseGet.html if you want to learn more about GET and POST.) Now that we’ve verified request.GET is being passed in properly, let’s hook the user’s search query into our book database (again, in views.py): from django.http import HttpResponse from django.shortcuts import render from mysite.books.models import Book def search(request): if ’q’ in request.GET and request.GET[’q’]: q = request.GET[’q’] books = Book.objects.filter(title__icontains=q) return render(request, ’search_results.html’, {’books’: books, ’query’: q}) else: return HttpResponse(’Please submit a search term.’) A couple of notes on what we did here: • Aside from checking that ’q’ exists in request.GET, we also make sure that request.GET[’q’] is a non-empty value before passing it to the database query. • We’re using Book.objects.filter(title__icontains=q) to query our book table for all books whose title includes the given submission. The icontains is a lookup type (as explained in Chapter 5 and Appendix B), and the statement can be roughly translated as “Get the books whose title contains q, without being case-sensitive.” This is a very simple way to do a book search. We wouldn’t recommend using a simple icontains query on a large production database, as it can be slow. (In the real world, you’d want to use a custom search system of some sort. Search the Web for open-source full-text search to get an idea of the possibilities.) • We pass books, a list of Book objects, to the template. The template code for search_results.html might include something like this:

    You searched for: {{ query }}

    {% if books %}

    Found {{ books|length }} book{{ books|pluralize }}.

      {% for book in books %}
    • {{ book.title }}
    • {% endfor %}
    {% else %} 9.2. A Simple Form-Handling Example 109 The Django Book, Release 2.0

    No books matched your search criteria.

    {% endif %} Note usage of the pluralize template filter, which outputs an “s” if appropriate, based on the number of books found. 9.3 Improving Our Simple Form-Handling Example As in previous chapters, we’ve shown you the simplest thing that could possibly work. Now we’ll point out some problems and show you how to improve it. First, our search() view’s handling of an empty query is poor – we’re just displaying a "Please submit a search term." message, requiring the user to hit the browser’s back button. This is horrid and unprofessional, and if you ever actually implement something like this in the wild, your Django privileges will be revoked. It would be much better to redisplay the form, with an error above it, so that the user can try again immediately. The easiest way to do that would be to render the template again, like this: from django.http import HttpResponse from django.shortcuts import render from mysite.books.models import Book def search_form(request): return render(request, ‘search_form.html’) def search(request): if ‘q’ in request.GET and request.GET[’q’]: q = request.GET[’q’] books = Book.objects.filter(title__icontains=q) return render(request, ‘search_results.html’, {‘books’: books, ‘query’: q}) else: return render(request, ‘search_form.html’, {‘error’: True}) (Note that we’ve included search_form() here so you can see both views in one place.) Here, we’ve improved search() to render the search_form.html template again, if the query is empty. And because we need to display an error message in that template, we pass a template variable. Now we can edit search_form.html to check for the error variable: Search {% if error %}

    Please submit a search term.

    {% endif %}
    110 Chapter 9. Chapter 7: Forms The Django Book, Release 2.0 We can still use this template from our original view, search_form(), because search_form() doesn’t pass error to the template – so the error message won’t show up in that case. With this change in place, it’s a better application, but it now begs the question: is a dedicated search_form() view really necessary? As it stands, a request to the URL /search/ (without any GET parameters) will display the empty form (but with an error). We can remove the search_form() view, along with its associated URLpattern, as long as we change search() to hide the error message when somebody visits /search/ with no GET parameters: def search(request): error = False if ’q’ in request.GET: q = request.GET[’q’] if not q: error = True else: books = Book.objects.filter(title__icontains=q) return render(request, ’search_results.html’, {’books’: books, ’query’: q}) return render(request, ’search_form.html’, {’error’: error}) In this updated view, if a user visits /search/ with no GET parameters, he’ll see the search form with no error message. If a user submits the form with an empty value for ’q’, he’ll see the search form with an error message. And, finally, if a user submits the form with a non-empty value for ’q’, he’ll see the search results. We can make one final improvement to this application, to remove a bit of redundancy. Now that we’ve rolled the two views and URLs into one and /search/ handles both search-form display and result display, the HTML
    in search_form.html doesn’t have to hard-code a URL. Instead of this: It can be changed to this: The action="" means “Submit the form to the same URL as the current page.” With this change in place, you won’t have to remember to change the action if you ever hook the search() view to another URL. 9.4 Simple validation Our search example is still reasonably simple, particularly in terms of its data validation; we’re merely checking to make sure the search query isn’t empty. Many HTML forms include a level of validation that’s more complex than making sure the value is non-empty. We’ve all seen the error messages on Web sites: • “Please enter a valid e-mail address. ‘foo’ is not an e-mail address.” • “Please enter a valid five-digit U.S. ZIP code. ‘123’ is not a ZIP code.” • “Please enter a valid date in the format YYYY-MM-DD.” • “Please enter a password that is at least 8 characters long and contains at least one number.” A note on JavaScript validation This is beyond the scope of this book, but you can use JavaScript to validate data on the client side, directly in the browser. But be warned: even if you do this, you must validate data on the server side, too. Some people have JavaScript turned off, and some malicious users might submit raw, unvalidated data directly to your form handler to see whether they can cause mischief. 9.4. Simple validation 111 The Django Book, Release 2.0 There’s nothing you can do about this, other than always validate user-submitted data server-side (i.e., in your Django views). You should think of JavaScript validation as a bonus usability feature, not as your only means of validating. Let’s tweak our search() view so that it validates that the search term is less than or equal to 20 characters long. (For sake of example, let’s say anything longer than that might make the query too slow.) How might we do that? The simplest possible thing would be to embed the logic directly in the view, like this: def search(request): error = False if ‘q’ in request.GET: q = request.GET[’q’] if not q: error = True elif len(q) > 20: error = True else: books = Book.objects.filter(title__icontains=q) return render(request, ‘search_results.html’, {‘books’: books, ‘query’: q}) return render(request, ‘search_form.html’, {‘error’: error}) Now, if you try submitting a search query greater than 20 characters long, it won’t let you search; you’ll get an error message. But that error message in search_form.html currently says "Please submit a search term." – so we’ll have to change it to be accurate for both cases: Search {% if error %}

    Please submit a search term 20 characters or shorter.

    {% endif %}
    There’s something ugly about this. Our one-size-fits-all error message is potentially confusing. Why should the error message for an empty form submission mention anything about a 20-character limit? Error messages should be specific, unambiguous and not confusing. The problem is in the fact that we’re using a simple boolean value for error, whereas we should be using a list of error message strings. Here’s how we might fix that: def search(request): errors = [] if ‘q’ in request.GET: q = request.GET[’q’] if not q: errors.append(‘Enter a search term.’) elif len(q) > 20: errors.append(‘Please enter at most 20 characters.’) else: 112 Chapter 9. Chapter 7: Forms The Django Book, Release 2.0 books = Book.objects.filter(title__icontains=q) return render(request, ‘search_results.html’, {‘books’: books, ‘query’: q}) return render(request, ‘search_form.html’, {‘errors’: errors}) Then, we need make a small tweak to the search_form.html template to reflect that it’s now passed an errors list instead of an error boolean value: Search {% if errors %}
      {% for error in errors %}
    • {{ error }}
    • {% endfor %}
    {% endif %}
    9.5 Making a Contact Form Although we iterated over the book search form example several times and improved it nicely, it’s still fundamentally simple: just a single field, ’q’. Because it’s so simple, we didn’t even use Django’s form library to deal with it. But more complex forms call for more complex treatment – and now we’ll develop something more complex: a site contact form. This will be a form that lets site users submit a bit of feedback, along with an optional e-mail return address. After the form is submitted and the data is validated, we’ll automatically send the message via e-mail to the site staff. We’ll start with our template, contact_form.html. Contact us

    Contact us

    {% if errors %}
      {% for error in errors %}
    • {{ error }}
    • {% endfor %}
    {% endif %}
    9.5. Making a Contact Form 113 The Django Book, Release 2.0

    Subject:

    Your e-mail (optional):

    Message:

    We’ve defined three fields: the subject, e-mail address and message. The second is optional, but the other two fields are required. Note we’re using method="post" here instead of method="get" because this form submission has a side effect – it sends an e-mail. Also, we copied the error-displaying code from our previous template search_form.html. If we continue down the road established by our search() view from the previous section, a naive version of our contact() view might look like this: from django.core.mail import send_mail from django.http import HttpResponseRedirect from django.shortcuts import render def contact(request): errors = [] if request.method == ’POST’: if not request.POST.get(’subject’, ’’): errors.append(’Enter a subject.’) if not request.POST.get(’message’, ’’): errors.append(’Enter a message.’) if request.POST.get(’email’) and ’@’ not in request.POST[’email’]: errors.append(’Enter a valid e-mail address.’) if not errors: send_mail( request.POST[’subject’], request.POST[’message’], request.POST.get(’email’, ’noreply@example.com’), [’siteowner@example.com’], ) return HttpResponseRedirect(’/contact/thanks/’) return render(request, ’contact_form.html’, {’errors’: errors}) (If you’re following along, you may be wondering whether to put this view in the books/views.py file. It doesn’t have anything to do with the books application, so should it live elsewhere? It’s totally up to you; Django doesn’t care, as long as you’re able to point to the view from your URLconf. Our personal preference would be to create a separate directory, contact, at the same level in the directory tree as books. This would contain an empty __init__.py and views.py.) A couple of new things are happening here: • We’re checking that request.method is ’POST’. This will only be true in the case of a form submission; it won’t be true if somebody is merely viewing the contact form. (In the latter case, request.method will be set to ’GET’, because in normal Web browsing, browsers use GET, not POST.) This makes it a nice way to isolate the “form display” case from the “form processing” case. • Instead of request.GET, we’re using request.POST to access the submitted form data. This is necessary because the HTML
    in contact_form.html uses method="post". If this view is accessed via POST, then request.GET will be empty. • This time, we have two required fields, subject and message, so we have to validate both. Note that we’re using request.POST.get() and providing a blank string as the default value; this is a nice, short way of 114 Chapter 9. Chapter 7: Forms The Django Book, Release 2.0 handling both the cases of missing keys and missing data. • Although the email field is not required, we still validate it if it is indeed submitted. Our validation algorithm here is fragile – we’re just checking that the string contains an @ character. In the real world, you’d want more robust validation (and Django provides it, which we’ll show you very shortly). • We’re using the function django.core.mail.send_mail to send an e-mail. This function has four required arguments: the e-mail subject, the e-mail body, the “from” address, and a list of recipient addresses. send_mail is a convenient wrapper around Django’s EmailMessage class, which provides advanced features such as attachments, multipart e-mails, and full control over e-mail headers. Note that in order to send e-mail using send_mail(), your server must be configured to send mail, and Django must be told about your outbound e-mail server. See http://docs.djangoproject.com/en/dev/topics/email/ for the specifics. • After the e-mail is sent, we redirect to a “success” page by returning an HttpResponseRedirect object. We’ll leave the implementation of that “success” page up to you (it’s a simple view/URLconf/template), but we should explain why we initiate a redirect instead of, for example, simply calling render() with a template right there. The reason: if a user hits “Refresh” on a page that was loaded via POST, that request will be repeated. This can often lead to undesired behavior, such as a duplicate record being added to the database – or, in our example, the e-mail being sent twice. If the user is redirected to another page after the POST, then there’s no chance of repeating the request. You should always issue a redirect for successful POST requests. It’s a Web development best practice. This view works, but those validation functions are kind of crufty. Imagine processing a form with a dozen fields; would you really want to have to write all of those if statements? Another problem is form redisplay. In the case of validation errors, it’s best practice to redisplay the form with the previously submitted data already filled in, so the user can see what he did wrong (and also so the user doesn’t have to reenter data in fields that were submitted correctly). We could manually pass the POST data back to the template, but we’d have to edit each HTML field to insert the proper value in the proper place: # views.py def contact(request): errors = [] if request.method == ‘POST’: if not request.POST.get(‘subject’, ‘’): errors.append(‘Enter a subject.’) if not request.POST.get(‘message’, ‘’): errors.append(‘Enter a message.’) if request.POST.get(‘email’) and ‘@’ not in request.POST[’email’]: errors.append(‘Enter a valid e-mail address.’) if not errors: send_mail( request.POST[’subject’], request.POST[’message’], request.POST.get(‘email’, ‘noreply@example.com‘), [‘siteowner@example.com‘], ) return HttpResponseRedirect(‘/contact/thanks/’) return render(request, ‘contact_form.html’, { ‘errors’: errors, ‘subject’: request.POST.get(‘subject’, ‘’), ‘message’: request.POST.get(‘message’, ‘’), 9.5. Making a Contact Form 115 The Django Book, Release 2.0 ‘email’: request.POST.get(‘email’, ‘’), }) # contact_form.html Contact us

    Contact us

    {% if errors %}
      {% for error in errors %}
    • {{ error }}
    • {% endfor %}
    {% endif %}

    Subject:

    Your e-mail (optional): Message: