Django 1.2 Manual
Django 1.2 Manual
Release 1.2
CONTENTS
I
1
Getting started
Django at a glance 1.1 Design your model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2 Install it . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3 Enjoy the free API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.4 A dynamic admin interface: its not just scaffolding its the whole house . 1.5 Design your URLs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.6 Write your views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.7 Design your templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.8 This is just the surface . . . . . . . . . . . . . . . . . . . . . . . . . . . . Quick install guide 2.1 Install Python . . . . . . . . . . . . 2.2 Set up a database . . . . . . . . . . 2.3 Remove any old versions of Django 2.4 Install Django . . . . . . . . . . . 2.5 Thats it! . . . . . . . . . . . . . . Writing your rst Django app, part 1 3.1 Creating a project . . . . . . . . 3.2 Creating models . . . . . . . . . 3.3 Activating models . . . . . . . . 3.4 Playing with the API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1
5 5 5 6 7 7 8 8 9 11 11 11 11 12 12 13 13 16 17 19 23 23 24 24 25 25 27 28 31 33 33 35 35 35
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
Writing your rst Django app, part 2 4.1 Activate the admin site . . . . . . . . . . . 4.2 Start the development server . . . . . . . . 4.3 Enter the admin site . . . . . . . . . . . . 4.4 Make the poll app modiable in the admin 4.5 Explore the free admin functionality . . . . 4.6 Customize the admin form . . . . . . . . . 4.7 Adding related objects . . . . . . . . . . . 4.8 Customize the admin change list . . . . . . 4.9 Customize the admin look and feel . . . . 4.10 Customize the admin index page . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
Writing your rst Django app, part 3 5.1 Philosophy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2 Design your URLs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Write your rst view . . . . . . . . . . Write views that actually do something Raising 404 . . . . . . . . . . . . . . . Write a 404 (page not found) view . . . Write a 500 (server error) view . . . . Use the template system . . . . . . . . Simplifying the URLconfs . . . . . . . Decoupling the URLconfs . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
37 38 39 40 41 41 41 42 43 43 45 47 49 49 49 50 50 51
Writing your rst Django app, part 4 6.1 Write a simple form . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2 Use generic views: Less code is better . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.3 Coming soon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . What to read next 7.1 Finding documentation . . . . . . . . 7.2 How the documentation is organized 7.3 How documentation is updated . . . 7.4 Where to get it . . . . . . . . . . . . 7.5 Differences between versions . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
II
8
Using Django
How to install Django 8.1 Install Python . . . . . . . . . . . . 8.2 Install Apache and mod_wsgi . . . 8.3 Get your database running . . . . . 8.4 Remove any old versions of Django 8.5 Install the Django code . . . . . . . Models and databases 9.1 Models . . . . . . . . . . . . . 9.2 Making queries . . . . . . . . . 9.3 Aggregation . . . . . . . . . . 9.4 Managers . . . . . . . . . . . . 9.5 Performing raw SQL queries . . 9.6 Managing database transactions 9.7 Multiple databases . . . . . . . 9.8 Database access optimization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
53
57 57 57 57 58 59 61 61 77 93 99 104 108 113 121 127 127 139 142 147 151 151 154
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
10 Handling HTTP requests 10.1 URL dispatcher . . . . . . 10.2 Writing Views . . . . . . 10.3 File Uploads . . . . . . . 10.4 Django shortcut functions 10.5 Generic views . . . . . . 10.6 Middleware . . . . . . . . 10.7 How to use sessions . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
11 Working with forms 163 11.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 11.2 Form objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 11.3 Further topics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
ii
12 Creating forms from models 195 12.1 ModelForm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195 12.2 Model formsets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202 12.3 Inline formsets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206 13 The Django template language 13.1 Templates . . . . . . . . . . . 13.2 Variables . . . . . . . . . . . 13.3 Filters . . . . . . . . . . . . . 13.4 Tags . . . . . . . . . . . . . . 13.5 Comments . . . . . . . . . . 13.6 Template inheritance . . . . . 13.7 Automatic HTML escaping . 13.8 Using the built-in reference . 13.9 Custom tag and lter libraries 209 209 210 210 211 212 212 214 217 218
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
14 Generic views 219 14.1 Using generic views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219 14.2 Generic views of objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220 14.3 Extending generic views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222 15 Managing les 227 15.1 Using les in models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227 15.2 The File object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227 15.3 File storage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228 16 Testing Django applications 16.1 Writing tests . . . . . . . . . . . . 16.2 Running tests . . . . . . . . . . . . 16.3 Testing tools . . . . . . . . . . . . 16.4 Using different testing frameworks 17 User authentication in Django 17.1 Overview . . . . . . . . . . . . 17.2 Installation . . . . . . . . . . . 17.3 Users . . . . . . . . . . . . . . 17.4 Authentication in Web requests 17.5 Permissions . . . . . . . . . . . 17.6 Authentication data in templates 17.7 Groups . . . . . . . . . . . . . 17.8 Messages . . . . . . . . . . . . 17.9 Other authentication sources . . 231 231 234 237 248 251 251 251 252 257 265 266 267 268 268 273 273 276 277 278 279 281 282 283 284 284
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
18 Djangos cache framework 18.1 Setting up the cache . . . . . . . . . . 18.2 The per-site cache . . . . . . . . . . . 18.3 The per-view cache . . . . . . . . . . . 18.4 Template fragment caching . . . . . . 18.5 The low-level cache API . . . . . . . . 18.6 Upstream caches . . . . . . . . . . . . 18.7 Using Vary headers . . . . . . . . . . . 18.8 Controlling cache: Using other headers 18.9 Other optimizations . . . . . . . . . . 18.10 Order of MIDDLEWARE_CLASSES .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
iii
19 Conditional View Processing 19.1 The condition decorator . . . . . . . . . . . . . 19.2 Shortcuts for only computing one value . . . . . . . 19.3 Using the decorators with other HTTP methods . . . 19.4 Comparison with middleware conditional processing 20 Sending e-mail 20.1 Quick example . . . . . . . 20.2 send_mail() . . . . . . . . . 20.3 send_mass_mail() . . . . . 20.4 mail_admins() . . . . . . . 20.5 mail_managers() function . 20.6 Examples . . . . . . . . . . 20.7 Preventing header injection 20.8 The EmailMessage class . . 20.9 E-Mail Backends . . . . . . 20.10 Testing e-mail sending . . . 20.11 SMTPConnection . . . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
287 287 288 289 289 291 291 291 292 292 293 293 293 294 296 299 299
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
21 Internationalization and localization 301 21.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301 21.2 Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317 21.3 Specialties of Django translation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318 22 Pagination 22.1 Example . . . . . . . . . . . 22.2 Using Paginator in a view 22.3 Paginator objects . . . . . 22.4 InvalidPage exceptions . 22.5 Page objects . . . . . . . . . 23 Serializing Django objects 23.1 Serializing data . . . 23.2 Deserializing data . 23.3 Serialization formats 23.4 Natural keys . . . . 319 319 320 321 322 322 325 325 326 327 328 333 333 333 334 334 335 335 335 335 336
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
24 Django settings 24.1 The basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24.2 Designating the settings . . . . . . . . . . . . . . . . . . . . . . 24.3 Default settings . . . . . . . . . . . . . . . . . . . . . . . . . . . 24.4 Using settings in Python code . . . . . . . . . . . . . . . . . . . 24.5 Altering settings at runtime . . . . . . . . . . . . . . . . . . . . 24.6 Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24.7 Available settings . . . . . . . . . . . . . . . . . . . . . . . . . . 24.8 Creating your own settings . . . . . . . . . . . . . . . . . . . . . 24.9 Using settings without setting DJANGO_SETTINGS_MODULE
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
25 Signals 339 25.1 Listening to signals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339 25.2 Dening and sending signals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340
iv
III
How-to guides
343
26 Authenticating against Djangos user database from Apache 347 26.1 Conguring Apache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347 27 Authentication using REMOTE_USER 349 27.1 Conguration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349 27.2 RemoteUserBackend . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350 28 Writing custom django-admin commands 351 28.1 Command objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352 29 Writing custom model elds 29.1 Introduction . . . . . . . . . . 29.2 Background theory . . . . . . . 29.3 Writing a eld subclass . . . . 29.4 Writing a FileField subclass 355 355 356 357 365
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
30 Custom template tags and lters 367 30.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367 31 Writing a custom storage system 381 31.1 _open(name, mode=rb) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382 31.2 _save(name, content) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382 32 Deploying Django 32.1 How to use Django with Apache and mod_wsgi . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32.2 How to use Django with Apache and mod_python . . . . . . . . . . . . . . . . . . . . . . . . . . . 32.3 How to use Django with FastCGI, SCGI, or AJP . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383 383 385 390
33 Error reporting via e-mail 397 33.1 Server errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397 33.2 404 errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397 34 Providing initial data for models 399 34.1 Providing initial data with xtures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399 34.2 Providing initial SQL data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400 35 Using internationalization in your own projects 403 35.1 Using translations outside views and templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404 36 Running Django on Jython 36.1 Installing Jython . . . . . . . . . . . . . . 36.2 Creating a servlet container . . . . . . . . 36.3 Installing Django . . . . . . . . . . . . . . 36.4 Installing Jython platform support libraries 36.5 Differences with Django on Jython . . . . 37 Integrating Django with a legacy database 37.1 Give Django your database parameters 37.2 Auto-generate the models . . . . . . . 37.3 Install the core Django tables . . . . . 37.4 Test and tweak . . . . . . . . . . . . . 405 405 405 405 405 406 407 407 407 408 408
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
38 Outputting CSV with Django 409 38.1 Using the Python CSV library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409
38.2 Using the template system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410 38.3 Other text-based formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410 39 Outputting PDFs with Django 39.1 Install ReportLab . . . . . 39.2 Write your view . . . . . 39.3 Complex PDFs . . . . . . 39.4 Further resources . . . . . 39.5 Other formats . . . . . . . 411 411 411 412 413 413 415 415 415 416 417
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
40 How to serve static les 40.1 The big, fat disclaimer . . . . 40.2 How to do it . . . . . . . . . 40.3 Directory listings . . . . . . . 40.4 Limiting use to DEBUG=True
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
IV
Django FAQ
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . the View the . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
419
421 421 421 421 422 422 422 422 423 423 423 423 424 425 425 425 425 426 426 426 426 427 427 427 427 427 428 429 429 429 429 429
41 FAQ: General 41.1 Why does this project exist? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41.2 What does Django mean, and how do you pronounce it? . . . . . . . . . . . . . . . 41.3 Is Django stable? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41.4 Does Django scale? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41.5 Whos behind this? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41.6 Which sites use Django? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41.7 Django appears to be a MVC framework, but you call the Controller the view, and template. How come you dont use the standard names? . . . . . . . . . . . . . . . 41.8 <Framework X> does <feature Y> why doesnt Django? . . . . . . . . . . . . . . . 41.9 Why did you write all of Django from scratch, instead of using other Python libraries? 41.10 Is Django a content-management-system (CMS)? . . . . . . . . . . . . . . . . . . . . 41.11 How can I download the Django documentation to read it ofine? . . . . . . . . . . . 41.12 Where can I nd Django developers for hire? . . . . . . . . . . . . . . . . . . . . . .
42 FAQ: Installation 42.1 How do I get started? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42.2 What are Djangos prerequisites? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42.3 Do I lose anything by using Python 2.4 versus newer Python versions, such as Python 2.5 or 2.6? 42.4 Can I use Django with Python 2.3? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42.5 Can I use Django with Python 3? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42.6 Will Django run under shared hosting (like TextDrive or Dreamhost)? . . . . . . . . . . . . . . . 42.7 Should I use the stable version or development version? . . . . . . . . . . . . . . . . . . . . . . 43 FAQ: Using Django 43.1 Why do I get an error about importing DJANGO_SETTINGS_MODULE? 43.2 I cant stand your template language. Do I have to use it? . . . . . . . . . . 43.3 Do I have to use your model/database layer? . . . . . . . . . . . . . . . . 43.4 How do I use image and le elds? . . . . . . . . . . . . . . . . . . . . . 43.5 How do I make a variable available to all my templates? . . . . . . . . . . 44 FAQ: Getting Help 44.1 How do I do X? Why doesnt Y work? Where can I go to get help? 44.2 Why hasnt my message appeared on django-users? . . . . . . . . 44.3 Nobody on django-users answered my question! What should I do? 44.4 I think Ive found a bug! What should I do? . . . . . . . . . . . . .
. . . . . . .
. . . . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
vi
44.5 I think Ive found a security problem! What should I do? . . . . . . . . . . . . . . . . . . . . . . . . 430 45 FAQ: Databases and models 45.1 How can I see the raw SQL queries Django is running? . . . . . . . . . . . . . . . . . . . . . . . . . 45.2 Can I use Django with a pre-existing database? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45.3 If I make changes to a model, how do I update the database? . . . . . . . . . . . . . . . . . . . . . . 45.4 Do Django models support multiple-column primary keys? . . . . . . . . . . . . . . . . . . . . . . . 45.5 How do I add database-specic options to my CREATE TABLE statements, such as specifying MyISAM as the table type? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45.6 Why is Django leaking memory? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 FAQ: The admin 46.1 I cant log in. When I enter a valid username and password, it just brings up the login page again, with no error messages. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46.2 I cant log in. When I enter a valid username and password, it brings up the login page again, with a Please enter a correct username and password error. . . . . . . . . . . . . . . . . . . . . . . . . . 46.3 How can I prevent the cache middleware from caching the admin site? . . . . . . . . . . . . . . . . . 46.4 How do I automatically set a elds value to the user who last edited the object in the admin? . . . . 46.5 How do I limit admin access so that objects can only be edited by the users who created them? . . . . 46.6 My admin-site CSS and images showed up ne using the development server, but theyre not displaying when using mod_python. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46.7 My list_lter contains a ManyToManyField, but the lter doesnt display. . . . . . . . . . . . . . . 46.8 How can I customize the functionality of the admin interface? . . . . . . . . . . . . . . . . . . . . . 46.9 The dynamically-generated admin site is ugly! How can I change it? . . . . . . . . . . . . . . . . . 47 FAQ: Contributing code 47.1 How can I get started contributing code to Django? . . . . . . . . . . . . . . . . . . . . . . . 47.2 I submitted a bug x in the ticket system several weeks ago. Why are you ignoring my patch? 47.3 When and how might I remind the core team of a patch I care about? . . . . . . . . . . . . . 47.4 But Ive reminded you several times and you keep ignoring my patch! . . . . . . . . . . . . . 431 431 431 431 432 432 432 433 433 433 433 433 434 434 434 434 434 435 435 435 435 436
. . . .
. . . .
. . . .
. . . .
API Reference
437
48 Authentication backends 439 48.1 Available authentication backends . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439 49 contrib packages 49.1 The Django admin site . . . . . . . . 49.2 django.contrib.auth . . . . . 49.3 Djangos comments framework . . . 49.4 The contenttypes framework . . . . . 49.5 Cross Site Request Forgery protection 49.6 Databrowse . . . . . . . . . . . . . . 49.7 The atpages app . . . . . . . . . . . 49.8 django.contrib.formtools . . . . . . . 49.9 GeoDjango . . . . . . . . . . . . . . 49.10 django.contrib.humanize . . . . . . . 49.11 The local avor add-ons . . . . . . 49.12 The messages framework . . . . . . 49.13 The redirects app . . . . . . . . . . . 49.14 The sitemap framework . . . . . . . 49.15 The sites framework . . . . . . . . 49.16 The syndication feed framework . . . 49.17 django.contrib.webdesign . . . . . . 441 441 470 470 487 491 497 498 500 506 603 604 614 620 621 626 632 646 vii
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
49.18 49.19 49.20 49.21 49.22 49.23 49.24 49.25 49.26 49.27 49.28 49.29 49.30 49.31 49.32 49.33 49.34 49.35 49.36
admin . . . . . auth . . . . . . comments . . . contenttypes . csrf . . . . . . atpages . . . formtools . . . gis . . . . . . humanize . . . localavor . . markup . . . . messages . . . redirects . . . sessions . . . . sites . . . . . . sitemaps . . . syndication . . webdesign . . Other add-ons
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
647 647 648 648 648 648 648 649 649 649 649 649 650 650 650 650 650 650 650 651 651 652 655 657 659 661 661 662 673 674 674 677 677 678 678
50 Databases 50.1 PostgreSQL notes . . . . . . . . . 50.2 MySQL notes . . . . . . . . . . . . 50.3 SQLite notes . . . . . . . . . . . . 50.4 Oracle notes . . . . . . . . . . . . 50.5 Using a 3rd-party database backend 51 django-admin.py and manage.py 51.1 Usage . . . . . . . . . . . . 51.2 Available subcommands . . 51.3 Default options . . . . . . . 51.4 Common options . . . . . . 51.5 Extra niceties . . . . . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
52 Django Exceptions 52.1 Django-specic Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52.2 Database Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52.3 Python Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
53 File handling 679 53.1 The File object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 679 53.2 File storage API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 680 54 Forms 54.1 The Forms API . . . . . 54.2 Form elds . . . . . . . 54.3 Widgets . . . . . . . . . 54.4 Form and eld validation 683 683 695 709 713 719 719 721 728 730
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
55 Generic views 55.1 Simple generic views . . . . . . 55.2 Date-based generic views . . . . . 55.3 List/detail generic views . . . . . . 55.4 Create/update/delete generic views
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
viii
56 Middleware 735 56.1 Available middleware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 735 57 Models 57.1 Model eld reference . . . 57.2 Related objects reference . 57.3 Model Meta options . . . 57.4 Model instance reference . 57.5 QuerySet API reference . 739 739 752 754 757 765
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
58 Request and response objects 793 58.1 Quick overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 793 58.2 HttpRequest objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 793 58.3 HttpResponse objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 798 59 Settings 803 59.1 Available settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 803 59.2 Deprecated settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 823 60 Signals 60.1 Model signals . . . . . . 60.2 Management signals . . 60.3 Request/response signals 60.4 Test signals . . . . . . . 825 825 828 829 830
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
61 Templates 831 61.1 Built-in template tags and lters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 831 61.2 The Django template language: For Python programmers . . . . . . . . . . . . . . . . . . . . . . . 861 62 Unicode data 62.1 Creating the database . . 62.2 General string handling 62.3 Models . . . . . . . . . 62.4 The database API . . . . 62.5 Templates . . . . . . . . 62.6 E-mail . . . . . . . . . 62.7 Form submission . . . . 873 873 873 876 876 877 877 877 879 879 880 881 881 883 884 884 885 887 887 887 888
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
63 Django Utils 63.1 django.utils.cache . . . . . . . 63.2 SortedDict . . . . . . . . . . . . . . . 63.3 django.utils.encoding . . . . 63.4 django.utils.feedgenerator 63.5 django.utils.http . . . . . . . 63.6 django.utils.safestring . . . 63.7 django.utils.translation . . 63.8 django.utils.tzinfo . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
64 Validators 64.1 Writing validators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64.2 How validators are run . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64.3 Built-in validators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
ix
VI
891
65 API stability 895 65.1 What stable means . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 895 65.2 Stable APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 895 65.3 Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 896 66 Design philosophies 66.1 Overall . . . . . 66.2 Models . . . . . 66.3 Database API . . 66.4 URL design . . . 66.5 Template system 66.6 Views . . . . . . 899 899 900 900 901 901 903
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
VII VIII
907 911
915 915 930 937 953 959 959 960 962 971 972 975 977 978 980 982
68 Final releases 68.1 1.2 release . . 68.2 1.1 release . . 68.3 1.0 release . . 68.4 Pre-1.0 releases
69 Development releases 69.1 Django 1.2 RC 1 release notes . 69.2 Django 1.2 beta 1 release notes 69.3 Django 1.2 alpha 1 release notes 69.4 Django 1.1 RC 1 release notes . 69.5 Django 1.1 beta 1 release notes 69.6 Django 1.1 alpha 1 release notes 69.7 Django 1.0 beta 2 release notes 69.8 Django 1.0 beta 1 release notes 69.9 Django 1.0 alpha 2 release notes 69.10 Django 1.0 alpha release notes .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
IX
Django internals
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
985
989 989 990 990 992 994 995 995 996 998
70 Contributing to Django 70.1 Reporting bugs . . . . . . . . . . . . . 70.2 Reporting security issues . . . . . . . . 70.3 Submitting patches . . . . . . . . . . . 70.4 Ticket triage . . . . . . . . . . . . . . 70.5 Submitting and maintaining translations 70.6 Submitting javascript patches . . . . . 70.7 Django conventions . . . . . . . . . . 70.8 Coding style . . . . . . . . . . . . . . 70.9 Documentation style . . . . . . . . . .
Committing code . . Unit tests . . . . . . Requesting features Branch policy . . . . Deciding on features Commit access . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
1000 1000 1002 1003 1005 1005 1007 1007 1008 1009 1009
71 How the Django documentation works 71.1 Django-specic markup . . . . . 71.2 An example . . . . . . . . . . . . 71.3 TODO . . . . . . . . . . . . . . 71.4 Hints . . . . . . . . . . . . . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
72 Django committers 72.1 The original team . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72.2 Current developers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72.3 Developers Emeritus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
73 Djangos release process 1015 73.1 Ofcial releases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1015 73.2 Supported versions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1016 73.3 Release process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1016 74 Django Deprecation Timeline 75 The Django source code repository 75.1 High-level overview . . . . . 75.2 Working with Djangos trunk 75.3 Branches . . . . . . . . . . . 75.4 Tags . . . . . . . . . . . . . . 1019 1021 1021 1021 1022 1023
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
X XI
1025 1029
76 Deprecated/obsolete documentation 1033 76.1 Customizing the Django admin interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1033 Module Index Index 1037 1039
xi
xii
Part I
Getting started
New to Django? Or to web development in general? Well, you came to the right place: read this material to quickly get up and running.
CHAPTER
ONE
DJANGO AT A GLANCE
Because Django was developed in a fast-paced newsroom environment, it was designed to make common Webdevelopment tasks fast and easy. Heres an informal overview of how to write a database-driven Web app with Django. The goal of this document is to give you enough technical specics to understand how Django works, but this isnt intended to be a tutorial or reference but weve got both! When youre ready to start a project, you can start with the tutorial or dive right into more detailed documentation.
1.2 Install it
Next, run the Django command-line utility to create the database tables automatically:
manage.py syncdb
The syncdb command looks at all your available models and creates tables in your database for whichever tables dont already exist.
>>> r.article_set.all() [<Article: Django is cool>] # The API follows relationships as far as you need, performing efficient # JOINs for you behind the scenes. # This finds all articles by a reporter whose name starts with "John". >>> Article.objects.filter(reporter__full_name__startswith="John") [<Article: Django is cool>] # Change an object by altering its attributes and calling save(). >>> r.full_name = Billy Goat >>> r.save() # Delete an object with delete(). >>> r.delete()
1.4 A dynamic admin interface: its not just scaffolding its the whole house
Once your models are dened, Django can automatically create a professional, production ready administrative interface a Web site that lets authenticated users add, change and delete objects. Its as easy as registering your model in the admin site:
# In models.py... from django.db import models class Article(models.Model): pub_date = models.DateTimeField() headline = models.CharField(max_length=200) content = models.TextField() reporter = models.ForeignKey(Reporter)
# In admin.py in the same directory... import models from django.contrib import admin admin.site.register(models.Article)
The philosophy here is that your site is edited by a staff, or a client, or maybe just you and you dont want to have to deal with creating backend interfaces just to manage content. One typical workow in creating Django apps is to create models and get the admin sites up and running as fast as possible, so your staff (or clients) can start populating data. Then, develop the way data is presented to the public.
1.4. A dynamic admin interface: its not just scaffolding its the whole house
To design URLs for an app, you create a Python module called a URLconf . A table of contents for your app, it contains a simple mapping between URL patterns and Python callback functions. URLconfs also serve to decouple URLs from Python code. Heres what a URLconf might look like for the Reporter/Article example above:
from django.conf.urls.defaults import * urlpatterns = patterns(, (r^articles/(\d{4})/$, mysite.views.year_archive), (r^articles/(\d{4})/(\d{2})/$, mysite.views.month_archive), (r^articles/(\d{4})/(\d{2})/(\d+)/$, mysite.views.article_detail), )
The code above maps URLs, as simple regular expressions, to the location of Python callback functions (views). The regular expressions use parenthesis to capture values from the URLs. When a user requests a page, Django runs through each pattern, in order, and stops at the rst one that matches the requested URL. (If none of them matches, Django calls a special-case 404 view.) This is blazingly fast, because the regular expressions are compiled at load time. Once one of the regexes matches, Django imports and calls the given view, which is a simple Python function. Each view gets passed a request object which contains request metadata and the values captured in the regex. For example, if a user requested the URL /articles/2005/05/39323/, Django would call the function mysite.views.article_detail(request, 2005, 05, 39323).
This example uses Djangos template system, which has several powerful features but strives to stay simple enough for non-programmers to use.
{% block content %} <h1>Articles for {{ year }}</h1> {% for article in article_list %} <p>{{ article.headline }}</p> <p>By {{ article.reporter.full_name }}</p> <p>Published {{ article.pub_date|date:"F j, Y" }}</p> {% endfor %} {% endblock %}
Variables are surrounded by double-curly braces. {{ article.headline }} means Output the value of the articles headline attribute. But dots arent used only for attribute lookup: They also can do dictionary-key lookup, index lookup and function calls. Note {{ article.pub_date|date:"F j, Y" }} uses a Unix-style pipe (the | character). This is called a template lter, and its a way to lter the value of a variable. In this case, the date lter formats a Python datetime object in the given format (as found in PHPs date function; yes, there is one good idea in PHP). You can chain together as many lters as youd like. You can write custom lters. You can write custom template tags, which run custom Python code behind the scenes. Finally, Django uses the concept of template inheritance: Thats what the {% extends "base.html" %} does. It means First load the template called base, which has dened a bunch of blocks, and ll the blocks with the following blocks. In short, that lets you dramatically cut down on redundancy in templates: each template has to dene only whats unique to that template. Heres what the base.html template might look like:
<html> <head> <title>{% block title %}{% endblock %}</title> </head> <body> <img src="sitelogo.gif" alt="Logo" /> {% block content %}{% endblock %} </body> </html>
Simplistically, it denes the look-and-feel of the site (with the sites logo), and provides holes for child templates to ll. This makes a site redesign as easy as changing a single le the base template. It also lets you create multiple versions of a site, with different base templates, while reusing child templates. Djangos creators have used this technique to create strikingly different cell-phone editions of sites simply by creating a new base template. Note that you dont have to use Djangos template system if you prefer another system. While Djangos template system is particularly well-integrated with Djangos model layer, nothing forces you to use it. For that matter, you dont have to use Djangos database API, either. You can use another database abstraction layer, you can read XML les, you can read les off disk, or anything you want. Each piece of Django models, views, templates is decoupled from the next.
A syndication framework that makes creating RSS and Atom feeds as easy as writing a small Python class. More sexy automatically-generated admin features this overview barely scratched the surface. The next obvious steps are for you to download Django, read the tutorial and join the community. Thanks for your interest!
10
CHAPTER
TWO
11
12
CHAPTER
THREE
Where should this code live? If your background is in PHP, youre probably used to putting code under the Web servers document root (in a place such as /var/www). With Django, you dont do that. Its not a good idea to put any of this Python code within your Web servers document root, because it risks the possibility that people may be able to view your code over the Web. Thats not good for security. Put your code in some directory outside of the document root, such as /home/mycode. Lets look at what startproject created:
mysite/ __init__.py manage.py settings.py urls.py
These les are: __init__.py: An empty le that tells Python that this directory should be considered a Python package. (Read more about packages in the ofcial Python docs if youre a Python beginner.) manage.py: A command-line utility that lets you interact with this Django project in various ways. You can read all the details about manage.py in django-admin.py and manage.py. settings.py: Settings/conguration for this Django project. Django settings will tell you all about how settings work. urls.py: The URL declarations for this Django project; a table of contents of your Django-powered site. You can read more about URLs in URL dispatcher.
Youve started the Django development server, a lightweight Web server written purely in Python. Weve included this with Django so you can develop things rapidly, without having to deal with conguring a production server such as Apache until youre ready for production. Nows a good time to note: DONT use this server in anything resembling a production environment. Its intended only for use while developing. (Were in the business of making Web frameworks, not Web servers.) Now that the servers running, visit http://127.0.0.1:8000/ with your Web browser. Youll see a Welcome to Django page, in pleasant, light-blue pastel. It worked! Changing the port By default, the runserver command starts the development server on the internal IP at port 8000. If you want to change the servers port, pass it as a command-line argument. For instance, this command starts the server on port 8080:
14
If you want to change the servers IP, pass it along with the port. So to listen on all public IPs (useful if you want to show off your work on other computers), use:
python manage.py runserver 0.0.0.0:8000
Full docs for the development server can be found in the runserver reference.
15
The syncdb command looks at the INSTALLED_APPS setting and creates any necessary database tables according to the database settings in your settings.py le. Youll see a message for each database table it creates, and youll get a prompt asking you if youd like to create a superuser account for the authentication system. Go ahead and do that. If youre interested, run the command-line client for your database and type \dt (PostgreSQL), SHOW TABLES; (MySQL), or .schema (SQLite) to display the tables Django created. For the minimalists Like we said above, the default applications are included for the common case, but not everybody needs them. If you dont need any or all of them, feel free to comment-out or delete the appropriate line(s) from INSTALLED_APPS before running syncdb. The syncdb command will only create tables for apps in INSTALLED_APPS.
This directory structure will house the poll application. The rst step in writing a database Web app in Django is to dene your models essentially, your database layout, with additional metadata. Philosophy A model is the single, denitive source of data about your data. It contains the essential elds and behaviors of the data youre storing. Django follows the DRY Principle. The goal is to dene your data model in one place and automatically derive things from it.
16
In our simple poll app, well create two models: polls and choices. A poll has a question and a publication date. A choice has two elds: the text of the choice and a vote tally. Each choice is associated with a poll. These concepts are represented by simple Python classes. Edit the polls/models.py le so it looks like this:
from django.db import models class Poll(models.Model): question = models.CharField(max_length=200) pub_date = models.DateTimeField(date published) class Choice(models.Model): poll = models.ForeignKey(Poll) choice = models.CharField(max_length=200) votes = models.IntegerField()
The code is straightforward. Each model is represented by a class that subclasses django.db.models.Model. Each model has a number of class variables, each of which represents a database eld in the model. Each eld is represented by an instance of a Field class e.g., CharField for character elds and DateTimeField for datetimes. This tells Django what type of data each eld holds. The name of each Field instance (e.g. question or pub_date ) is the elds name, in machine-friendly format. Youll use this value in your Python code, and your database will use it as the column name. You can use an optional rst positional argument to a Field to designate a human-readable name. Thats used in a couple of introspective parts of Django, and it doubles as documentation. If this eld isnt provided, Django will use the machine-readable name. In this example, weve only dened a human-readable name for Poll.pub_date. For all other elds in this model, the elds machine-readable name will sufce as its human-readable name. Some Field classes have required elements. CharField, for example, requires that you give it a max_length. Thats used not only in the database schema, but in validation, as well soon see. Finally, note a relationship is dened, using ForeignKey. That tells Django each Choice is related to a single Poll. Django supports all the common database relationships: many-to-ones, many-to-manys and one-to-ones.
17
mysite.polls )
Now Django knows mysite includes the polls app. Lets run another command:
python manage.py sql polls
You should see something similar to the following (the CREATE TABLE SQL statements for the polls app):
BEGIN; CREATE TABLE "polls_poll" ( "id" serial NOT NULL PRIMARY KEY, "question" varchar(200) NOT NULL, "pub_date" timestamp with time zone NOT NULL ); CREATE TABLE "polls_choice" ( "id" serial NOT NULL PRIMARY KEY, "poll_id" integer NOT NULL REFERENCES "polls_poll" ("id"), "choice" varchar(200) NOT NULL, "votes" integer NOT NULL ); COMMIT;
Note the following: The exact output will vary depending on the database you are using. Table names are automatically generated by combining the name of the app (polls) and the lowercase name of the model poll and choice. (You can override this behavior.) Primary keys (IDs) are added automatically. (You can override this, too.) By convention, Django appends "_id" to the foreign key eld name. Yes, you can override this, as well. The foreign key relationship is made explicit by a REFERENCES statement. Its tailored to the database youre using, so database-specic eld types such as auto_increment (MySQL), serial (PostgreSQL), or integer primary key (SQLite) are handled for you automatically. Same goes for quoting of eld names e.g., using double quotes or single quotes. The author of this tutorial runs PostgreSQL, so the example output is in PostgreSQL syntax. The sql command doesnt actually run the SQL in your database - it just prints it to the screen so that you can see what SQL Django thinks is required. If you wanted to, you could copy and paste this SQL into your database prompt. However, as we will see shortly, Django provides an easier way of committing the SQL to the database. If youre interested, also run the following commands: python manage.py validate Checks for any errors in the construction of your models. python manage.py sqlcustom polls Outputs any custom SQL statements (such as table modications or constraints) that are dened for the application. python manage.py sqlclear polls Outputs the necessary DROP TABLE statements for this app, according to which tables already exist in your database (if any). python manage.py sqlindexes polls Outputs the CREATE INDEX statements for this app. python manage.py sqlall polls A combination of all the SQL from the sql, sqlcustom, and sqlindexes commands.
18
Looking at the output of those commands can help you understand whats actually happening under the hood. Now, run syncdb again to create those model tables in your database:
python manage.py syncdb
The syncdb command runs the sql from sqlall on your database for all apps in INSTALLED_APPS that dont already exist in your database. This creates all the tables, initial data and indexes for any apps you have added to your project since the last time you ran syncdb. syncdb can be called as often as you like, and it will only ever create the tables that dont exist. Read the django-admin.py documentation for full information on what the manage.py utility can do.
Were using this instead of simply typing python, because manage.py sets up the projects environment for you. Setting up the environment involves two things: Putting mysite on sys.path. For exibility, several pieces of Django refer to projects in Python dotted-path notation (e.g. mysite.polls.models). In order for this to work, the mysite package has to be on sys.path. Weve already seen one example of this: the INSTALLED_APPS setting is a list of packages in dotted-path notation. Setting the DJANGO_SETTINGS_MODULE environment variable, which gives Django the path to your settings.py le. Bypassing manage.py If youd rather not use manage.py, no problem. Just make sure mysite is at the root level on the Python path (i.e., import mysite works) and set the DJANGO_SETTINGS_MODULE environment variable to mysite.settings. For more information on all of this, see the django-admin.py documentation. Once youre in the shell, explore the database API :
>>> from mysite.polls.models import Poll, Choice # Import the model classes we just wrote. # No polls are in the system yet. >>> Poll.objects.all() [] # Create a new Poll. >>> import datetime >>> p = Poll(question="Whats up?", pub_date=datetime.datetime.now()) # Save the object into the database. You have to call save() explicitly. >>> p.save() # Now it has an ID. Note that this might say "1L" instead of "1", depending # on which database youre using. Thats no biggie; it just means your
19
# database backend prefers to return integers as Python long integer # objects. >>> p.id 1 # Access database columns via Python attributes. >>> p.question "Whats up?" >>> p.pub_date datetime.datetime(2007, 7, 15, 12, 00, 53) # Change values by changing the attributes, then calling save(). >>> p.pub_date = datetime.datetime(2007, 4, 1, 0, 0) >>> p.save() # objects.all() displays all the polls in the database. >>> Poll.objects.all() [<Poll: Poll object>]
Wait a minute. <Poll: Poll object> is, utterly, an unhelpful representation of this object. Lets x that by editing the polls model (in the polls/models.py le) and adding a __unicode__() method to both Poll and Choice:
class Poll(models.Model): # ... def __unicode__(self): return self.question class Choice(models.Model): # ... def __unicode__(self): return self.choice
If __unicode__() doesnt seem to work If you add the __unicode__() method to your models and dont see any change in how theyre represented, youre most likely using an old version of Django. (This version of the tutorial is written for the latest development version of Django.) If youre using a Subversion checkout of Djangos development version (see the installation docs for more information), you shouldnt have any problems. If you want to stick with an older version of Django, youll want to switch to the Django 0.96 tutorial, because this tutorial covers several features that only exist in the Django development version. Its important to add __unicode__() methods to your models, not only for your own sanity when dealing with the interactive prompt, but also because objects representations are used throughout Djangos automatically-generated admin. Why __unicode__() and not __str__()? If youre familiar with Python, you might be in the habit of adding __str__() methods to your classes, not __unicode__() methods. We use __unicode__() here because Django models deal with Unicode by default. All data stored in your database is converted to Unicode when its returned. Django models have a default __str__() method that calls __unicode__() and converts the result to a UTF-8 bytestring. This means that unicode(p) will return a Unicode string, and str(p) will return a normal string, with characters encoded as UTF-8. If all of this is jibberish to you, just remember to add __unicode__() methods to your models. With any luck, things should Just Work for you.
20
Note these are normal Python methods. Lets add a custom method, just for demonstration:
import datetime # ... class Poll(models.Model): # ... def was_published_today(self): return self.pub_date.date() == datetime.date.today()
Note the addition of import datetime to reference Pythons standard datetime module. Save these changes and start a new Python interactive shell by running python manage.py shell again:
>>> from mysite.polls.models import Poll, Choice # Make sure our __unicode__() addition worked. >>> Poll.objects.all() [<Poll: Whats up?>] # Django provides a rich database lookup API thats entirely driven by # keyword arguments. >>> Poll.objects.filter(id=1) [<Poll: Whats up?>] >>> Poll.objects.filter(question__startswith=What) [<Poll: Whats up?>] # Get the poll whose year is 2007. >>> Poll.objects.get(pub_date__year=2007) <Poll: Whats up?> >>> Poll.objects.get(id=2) Traceback (most recent call last): ... DoesNotExist: Poll matching query does not exist. # Lookup by a primary key is the most common case, so Django provides a # shortcut for primary-key exact lookups. # The following is identical to Poll.objects.get(id=1). >>> Poll.objects.get(pk=1) <Poll: Whats up?> # Make sure our custom method worked. >>> p = Poll.objects.get(pk=1) >>> p.was_published_today() False # Give the Poll a couple of Choices. The create call constructs a new # choice object, does the INSERT statement, adds the choice to the set # of available choices and returns the new Choice object. Django creates # a set to hold the "other side" of a ForeignKey relation # (e.g. a polls choices) which can be accessed via the API. >>> p = Poll.objects.get(pk=1) # Display any choices from the related object set -- none so far. >>> p.choice_set.all() [] # Create three choices.
21
>>> p.choice_set.create(choice=Not much, votes=0) <Choice: Not much> >>> p.choice_set.create(choice=The sky, votes=0) <Choice: The sky> >>> c = p.choice_set.create(choice=Just hacking again, votes=0) # Choice objects have API access to their related Poll objects. >>> c.poll <Poll: Whats up?> # And vice versa: Poll objects get access to Choice objects. >>> p.choice_set.all() [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>] >>> p.choice_set.count() 3 # The API automatically follows relationships as far as you need. # Use double underscores to separate relationships. # This works as many levels deep as you want; theres no limit. # Find all Choices for any poll whose pub_date is in 2007. >>> Choice.objects.filter(poll__pub_date__year=2007) [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>] # Lets delete one of the choices. Use delete() for that. >>> c = p.choice_set.filter(choice__startswith=Just hacking) >>> c.delete()
For more information on model relations, see Accessing related objects. For full details on the database API, see our Database API reference. When youre comfortable with the API, read part 2 of this tutorial to get Djangos automatic admin working.
22
CHAPTER
FOUR
23
# Uncomment the admin/doc line below and add django.contrib.admindocs # to INSTALLED_APPS to enable admin documentation: # (r^admin/doc/, include(django.contrib.admindocs.urls)), # Uncomment the next line to enable the admin: (r^admin/, include(admin.site.urls)), )
Now, open a Web browser and go to /admin/ on your local domain e.g., http://127.0.0.1:8000/admin/. You should see the admins login screen:
24
You should see a few other types of editable content, including groups, users and sites. These are core features Django ships with by default.
Youll need to restart the development server to see your changes. Normally, the server auto-reloads code every time you modify a le, but the action of creating a new le doesnt trigger the auto-reloading logic.
Click Polls. Now youre at the change list page for polls. This page displays all the polls in the database and lets you choose one to change it. Theres the Whats up? poll we created in the rst tutorial:
25
Things to note here: The form is automatically generated from the Poll model. The different model eld types (DateTimeField, CharField) correspond to the appropriate HTML input widget. Each type of eld knows how to display itself in the Django admin. Each DateTimeField gets free JavaScript shortcuts. Dates get a Today shortcut and calendar popup, and times get a Now shortcut and a convenient popup that lists commonly entered times. The bottom part of the page gives you a couple of options: Save Saves changes and returns to the change-list page for this type of object. Save and continue editing Saves changes and reloads the admin page for this object. Save and add another Saves changes and loads a new, blank form for this type of object. Delete Displays a delete conrmation page. Change the Date published by clicking the Today and Now shortcuts. Then click Save and continue editing. Then click History in the upper right. Youll see a page listing all changes made to this object via the Django admin, with the timestamp and username of the person who made the change:
26
Youll follow this pattern create a model admin object, then pass it as the second argument to admin.site.register() any time you need to change the admin options for an object. This particular change above makes the Publication date come before the Question eld:
This isnt impressive with only two elds, but for admin forms with dozens of elds, choosing an intuitive order is an important usability detail. And speaking of forms with dozens of elds, you might want to split the form up into eldsets:
class PollAdmin(admin.ModelAdmin): fieldsets = [ (None, {fields: [question]}), (Date information, {fields: [pub_date]}), ] admin.site.register(Poll, PollAdmin)
The rst element of each tuple in fieldsets is the title of the eldset. Heres what our form looks like now:
27
You can assign arbitrary HTML classes to each eldset. Django provides a "collapse" class that displays a particular eldset initially collapsed. This is useful when you have a long form that contains a number of elds that arent commonly used:
class PollAdmin(admin.ModelAdmin): fieldsets = [ (None, {fields: [question]}), (Date information, {fields: [pub_date], classes: [collapse]}), ]
28
Now Choices is an available option in the Django admin. The Add choice form looks like this:
In that form, the Poll eld is a select box containing every poll in the database. Django knows that a ForeignKey should be represented in the admin as a <select> box. In our case, only one poll exists at this point. Also note the Add Another link next to Poll. Every object with a ForeignKey relationship to another gets this for free. When you click Add Another, youll get a popup window with the Add poll form. If you add a poll in that window and click Save, Django will save the poll to the database and dynamically add it as the selected choice on the Add choice form youre looking at. But, really, this is an inefcient way of adding Choice objects to the system. Itd be better if you could add a bunch of Choices directly when you create the Poll object. Lets make that happen. Remove the register() call for the Choice model. Then, edit the Poll registration code to read:
class ChoiceInline(admin.StackedInline): model = Choice extra = 3 class PollAdmin(admin.ModelAdmin): fieldsets = [ (None, {fields: [question]}), (Date information, {fields: [pub_date], classes: [collapse]}), ] inlines = [ChoiceInline] admin.site.register(Poll, PollAdmin)
This tells Django: Choice objects are edited on the Poll admin page. By default, provide enough elds for 3 choices.
29
It works like this: There are three slots for related Choices as specied by extra and each time you come back to the Change page for an already-created object, you get another three extra slots. One small problem, though. It takes a lot of screen space to display all the elds for entering related Choice objects. For that reason, Django offers a tabular way of displaying inline related objects; you just need to change the ChoiceInline declaration to read:
class ChoiceInline(admin.TabularInline): #...
With that TabularInline (instead of StackedInline), the related objects are displayed in a more compact, table-based format:
30
By default, Django displays the str() of each object. But sometimes itd be more helpful if we could display individual elds. To do that, use the list_display admin option, which is a tuple of eld names to display, as columns, on the change list page for the object:
class PollAdmin(admin.ModelAdmin): # ... list_display = (question, pub_date)
Just for good measure, lets also include the was_published_today custom method from Tutorial 1:
31
You can click on the column headers to sort by those values except in the case of the was_published_today header, because sorting by the output of an arbitrary method is not supported. Also note that the column header for was_published_today is, by default, the name of the method (with underscores replaced with spaces). But you can change that by giving that method (in models.py) a short_description attribute:
def was_published_today(self): return self.pub_date.date() == datetime.date.today() was_published_today.short_description = Published today?
Lets add another improvement to the Poll change list page: Filters. Add the following line to PollAdmin:
list_filter = [pub_date]
That adds a Filter sidebar that lets people lter the change list by the pub_date eld:
The type of lter displayed depends on the type of eld youre ltering on. Because pub_date is a DateTimeField, Django knows to give the default lter options for DateTimeFields: Any date, Today, Past 7 days, This month, This year. This is shaping up well. Lets add some search capability:
search_fields = [question]
That adds a search box at the top of the change list. When somebody enters search terms, Django will search the question eld. You can use as many elds as youd like although because it uses a LIKE query behind the scenes, keep it reasonable, to keep your database happy. Finally, because Poll objects have dates, itd be convenient to be able to drill down by date. Add this line:
32
date_hierarchy = pub_date
That adds hierarchical navigation, by date, to the top of the change list page. At top level, it displays all available years. Then it drills down to months and, ultimately, days. Nows also a good time to note that change lists give you free pagination. The default is to display 50 items per page. Change-list pagination, search boxes, lters, date-hierarchies and column-header-ordering all work together like you think they should.
Now copy the template admin/base_site.html from within the default Django admin template directory in the source code of Django itself (django/contrib/admin/templates) into an admin subdirectory of whichever directory youre using in TEMPLATE_DIRS. For example, if your TEMPLATE_DIRS includes "/home/my_username/mytemplates", as above, then copy django/contrib/admin/templates/admin/base_site.html to /home/my_username/mytemplates/admin/base_site.html. Dont forget that admin subdirectory. Then, just edit the le and replace the generic Django text with your own sites name as you see t. This template le contains lots of text like {% block branding %} and {{ title }}. The {% and {{ tags are part of Djangos template language. When Django renders admin/base_site.html, this template language will be evaluated to produce the nal HTML page. Dont worry if you cant make any sense of the template right now well delve into Djangos templating language in Tutorial 3. Note that any of Djangos default admin templates can be overridden. To override a template, just do the same thing you did with base_site.html copy it from the default directory into your custom directory, and make changes. Astute readers will ask: But if TEMPLATE_DIRS was empty by default, how was Django nding the default admin templates? The answer is that, by default, Django automatically looks for a templates/ subdirectory within each app package, for use as a fallback. See the template loader documentation for full information.
33
The template to customize is admin/index.html. (Do the same as with admin/base_site.html in the previous section copy it from the default directory to your custom template directory.) Edit the le, and youll see it uses a template variable called app_list. That variable contains every installed Django app. Instead of using that, you can hard-code links to object-specic admin pages in whatever way you think is best. Again, dont worry if you cant understand the template language well cover that in more detail in Tutorial 3. When youre comfortable with the admin site, read part 3 of this tutorial to start working on public poll views.
34
CHAPTER
FIVE
5.1 Philosophy
A view is a type of Web page in your Django application that generally serves a specic function and has a specic template. For example, in a weblog application, you might have the following views: Blog homepage displays the latest few entries. Entry detail page permalink page for a single entry. Year-based archive page displays all months with entries in the given year. Month-based archive page displays all days with entries in the given month. Day-based archive page displays all entries in the given day. Comment action handles posting comments to a given entry. In our poll application, well have the following four views: Poll archive page displays the latest few polls. Poll detail page displays a poll question, with no results but with a form to vote. Poll results page displays results for a particular poll. Vote action handles voting for a particular choice in a particular poll. In Django, each view is represented by a simple Python function.
35
Django starts at the rst regular expression and makes its way down the list, comparing the requested URL against each regular expression until it nds one that matches. When it nds a match, Django calls the Python callback function, with an HttpRequest object as the rst argument, any captured values from the regular expression as keyword arguments, and, optionally, arbitrary keyword arguments from the dictionary (an optional third item in the tuple). For more on HttpRequest objects, see the Request and response objects. For more details on URLconfs, see the URL dispatcher. When you ran django-admin.py startproject mysite at the beginning of Tutorial 1, it created a default URLconf in mysite/urls.py. It also automatically set your ROOT_URLCONF setting (in settings.py) to point at that le:
ROOT_URLCONF = mysite.urls
This is worth a review. When somebody requests a page from your Web site say, /polls/23/, Django will load this Python module, because its pointed to by the ROOT_URLCONF setting. It nds the variable named urlpatterns and traverses the regular expressions in order. When it nds a regular expression that matches r^polls/(?P<poll_id>\d+)/$ it loads the function detail() from mysite/polls/views.py. Finally, it calls that detail() function like so:
detail(request=<HttpRequest object>, poll_id=23)
The poll_id=23 part comes from (?P<poll_id>\d+). Using parentheses around a pattern captures the text matched by that pattern and sends it as an argument to the view function; the ?P<poll_id> denes the name that will be used to identify the matched pattern; and \d+ is a regular expression to match a sequence of digits (i.e., a number). Because the URL patterns are regular expressions, there really is no limit on what you can do with them. And theres no need to add URL cruft such as .php unless you have a sick sense of humor, in which case you can do something like this:
(r^polls/latest\.php$, mysite.polls.views.index),
But, dont do that. Its silly. Note that these regular expressions do not search GET and POST parameters, or the domain name. For example, in a request to http://www.example.com/myapp/, the URLconf will look for myapp/. In a request to http://www.example.com/myapp/?page=3, the URLconf will look for myapp/. 36 Chapter 5. Writing your rst Django app, part 3
If you need help with regular expressions, see Wikipedias entry and the Python documentation. Also, the OReilly book Mastering Regular Expressions by Jeffrey Friedl is fantastic. Finally, a performance note: these regular expressions are compiled the rst time the URLconf module is loaded. Theyre super fast.
Now go to http://localhost:8000/polls/ on your domain in your Web browser. You should get a pleasantly-colored error page with the following message:
ViewDoesNotExist at /polls/ Tried index in module mysite.polls.views. Error was: module object has no attribute index
This error happened because you havent written a function index() in the module mysite/polls/views.py. Try /polls/23/, /polls/23/results/ and /polls/23/vote/. The error messages tell you which view Django tried (and failed to nd, because you havent written any views yet). Time to write the rst view. Open the le mysite/polls/views.py and put the following Python code in it:
from django.http import HttpResponse def index(request): return HttpResponse("Hello, world. Youre at the poll index.")
This is the simplest view possible. Go to /polls/ in your browser, and you should see your text. Now lets add a few more views. These views are slightly different, because they take an argument (which, remember, is passed in from whatever was captured by the regular expression in the URLconf):
def detail(request, poll_id): return HttpResponse("Youre looking at poll %s." % poll_id) def results(request, poll_id): return HttpResponse("Youre looking at the results of poll %s." % poll_id) def vote(request, poll_id): return HttpResponse("Youre voting on poll %s." % poll_id)
Take a look in your browser, at /polls/34/. Itll run the detail() method and display whatever ID you provide in the URL. Try /polls/34/results/ and /polls/34/vote/ too these will display the placeholder results and voting pages.
37
Theres a problem here, though: The pages design is hard-coded in the view. If you want to change the way the page looks, youll have to edit this Python code. So lets use Djangos template system to separate the design from Python:
from django.template import Context, loader from mysite.polls.models import Poll from django.http import HttpResponse def index(request): latest_poll_list = Poll.objects.all().order_by(-pub_date)[:5] t = loader.get_template(polls/index.html) c = Context({ latest_poll_list: latest_poll_list, }) return HttpResponse(t.render(c))
That code loads the template called polls/index.html and passes it a context. The context is a dictionary mapping template variable names to Python objects. Reload the page. Now youll see an error:
TemplateDoesNotExist at /polls/ polls/index.html
Ah. Theres no template yet. First, create a directory, somewhere on your lesystem, whose contents Django can access. (Django runs as whatever user your server runs.) Dont put them under your document root, though. You probably shouldnt make them public, just for securitys sake. Then edit TEMPLATE_DIRS in your settings.py to tell Django where it can nd templates just as you did in the Customize the admin look and feel section of Tutorial 2. When youve done that, create a directory polls in your template directory. Within that, create a le called index.html. Note that our loader.get_template(polls/index.html) code from above maps to [template_directory]/polls/index.html on the lesystem. Put the following code in that template:
38
{% if latest_poll_list %} <ul> {% for poll in latest_poll_list %} <li><a href="/polls/{{ poll.id }}/">{{ poll.question }}</a></li> {% endfor %} </ul> {% else %} <p>No polls are available.</p> {% endif %}
Load the page in your Web browser, and you should see a bulleted-list containing the Whats up poll from Tutorial 1. The link points to the polls detail page.
Note that once weve done this in all these views, we no longer need to import loader, Context and HttpResponse. The render_to_response() function takes a template name as its rst argument and a dictionary as its optional second argument. It returns an HttpResponse object of the given template rendered with the given context.
The new concept here: The view raises the Http404 exception if a poll with the requested ID doesnt exist. Well discuss what you could put in that polls/detail.html template a bit later, but if youd like to quickly get the above example working, just:
{{ poll }}
39
The get_object_or_404() function takes a Django model as its rst argument and an arbitrary number of keyword arguments, which it passes to the modules get() function. It raises Http404 if the object doesnt exist. Philosophy Why do we use a helper function get_object_or_404() instead of automatically catching the ObjectDoesNotExist exceptions at a higher level, or having the model API raise Http404 instead of ObjectDoesNotExist? Because that would couple the model layer to the view layer. One of the foremost design goals of Django is to maintain loose coupling. Theres also a get_list_or_404() function, which works just as get_object_or_404() except using filter() instead of get(). It raises Http404 if the list is empty.
That takes care of setting handler404 in the can see in django/conf/urls/defaults.py, django.views.defaults.page_not_found() by default. Four more things to note about 404 views:
is
As set
you to
If DEBUG is set to True (in your settings module) then your 404 view will never be used (and thus the 404.html template will never be rendered) because the traceback will be displayed instead. The 404 view is also called if Django doesnt nd a match after checking every regular expression in the URLconf. If you dont dene your own 404 view and simply use the default, which is recommended you still have one obligation: To create a 404.html template in the root of your template directory. The default 404 view will use that template for all 404 errors. If DEBUG is set to False (in your settings module) and if you didnt create a 404.html le, an Http500 is raised instead. So remember to create a 404.html.
40
The template system uses dot-lookup syntax to access variable attributes. In the example of {{ poll.question }}, rst Django does a dictionary lookup on the object poll. Failing that, it tries attribute lookup which works, in this case. If attribute lookup had failed, it wouldve tried calling the method question() on the poll object. Method-calling happens in the {% for %} loop: poll.choice_set.all is interpreted as the Python code poll.choice_set.all(), which returns an iterable of Choice objects and is suitable for use in the {% for %} tag. See the template guide for more about templates.
Namely, mysite.polls.views is in every callback. Because this is a common case, the URLconf framework provides a shortcut for common prexes. You can factor out the common prexes and add them as the rst argument to patterns(), like so:
urlpatterns = patterns(mysite.polls.views, (r^polls/$, index), (r^polls/(?P<poll_id>\d+)/$, detail), (r^polls/(?P<poll_id>\d+)/results/$, results), (r^polls/(?P<poll_id>\d+)/vote/$, vote), )
This is functionally identical to the previous formatting. Its just a bit tidier.
41
include(), simply, references another URLconf. Note that the regular expression doesnt have a $ (end-of-string match character) but has the trailing slash. Whenever Django encounters include(), it chops off whatever part of the URL matched up to that point and sends the remaining string to the included URLconf for further processing. Heres what happens if a user goes to /polls/34/ in this system: Django will nd the match at ^polls/ Then, Django will strip off the matching text ("polls/") and send the remaining text "34/" to the mysite.polls.urls URLconf for further processing. Now that weve decoupled that, we need to decouple the mysite.polls.urls URLconf by removing the leading polls/ from each line, and removing the lines registering the admin site:
urlpatterns = patterns(mysite.polls.views, (r^$, index), (r^(?P<poll_id>\d+)/$, detail), (r^(?P<poll_id>\d+)/results/$, results), (r^(?P<poll_id>\d+)/vote/$, vote), )
The idea behind include() and URLconf decoupling is to make it easy to plug-and-play URLs. Now that polls are in their own URLconf, they can be placed under /polls/, or under /fun_polls/, or under /content/polls/, or any other URL root, and the app will still work. All the poll app cares about is its relative URLs, not its absolute URLs. When youre comfortable with writing views, read part 4 of this tutorial to learn about simple form processing and generic views.
42
CHAPTER
SIX
A quick rundown: The above template displays a radio button for each poll choice. The value of each radio button is the associated poll choices ID. The name of each radio button is "choice". That means, when somebody selects one of the radio buttons and submits the form, itll send the POST data choice=3. This is HTML Forms 101. We set the forms action to /polls/{{ poll.id }}/vote/, and we set method="post". Using method="post" (as opposed to method="get") is very important, because the act of submitting this form will alter data server-side. Whenever you create a form that alters data server-side, use method="post". This tip isnt specic to Django; its just good Web development practice. forloop.counter indicates how many times the for tag has gone through its loop Since were creating a POST form (which can have the effect of modifying data), we need to worry about Cross Site Request Forgeries. Thankfully, you dont have to worry too hard, because Django comes with a very easyto-use system for protecting against it. In short, all POST forms that are targeted at internal URLs should use the {% csrf_token %} template tag.
43
The {% csrf_token %} tag requires information from the request object, which is not normally accessible from within the template context. To x this, a small adjustment needs to be made to the detail view, so that it looks like the following:
from django.template import RequestContext # ... def detail(request, poll_id): p = get_object_or_404(Poll, pk=poll_id) return render_to_response(polls/detail.html, {poll: p}, context_instance=RequestContext(request))
The details of how this works are explained in the documentation for RequestContext. Now, lets create a Django view that handles the submitted data and does something with it. Remember, in Tutorial 3, we created a URLconf for the polls application that includes this line:
(r^(?P<poll_id>\d+)/vote/$, vote),
We also created a dummy implementation of the vote() function. Lets create a real version. Add the following to mysite/polls/views.py:
from django.shortcuts import get_object_or_404, render_to_response from django.http import HttpResponseRedirect, HttpResponse from django.core.urlresolvers import reverse from django.template import RequestContext from mysite.polls.models import Choice, Poll # ... def vote(request, poll_id): p = get_object_or_404(Poll, pk=poll_id) try: selected_choice = p.choice_set.get(pk=request.POST[choice]) except (KeyError, Choice.DoesNotExist): # Redisplay the poll voting form. return render_to_response(polls/detail.html, { poll: p, error_message: "You didnt select a choice.", }, context_instance=RequestContext(request)) else: selected_choice.votes += 1 selected_choice.save() # Always return an HttpResponseRedirect after successfully dealing # with POST data. This prevents data from being posted twice if a # user hits the Back button. return HttpResponseRedirect(reverse(mysite.polls.views.results, args=(p.id,)))
This code includes a few things we havent covered yet in this tutorial: request.POST is a dictionary-like object that lets you access submitted data by key name. In this case, request.POST[choice] returns the ID of the selected choice, as a string. request.POST values are always strings. Note that Django also provides request.GET for accessing GET data in the same way but were explicitly using request.POST in our code, to ensure that data is only altered via a POST call. request.POST[choice] will raise KeyError if choice wasnt provided in POST data. The above code checks for KeyError and redisplays the poll form with an error message if choice isnt given.
44
After incrementing the choice count, the code returns an HttpResponseRedirect rather than a normal HttpResponse. HttpResponseRedirect takes a single argument: the URL to which the user will be redirected (see the following point for how we construct the URL in this case). As the Python comment above points out, you should always return an HttpResponseRedirect after successfully dealing with POST data. This tip isnt specic to Django; its just good Web development practice. We are using the reverse() function in the HttpResponseRedirect constructor in this example. This function helps avoid having to hardcode a URL in the view function. It is given the name of the view that we want to pass control to and the variable portion of the URL pattern that points to that view. In this case, using the URLconf we set up in Tutorial 3, this reverse() call will return a string like
/polls/3/results/
... where the 3 is the value of p.id. This redirected URL will then call the results view to display the nal page. Note that you need to use the full name of the view here (including the prex). As mentioned in Tutorial 3, request is a HttpRequest object. For more on HttpRequest objects, see the request and response documentation. After somebody votes in a poll, the vote() view redirects to the results page for the poll. Lets write that view:
def results(request, poll_id): p = get_object_or_404(Poll, pk=poll_id) return render_to_response(polls/results.html, {poll: p})
This is almost exactly the same as the detail() view from Tutorial 3. The only difference is the template name. Well x this redundancy later. Now, create a results.html template:
<h1>{{ poll.question }}</h1> <ul> {% for choice in poll.choice_set.all %} <li>{{ choice.choice }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li> {% endfor %} </ul> <a href="/polls/{{ poll.id }}/">Vote again?</a>
Now, go to /polls/1/ in your browser and vote in the poll. You should see a results page that gets updated each time you vote. If you submit the form without having chosen a choice, you should see the error message.
45
1. Convert the URLconf. 2. Rename a few templates. 3. Delete some of the old, unneeded views. 4. Fix up URL handling for the new views. Read on for details. Why the code-shufe? Generally, when writing a Django app, youll evaluate whether generic views are a good t for your problem, and youll use them from the beginning, rather than refactoring your code halfway through. But this tutorial intentionally has focused on writing the views the hard way until now, to focus on core concepts. You should know basic math before you start using a calculator. First, open the polls/urls.py URLconf. It looks like this, according to the tutorial so far:
from django.conf.urls.defaults import * urlpatterns = patterns(mysite.polls.views, (r^$, index), (r^(?P<poll_id>\d+)/$, detail), (r^(?P<poll_id>\d+)/results/$, results), (r^(?P<poll_id>\d+)/vote/$, vote), )
urlpatterns = patterns(, (r^$, django.views.generic.list_detail.object_list, info_dict), (r^(?P<object_id>\d+)/$, django.views.generic.list_detail.object_detail, info_dict), url(r^(?P<object_id>\d+)/results/$, django.views.generic.list_detail.object_detail, dict(info (r^(?P<poll_id>\d+)/vote/$, mysite.polls.views.vote), )
Were using two generic views here: object_list() and object_detail(). Respectively, those two views abstract the concepts of display a list of objects and display a detail page for a particular type of object. Each generic view needs to know what data it will be acting upon. This data is provided in a dictionary. The queryset key in this dictionary points to the list of objects to be manipulated by the generic view. The object_detail() generic view expects the ID value captured from the URL to be called "object_id", so weve changed poll_id to object_id for the generic views. Weve added a name, poll_results, to the results view so that we have a way to refer to its URL later on (see the documentation about naming URL patterns for information). Were also using the url() function from django.conf.urls.defaults here. Its a good habit to use url() when you are providing a pattern name like this. By default, the object_detail() generic view uses a template called <app name>/<model name>_detail.html. In our case, itll use the template "polls/poll_detail.html". Thus, rename your
46
polls/detail.html template to polls/poll_detail.html, and change the render_to_response() line in vote(). Similarly, the object_list() generic view uses a template called <app name>/<model name>_list.html. Thus, rename polls/index.html to polls/poll_list.html. Because we have more than one entry in the URLconf that uses object_detail() for the polls app, we manually specify a template name for the results view: template_name=polls/results.html. Otherwise, both views would use the same template. Note that we use dict() to return an altered dictionary in place. Note: django.db.models.QuerySet.all() is lazy It might look a little frightening to see Poll.objects.all() being used in a detail view which only needs one Poll object, but dont worry; Poll.objects.all() is actually a special object called a QuerySet, which is lazy and doesnt hit your database until it absolutely has to. By the time the database query happens, the object_detail() generic view will have narrowed its scope down to a single object, so the eventual query will only select one row from the database. If youd like to know more about how that works, The Django database API documentation explains the lazy nature of QuerySet objects. In previous parts of the tutorial, the templates have been provided with a context that contains the poll and latest_poll_list context variables. However, the generic views provide the variables object and object_list as context. Therefore, you need to change your templates to match the new context variables. Go through your templates, and modify any reference to latest_poll_list to object_list, and change any reference to poll to object. You can now delete the index(), detail() and results() views from polls/views.py. We dont need them anymore they have been replaced by generic views. The vote() view is still required. However, it must be modied to match the new context variables. In the render_to_response() call, rename the poll context variable to object. The last thing to do is x the URL handling to account for the use of generic views. In the vote view above, we used the reverse() function to avoid hard-coding our URLs. Now that weve switched to a generic view, well need to change the reverse() call to point back to our new generic view. We cant simply use the view function anymore generic views can be (and are) used multiple times but we can use the name weve given:
return HttpResponseRedirect(reverse(poll_results, args=(p.id,)))
Run the server, and use your new polling app based on generic views. For full details on generic views, see the generic views documentation.
48
CHAPTER
SEVEN
49
The guides and how-tos dont cover every single class, function, and method available in Django that would be overwhelming when youre trying to learn. Instead, details about individual classes, functions, methods, and modules are kept in the reference. This is where youll turn to nd the details of a particular function or whathaveyou. Finally, theres some specialized documentation not usually relevant to most developers. This includes the release notes, documentation of obsolete features, internals documentation for those who want to add code to Django itself, and a few other things that simply dont t elsewhere.
50
If youre using the development version of Django (aka the Subversion trunk), note that the docs/ directory contains all of the documentation. You can svn update it, just as you svn update the Python code, in order to get the latest changes. You can check out the latest Django documentation from Subversion using this shell command:
$ svn co http://code.djangoproject.com/svn/django/trunk/docs/ django_docs
One low-tech way of taking advantage of the text documentation is by using the Unix grep utility to search for a phrase in all of the documentation. For example, this will show you each mention of the phrase max_length in any Django document:
$ grep -r max_length /path/to/django/docs/
Then, just use the included Makefile to turn the documentation into HTML:
$ cd path/to/django/docs $ make html
Youll need GNU Make installed for this. The HTML documentation will be placed in docs/_build/html. Warning: At the time of this writing, Djangos using a version of Sphinx not yet released, so youll currently need to install Sphinx from the source. Well x this shortly.
Documentation for a particular Django release is frozen once the version has been released ofcially. It remains a snapshot of the docs as of the moment of the release. We will make exceptions to this rule in the case of retroactive security updates or other such retroactive changes. Once documentation is frozen, we add a note to the top of each frozen document that says These docs are frozen for Django version XXX and links to the current version of that document. The main documentation Web page includes links to documentation for all previous versions. See Also: If youre new to Python, you might want to start by getting an idea of what the language is like. Django is 100% Python, so if youve got minimal comfort with Python youll probably get a lot more out of Django. If youre new to programming entirely, you might want to start with this list of Python resources for non-programmers If you already know a few other languages and want to get up to speed with Python quickly, we recommend Dive Into Python (also available in a dead-tree version). If thats not quite your style, there are quite a few other books about Python.
52
Part II
Using Django
53
55
56
CHAPTER
EIGHT
(although SQLite doesnt require a separate server to be running). In addition to the ofcially supported databases, there are backends provided by 3rd parties that allow you to use other databases with Django: Sybase SQL Anywhere IBM DB2 Microsoft SQL Server 2005 Firebird ODBC The Django versions and ORM features supported by these unofcial backends vary considerably. Queries regarding the specic capabilities of these unofcial backends, along with any support queries, should be directed to the support channels provided by each 3rd party project. In addition to a database backend, youll need to make sure your Python database bindings are installed. If youre using PostgreSQL, youll need the psycopg package. Django supports both version 1 and 2. (When you congure Djangos database layer, specify either postgresql [for version 1] or postgresql_psycopg2 [for version 2].) If youre on Windows, check out the unofcial compiled Windows version. If youre using MySQL, youll need MySQLdb, version 1.2.1p2 or higher. You will also want to read the database-specic notes for the MySQL backend. If youre using SQLite and Python 2.4, youll need pysqlite. Use version 2.0.3 or higher. Python 2.5 ships with an SQLite wrapper in the standard library, so you dont need to install anything extra in that case. Please read the SQLite backend notes. If youre using Oracle, youll need a copy of cx_Oracle, but please read the database-specic notes for the Oracle backend for important information regarding supported versions of both Oracle and cx_Oracle. If youre using an unofcial 3rd party backend, please consult the documentation provided for any additional requirements. If you plan to use Djangos manage.py syncdb command to automatically create database tables for your models, youll need to ensure that Django has permission to create and alter tables in the database youre using; if you plan to manually create the tables, you can simply grant Django SELECT, INSERT, UPDATE and DELETE permissions. On some databases, Django will need ALTER TABLE privileges during syncdb but wont issue ALTER TABLE statements on a table once syncdb has created it. If youre using Djangos testing framework to test database queries, Django will need permission to create a test database.
58
The location of the site-packages directory depends on the operating system, and the location in which Python was installed. To nd out your systems site-packages location, execute the following:
python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"
(Note that this should be run from a shell prompt, not a Python interactive prompt.)
59
3. Next, make sure that the Python interpreter can load Djangos code. There are various ways of accomplishing this. One of the most convenient, on Linux, Mac OSX or other Unix-like systems, is to use a symbolic link:
ln -s pwd/django-trunk/django SITE-PACKAGES-DIR/django
(In the above line, change SITE-PACKAGES-DIR to match the location of your systems site-packages directory, as explained in the Where are my site-packages stored? section above.) Alternatively, you can dene your PYTHONPATH environment variable so that it includes the django-trunk directory. This is perhaps the most convenient solution on Windows systems, which dont support symbolic links. (Environment variables can be dened on Windows systems from the Control Panel.) What about Apache and mod_python? If you take the approach of setting PYTHONPATH, youll need to remember to do the same thing in your Apache conguration once you deploy your production site. Do this by setting PythonPath in your Apache conguration le. More information about deployment is available, of course, in our How to use Django with mod_python documentation. 4. On Unix-like systems, create a symbolic link to the le django-trunk/django/bin/django-admin.py in a directory on your system path, such as /usr/local/bin. For example:
ln -s pwd/django-trunk/django/bin/django-admin.py /usr/local/bin
This simply lets you type django-admin.py from within any directory, rather than having to qualify the command with the full path to the le. On Windows systems, the same result can be achieved by copying the le django-trunk/django/bin/django-admin.py to somewhere on your system path, for example C:\Python24\Scripts. You dont have to run python setup.py install, because youve already carried out the equivalent actions in steps 3 and 4. When you want to update your copy of the Django source code, just run the command svn update from within the django-trunk directory. When you do this, Subversion will automatically download any changes.
60
CHAPTER
NINE
9.1 Models
A model is the single, denitive source of data about your data. It contains the essential elds and behaviors of the data youre storing. Generally, each model maps to a single database table. The basics: Each model is a Python class that subclasses django.db.models.Model. Each attribute of the model represents a database eld. With all of this, Django gives you an automatically-generated database-access API; see Making queries. See Also: A companion to this document is the ofcial repository of model examples. (In the Django source distribution, these examples are in the tests/modeltests directory.)
first_name and last_name are elds of the model. Each eld is specied as a class attribute, and each attribute maps to a database column. The above Person model would create a database table like this:
CREATE TABLE myapp_person ( "id" serial NOT NULL PRIMARY KEY, "first_name" varchar(30) NOT NULL, "last_name" varchar(30) NOT NULL );
61
Some technical notes: The name of the table, myapp_person, is automatically derived from some model metadata but can be overridden. See Table names for more details.. An id eld is added automatically, but this behavior can be overridden. See Automatic primary key elds. The CREATE TABLE SQL in this example is formatted using PostgreSQL syntax, but its worth noting Django uses SQL tailored to the database backend specied in your settings le.
When you add new apps to INSTALLED_APPS, be sure to run manage.py syncdb.
9.1.3 Fields
The most important part of a model and the only required part of a model is the list of database elds it denes. Fields are specied by class attributes. Example:
class Musician(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) instrument = models.CharField(max_length=100) class Album(models.Model): artist = models.ForeignKey(Musician) name = models.CharField(max_length=100) release_date = models.DateField() num_stars = models.IntegerField()
Field types Each eld in your model should be an instance of the appropriate Field class. Django uses the eld class types to determine a few things: The database column type (e.g. INTEGER, VARCHAR). The widget to use in Djangos admin interface, if you care to use it (e.g. <input type="text">, <select>). The minimal validation requirements, used in Djangos admin and in automatically-generated forms.
62
Django ships with dozens of built-in eld types; you can nd the complete list in the model eld reference. You can easily write your own elds if Djangos built-in ones dont do the trick; see Writing custom model elds. Field options Each eld takes a certain set of eld-specic arguments (documented in the model eld reference). For example, CharField (and its subclasses) require a max_length argument which species the size of the VARCHAR database eld used to store the data. Theres also a set of common arguments available to all eld types. All are optional. Theyre fully explained in the reference, but heres a quick summary of the most often-used ones: null If True, Django will store empty values as NULL in the database. Default is False. blank If True, the eld is allowed to be blank. Default is False. Note that this is different than null. null is purely database-related, whereas blank is validation-related. If a eld has blank=True, validation on Djangos admin site will allow entry of an empty value. If a eld has blank=False, the eld will be required. choices An iterable (e.g., a list or tuple) of 2-tuples to use as choices for this eld. If this is given, Djangos admin will use a select box instead of the standard text eld and will limit choices to the choices given. A choices list looks like this:
YEAR_IN_SCHOOL_CHOICES = ( (uFR, uFreshman), (uSO, uSophomore), (uJR, uJunior), (uSR, uSenior), (uGR, uGraduate), )
The rst element in each tuple is the value that will be stored in the database, the second element will be displayed by the admin interface, or in a ModelChoiceField. Given an instance of a model object, the display value for a choices eld can be accessed using the get_FOO_display method. For example:
from django.db import models class Person(models.Model): GENDER_CHOICES = ( (uM, uMale), (uF, uFemale), ) name = models.CharField(max_length=60) gender = models.CharField(max_length=2, choices=GENDER_CHOICES) >>> p = Person(name="Fred Flinstone", gender="M") >>> p.save() >>> p.gender uM >>> p.get_gender_display() uMale
default The default value for the eld. This can be a value or a callable object. If callable it will be called every time a new object is created.
9.1. Models
63
help_text Extra help text to be displayed under the eld on the objects admin form. Its useful for documentation even if your object doesnt have an admin form. primary_key If True, this eld is the primary key for the model. If you dont specify primary_key=True for any elds in your model, Django will automatically add an IntegerField to hold the primary key, so you dont need to set primary_key=True on any of your elds unless you want to override the default primary-key behavior. For more, see Automatic primary key elds. unique If True, this eld must be unique throughout the table. Again, these are just short descriptions of the most common eld options. Full details can be found in the common model eld option reference. Automatic primary key elds By default, Django gives each model the following eld:
id = models.AutoField(primary_key=True)
This is an auto-incrementing primary key. If youd like to specify a custom primary key, just specify primary_key=True on one of your elds. If Django sees youve explicitly set Field.primary_key, it wont add the automatic id column. Each model requires exactly one eld to have primary_key=True. Verbose eld names Each eld type, except for ForeignKey, ManyToManyField and OneToOneField, takes an optional rst positional argument a verbose name. If the verbose name isnt given, Django will automatically create it using the elds attribute name, converting underscores to spaces. In this example, the verbose name is "Persons first name":
first_name = models.CharField("Persons first name", max_length=30)
ForeignKey, ManyToManyField and OneToOneField require the rst argument to be a model class, so use the verbose_name keyword argument:
poll = models.ForeignKey(Poll, verbose_name="the related poll") sites = models.ManyToManyField(Site, verbose_name="list of sites") place = models.OneToOneField(Place, verbose_name="related place")
The convention is not to capitalize the rst letter of the verbose_name. Django will automatically capitalize the rst letter where it needs to. Relationships Clearly, the power of relational databases lies in relating tables to each other. Django offers ways to dene the three most common types of database relationships: many-to-one, many-to-many and one-to-one.
64
Many-to-one relationships
To dene a many-to-one relationship, use ForeignKey. You use it just like any other Field type: by including it as a class attribute of your model. ForeignKey requires a positional argument: the class to which the model is related. For example, if a Car model has a Manufacturer that is, a Manufacturer makes multiple cars but each Car only has one Manufacturer use the following denitions:
class Manufacturer(models.Model): # ... class Car(models.Model): manufacturer = models.ForeignKey(Manufacturer) # ...
You can also create recursive relationships (an object with a many-to-one relationship to itself) and relationships to models not yet dened; see the model eld reference for details. Its suggested, but not required, that the name of a ForeignKey eld (manufacturer in the example above) be the name of the model, lowercase. You can, of course, call the eld whatever you want. For example:
class Car(models.Model): company_that_makes_it = models.ForeignKey(Manufacturer) # ...
See Also: See the Many-to-one relationship model example for a full example. ForeignKey elds also accept a number of extra arguments which are explained in the model eld reference. These options help dene how the relationship should work; all are optional.
Many-to-many relationships
To dene a many-to-many relationship, use ManyToManyField. You use it just like any other Field type: by including it as a class attribute of your model. ManyToManyField requires a positional argument: the class to which the model is related. For example, if a Pizza has multiple Topping objects that is, a Topping can be on multiple pizzas and each Pizza has multiple toppings heres how youd represent that:
class Topping(models.Model): # ... class Pizza(models.Model): # ... toppings = models.ManyToManyField(Topping)
As with ForeignKey, you can also create recursive relationships (an object with a many-to-one relationship to itself) and relationships to models not yet dened; see the model eld reference for details. Its suggested, but not required, that the name of a ManyToManyField (toppings in the example above) be a plural describing the set of related model objects. It doesnt matter which model gets the ManyToManyField, but you only need it in one of the models not in both.
9.1. Models
65
Generally, ManyToManyField instances should go in the object thats going to be edited in the admin interface, if youre using Djangos admin. In the above example, toppings is in Pizza (rather than Topping having a pizzas ManyToManyField ) because its more natural to think about a pizza having toppings than a topping being on multiple pizzas. The way its set up above, the Pizza admin form would let users select the toppings. See Also: See the Many-to-many relationship model example for a full example. ManyToManyField elds also accept a number of extra arguments which are explained in the model eld reference. These options help dene how the relationship should work; all are optional.
When you set up the intermediary model, you explicitly specify foreign keys to the models that are involved in the ManyToMany relation. This explicit declaration denes how the two models are related. There are a few restrictions on the intermediate model: Your intermediate model must contain one - and only one - foreign key to the target model (this would be Person in our example). If you have more than one foreign key, a validation error will be raised. Your intermediate model must contain one - and only one - foreign key to the source model (this would be Group in our example). If you have more than one foreign key, a validation error will be raised.
66
The only exception to this is a model which has a many-to-many relationship to itself, through an intermediary model. In this case, two foreign keys to the same model are permitted, but they will be treated as the two (different) sides of the many-to-many relation. When dening a many-to-many relationship from a model to itself, using an intermediary model, you must use symmetrical=False (see the model eld reference). Now that you have set up your ManyToManyField to use your intermediary model (Membership, in this case), youre ready to start creating some many-to-many relationships. You do this by creating instances of the intermediate model:
>>> ringo = Person.objects.create(name="Ringo Starr") >>> paul = Person.objects.create(name="Paul McCartney") >>> beatles = Group.objects.create(name="The Beatles") >>> m1 = Membership(person=ringo, group=beatles, ... date_joined=date(1962, 8, 16), ... invite_reason= "Needed a new drummer.") >>> m1.save() >>> beatles.members.all() [<Person: Ringo Starr>] >>> ringo.group_set.all() [<Group: The Beatles>] >>> m2 = Membership.objects.create(person=paul, group=beatles, ... date_joined=date(1960, 8, 1), ... invite_reason= "Wanted to form a band.") >>> beatles.members.all() [<Person: Ringo Starr>, <Person: Paul McCartney>]
Unlike normal many-to-many elds, you cant use add, create, or assignment (i.e., beatles.members = [...]) to create relationships:
# THIS WILL NOT WORK >>> beatles.members.add(john) # NEITHER WILL THIS >>> beatles.members.create(name="George Harrison") # AND NEITHER WILL THIS >>> beatles.members = [john, paul, ringo, george]
Why? You cant just create a relationship between a Person and a Group - you need to specify all the detail for the relationship required by the Membership model. The simple add, create and assignment calls dont provide a way to specify this extra detail. As a result, they are disabled for many-to-many relationships that use an intermediate model. The only way to create this type of relationship is to create instances of the intermediate model. The remove method is disabled for similar reasons. However, the clear() method can be used to remove all many-to-many relationships for an instance:
# Beatles have broken up >>> beatles.members.clear()
Once you have established the many-to-many relationships by creating instances of your intermediate model, you can issue queries. Just as with normal many-to-many relationships, you can query using the attributes of the many-tomany-related model:
# Find all the groups with a member whose name starts with Paul >>> Group.objects.filter(members__name__startswith=Paul) [<Group: The Beatles>]
As you are using an intermediate model, you can also query on its attributes: 9.1. Models 67
# Find all the members of the Beatles that joined after 1 Jan 1961 >>> Person.objects.filter( ... group__name=The Beatles, ... membership__date_joined__gt=date(1961,1,1)) [<Person: Ringo Starr]
One-to-one relationships
To dene a one-to-one relationship, use OneToOneField. You use it just like any other Field type: by including it as a class attribute of your model. This is most useful on the primary key of an object when that object extends another object in some way. OneToOneField requires a positional argument: the class to which the model is related. For example, if you were building a database of places, you would build pretty standard stuff such as address, phone number, etc. in the database. Then, if you wanted to build a database of restaurants on top of the places, instead of repeating yourself and replicating those elds in the Restaurant model, you could make Restaurant have a OneToOneField to Place (because a restaurant is a place; in fact, to handle this youd typically use inheritance, which involves an implicit one-to-one relation). As with ForeignKey, a recursive relationship can be dened and references to as-yet undened models can be made; see the model eld reference for details. See Also: See the One-to-one relationship model example for a full example. New in version 1.0: Please, see the release notes OneToOneField elds also accept one optional argument described in the model eld reference. OneToOneField classes used to automatically become the primary key on a model. This is no longer true (although you can manually pass in the primary_key argument if you like). Thus, its now possible to have multiple elds of type OneToOneField on a single model. Models across les Its perfectly OK to relate a model to one from another app. To do this, import the related model at the top of the model that holds your model. Then, just refer to the other model class wherever needed. For example:
from mysite.geography.models import ZipCode class Restaurant(models.Model): # ... zip_code = models.ForeignKey(ZipCode)
Field name restrictions Django places only two restrictions on model eld names: 1. A eld name cannot be a Python reserved word, because that would result in a Python syntax error. For example:
class Example(models.Model): pass = models.IntegerField() # pass is a reserved word!
68
2. A eld name cannot contain more than one underscore in a row, due to the way Djangos query lookup syntax works. For example:
class Example(models.Model): foo__bar = models.IntegerField() # foo__bar has two underscores!
These limitations can be worked around, though, because your eld name doesnt necessarily have to match your database column name. See the db_column option. SQL reserved words, such as join, where or select, are allowed as model eld names, because Django escapes all database table names and column names in every underlying SQL query. It uses the quoting syntax of your particular database engine. Custom eld types New in version 1.0: Please, see the release notes If one of the existing model elds cannot be used to t your purposes, or if you wish to take advantage of some less common database column types, you can create your own eld class. Full coverage of creating your own elds is provided in Writing custom model elds.
Model metadata is anything thats not a eld, such as ordering options (ordering), database table name (db_table), or human-readable singular and plural names (verbose_name and verbose_name_plural). None are required, and adding class Meta to a model is completely optional. A complete list of all possible Meta options can be found in the model option reference.
9.1. Models
69
def baby_boomer_status(self): "Returns the persons baby-boomer status." import datetime if datetime.date(1945, 8, 1) <= self.birth_date <= datetime.date(1964, 12, 31): return "Baby boomer" if self.birth_date < datetime.date(1945, 8, 1): return "Pre-boomer" return "Post-boomer" def is_midwestern(self): "Returns True if this person is from the Midwest." return self.state in (IL, WI, MI, IN, OH, IA, MO) def _get_full_name(self): "Returns the persons full name." return %s %s % (self.first_name, self.last_name) full_name = property(_get_full_name)
The last method in this example is a property. Read more about properties. The model instance reference has a complete list of methods automatically given to each model. You can override most of these see overriding predened model methods, below but there are a couple that youll almost always want to dene: __unicode__() A Python magic method that returns a unicode representation of any object. This is what Python and Django will use whenever a model instance needs to be coerced and displayed as a plain string. Most notably, this happens when you display an object in an interactive console or in the admin. Youll always want to dene this method; the default isnt very helpful at all. get_absolute_url() This tells Django how to calculate the URL for an object. Django uses this in its admin interface, and any time it needs to gure out a URL for an object. Any object that has a URL that uniquely identies it should dene this method. Overriding predened model methods Theres another set of model methods that encapsulate a bunch of database behavior that youll want to customize. In particular youll often want to change the way save() and delete() work. Youre free to override these methods (and any other model method) to alter behavior. A classic use-case for overriding the built-in methods is if you want something to happen whenever you save an object. For example (see save() for documentation of the parameters it accepts):
class Blog(models.Model): name = models.CharField(max_length=100) tagline = models.TextField() def save(self, *args, **kwargs): do_something() super(Blog, self).save(*args, **kwargs) # Call the "real" save() method. do_something_else()
70
tagline = models.TextField() def save(self, *args, **kwargs): if self.name == "Yoko Onos blog": return # Yoko shall never have her own blog! else: super(Blog, self).save(*args, **kwargs) # Call the "real" save() method.
Its important to remember to call the superclass method thats that super(Blog, self).save(*args, **kwargs) business to ensure that the object still gets saved into the database. If you forget to call the superclass method, the default behavior wont happen and the database wont get touched. Its also important that you pass through the arguments that can be passed to the model method thats what the *args, **kwargs bit does. Django will, from time to time, extend the capabilities of built-in model methods, adding new arguments. If you use *args, **kwargs in your method denitions, you are guaranteed that your code will automatically support those arguments when they are added. Executing custom SQL Another common pattern is writing custom SQL statements in model methods and module-level methods. For more details on using raw SQL, see the documentation on using raw SQL.
9.1. Models
71
The Student model will have three elds: name, age and home_group. The CommonInfo model cannot be used as a normal Django model, since it is an abstract base class. It does not generate a database table or have a manager, and cannot be instantiated or saved directly. For many uses, this type of model inheritance will be exactly what you want. It provides a way to factor out common information at the Python level, whilst still only creating one database table per child model at the database level.
Meta inheritance
When an abstract base class is created, Django makes any Meta inner class you declared in the base class available as an attribute. If a child class does not declare its own Meta class, it will inherit the parents Meta. If the child wants to extend the parents Meta class, it can subclass it. For example:
class CommonInfo(models.Model): ... class Meta: abstract = True ordering = [name] class Student(CommonInfo): ... class Meta(CommonInfo.Meta): db_table = student_info
Django does make one adjustment to the Meta class of an abstract base class: before installing the Meta attribute, it sets abstract=False. This means that children of abstract base classes dont automatically become abstract classes themselves. Of course, you can make an abstract base class that inherits from another abstract base class. You just need to remember to explicitly set abstract=True each time. Some attributes wont make sense to include in the Meta class of an abstract base class. For example, including db_table would mean that all the child classes (the ones that dont specify their own Meta) would use the same database table, which is almost certainly not what you want.
class Base(models.Model): m2m = models.ManyToManyField(OtherModel, related_name="%(app_label)s_%(class)s_related") class Meta: abstract = True class ChildA(Base): pass class ChildB(Base): pass
The reverse name of the commmon.ChildA.m2m eld will be common_childa_related, whilst the reverse name of the common.ChildB.m2m eld will be common_childb_related, and nally the reverse name of the rare.ChildB.m2m eld will be rare_childb_related. It is up to you how you use the %(class)s and %(app_label)s portion to construct your related name, but if you forget to use it, Django will raise errors when you validate your models (or run syncdb). If you dont specify a related_name attribute for a eld in an abstract base class, the default reverse name will be the name of the child class followed by _set, just as it normally would be if youd declared the eld directly on the child class. For example, in the above code, if the related_name attribute was omitted, the reverse name for the m2m eld would be childa_set in the ChildA case and childb_set for the ChildB eld. Multi-table inheritance The second type of model inheritance supported by Django is when each model in the hierarchy is a model all by itself. Each model corresponds to its own database table and can be queried and created individually. The inheritance relationship introduces links between the child model and each of its parents (via an automatically-created OneToOneField). For example:
class Place(models.Model): name = models.CharField(max_length=50) address = models.CharField(max_length=80) class Restaurant(Place): serves_hot_dogs = models.BooleanField() serves_pizza = models.BooleanField()
All of the elds of Place will also be available in Restaurant, although the data will reside in a different database table. So these are both possible:
>>> Place.objects.filter(name="Bobs Cafe") >>> Restaurant.objects.filter(name="Bobs Cafe")
If you have a Place that is also a Restaurant, you can get from the Place object to the Restaurant object by using the lower-case version of the model name:
9.1. Models
73
>>> p = Place.objects.get(id=12) # If p is a Restaurant object, this will give the child class: >>> p.restaurant <Restaurant: ...>
However, if p in the above example was not a Restaurant (it had been created directly as a Place object or was the parent of some other class), referring to p.restaurant would raise a Restaurant.DoesNotExist exception.
74
Proxy models New in version 1.1: Please, see the release notes When using multi-table inheritance, a new database table is created for each subclass of a model. This is usually the desired behavior, since the subclass needs a place to store any additional data elds that are not present on the base class. Sometimes, however, you only want to change the Python behavior of a model perhaps to change the default manager, or add a new method. This is what proxy model inheritance is for: creating a proxy for the original model. You can create, delete and update instances of the proxy model and all the data will be saved as if you were using the original (non-proxied) model. The difference is that you can change things like the default model ordering or the default manager in the proxy, without having to alter the original. Proxy models are declared like normal models. You tell Django that its a proxy model by setting the proxy attribute of the Meta class to True. For example, suppose you want to add a method to the standard User model that will be used in your templates. You can do it like this:
from django.contrib.auth.models import User class MyUser(User): class Meta: proxy = True def do_something(self): ...
The MyUser class operates on the same database table as its parent User class. In particular, any new instances of User will also be accessible through MyUser, and vice-versa:
>>> u = User.objects.create(username="foobar") >>> MyUser.objects.get(username="foobar") <MyUser: foobar>
You could also use a proxy model to dene a different default ordering on a model. The standard User model has no ordering dened on it (intentionally; sorting is expensive and we dont want to do it all the time when we fetch users). You might want to regularly order by the username attribute when you use the proxy. This is easy:
class OrderedUser(User): class Meta: ordering = ["username"] proxy = True
Now normal User queries will be unorderd and OrderedUser queries will be ordered by username.
9.1. Models
75
If you wanted to add a new manager to the Proxy, without replacing the existing default, you can use the techniques described in the custom manager documentation: create a base class containing the new managers and inherit that after the primary base class:
# Create an abstract class for the new manager. class ExtraManagers(models.Model): secondary = NewManager() class Meta: abstract = True class MyUser(User, ExtraManagers): class Meta: proxy = True
You probably wont need to do this very often, but, when you do, its possible.
76
The other difference that is more important for proxy models, is how model managers are handled. Proxy models are intended to behave exactly like the model they are proxying for. So they inherit the parent models managers, including the default manager. In the normal multi-table model inheritance case, children do not inherit managers from their parents as the custom managers arent always appropriate when extra elds are involved. The manager documentation has more details about this latter case. When these two features were implemented, attempts were made to squash them into a single option. It turned out that interactions with inheritance, in general, and managers, in particular, made the API very complicated and potentially difcult to understand and use. It turned out that two options were needed in any case, so the current separation arose. So, the general rules are: 1. If you are mirroring an existing model or database table and dont want all the original database table columns, use Meta.managed=False. That option is normally useful for modeling database views and tables not under the control of Django. 2. If you are wanting to change the Python-only behavior of a model, but keep all the same elds as in the original, use Meta.proxy=True. This sets things up so that the proxy model is an exact copy of the storage structure of the original model when data is saved. Multiple inheritance Just as with Pythons subclassing, its possible for a Django model to inherit from multiple parent models. Keep in mind that normal Python name resolution rules apply. The rst base class that a particular name (e.g. Meta) appears in will be the one that is used; for example, this means that if multiple parents contain a Meta class, only the rst one is going to be used, and all others will be ignored. Generally, you wont need to inherit from multiple parents. The main use-case where this is useful is for mix-in classes: adding a particular extra eld or method to every class that inherits the mix-in. Try to keep your inheritance hierarchies as simple and straightforward as possible so that you wont have to struggle to work out where a particular piece of information is coming from. Field name hiding is not permitted In normal Python class inheritance, it is permissible for a child class to override any attribute from the parent class. In Django, this is not permitted for attributes that are Field instances (at least, not at the moment). If a base class has a eld called author, you cannot create another model eld called author in any class that inherits from that base class. Overriding elds in a parent model leads to difculties in areas such as initialising new instances (specifying which eld is being intialised in Model.__init__) and serialization. These are features which normal Python class inheritance doesnt have to deal with in quite the same way, so the difference between Django model inheritance and Python class inheritance isnt merely arbitrary. This restriction only applies to attributes which are Field instances. Normal Python attributes can be overridden if you wish. It also only applies to the name of the attribute as Python sees it: if you are manually specifying the database column name, you can have the same column name appearing in both a child and an ancestor model for multi-table inheritance (they are columns in two different database tables). Django will raise a FieldError exception if you override any model eld in any ancestor model.
full details of all the various model lookup options. Throughout this guide (and in the reference), well refer to the following models, which comprise a weblog application:
class Blog(models.Model): name = models.CharField(max_length=100) tagline = models.TextField() def __unicode__(self): return self.name class Author(models.Model): name = models.CharField(max_length=50) email = models.EmailField() def __unicode__(self): return self.name class Entry(models.Model): blog = models.ForeignKey(Blog) headline = models.CharField(max_length=255) body_text = models.TextField() pub_date = models.DateTimeField() authors = models.ManyToManyField(Author) n_comments = models.IntegerField() n_pingbacks = models.IntegerField() rating = models.IntegerField() def __unicode__(self): return self.headline
This performs an INSERT SQL statement behind the scenes. Django doesnt hit the database until you explicitly call save(). The save() method has no return value. See Also: save() takes a number of advanced options not described here. See the documentation for save() for complete details. To create an object and save it all in one step see the create() method.
78
This performs an UPDATE SQL statement behind the scenes. Django doesnt hit the database until you explicitly call save(). Saving ForeignKey and ManyToManyField elds Updating ForeignKey elds works exactly the same way as saving a normal eld; simply assign an object of the right type to the eld in question:
>>> cheese_blog = Blog.objects.get(name="Cheddar Talk") >>> entry.blog = cheese_blog >>> entry.save()
Updating a ManyToManyField works a little differently; use the add() method on the eld to add a record to the relation:
>> joe = Author.objects.create(name="Joe") >> entry.authors.add(joe)
Django will complain if you try to assign or add an object of the wrong type.
Note: Managers are accessible only via model classes, rather than from model instances, to enforce a separation between table-level operations and record-level operations. The Manager is the main source of QuerySets for a model. It acts as a root QuerySet that describes all objects in the models database table. For example, Blog.objects is the initial QuerySet that contains all Blog objects in the database.
79
Retrieving all objects The simplest way to retrieve objects from a table is to get all of them. To do this, use the all() method on a Manager:
>>> all_entries = Entry.objects.all()
The all() method returns a QuerySet of all the objects in the database. (If Entry.objects is a QuerySet, why cant we just do Entry.objects? Thats because Entry.objects, the root QuerySet, is a special case that cannot be evaluated. The all() method returns a QuerySet that can be evaluated.) Retrieving specic objects with lters The root QuerySet provided by the Manager describes all objects in the database table. Usually, though, youll need to select only a subset of the complete set of objects. To create such a subset, you rene the initial QuerySet, adding lter conditions. The two most common ways to rene a QuerySet are: filter(**kwargs) Returns a new QuerySet containing objects that match the given lookup parameters. exclude(**kwargs) Returns a new QuerySet containing objects that do not match the given lookup parameters. The lookup parameters (**kwargs in the above function denitions) should be in the format described in Field lookups below. For example, to get a QuerySet of blog entries from the year 2006, use filter() like so:
Entry.objects.filter(pub_date__year=2006)
We dont have to add an all() Entry.objects.all().filter(...). That would still work, but you only need all() when you want all objects from the root QuerySet.
Chaining lters
The result of rening a QuerySet is itself a QuerySet, so its possible to chain renements together. For example:
>>> ... ... ... ... ... ... Entry.objects.filter( headline__startswith=What ).exclude( pub_date__gte=datetime.now() ).filter( pub_date__gte=datetime(2005, 1, 1) )
This takes the initial QuerySet of all entries in the database, adds a lter, then an exclusion, then another lter. The nal result is a QuerySet containing all entries with a headline that starts with What, that were published between January 1, 2005, and the current day.
80
These three QuerySets are separate. The rst is a base QuerySet containing all entries that contain a headline starting with What. The second is a subset of the rst, with an additional criteria that excludes records whose pub_date is greater than now. The third is a subset of the rst, with an additional criteria that selects only the records whose pub_date is greater than now. The initial QuerySet (q1) is unaffected by the renement process.
Though this looks like three database hits, in fact it hits the database only once, at the last line (print q). In general, the results of a QuerySet arent fetched from the database until you ask for them. When you do, the QuerySet is evaluated by accessing the database. For more details on exactly when evaluation takes place, see When QuerySets are evaluated.
This returns the sixth through tenth objects (OFFSET 5 LIMIT 5):
>>> Entry.objects.all()[5:10]
81
Negative indexing (i.e. Entry.objects.all()[-1]) is not supported. Generally, slicing a QuerySet returns a new QuerySet it doesnt evaluate the query. An exception is if you use the step parameter of Python slice syntax. For example, this would actually execute the query in order to return a list of every second object of the rst 10:
>>> Entry.objects.all()[:10:2]
To retrieve a single object rather than a list (e.g. SELECT foo FROM bar LIMIT 1), use a simple index instead of a slice. For example, this returns the rst Entry in the database, after ordering entries alphabetically by headline:
>>> Entry.objects.order_by(headline)[0]
Note, however, that the rst of these will raise IndexError while the second will raise DoesNotExist if no objects match the given criteria. See get() for more details. Field lookups Field lookups are how you specify the meat of an SQL WHERE clause. Theyre specied as keyword arguments to the QuerySet methods filter(), exclude() and get(). Basic lookups keyword arguments take the form field__lookuptype=value. (Thats a double-underscore). For example:
>>> Entry.objects.filter(pub_date__lte=2006-01-01)
How this is possible Python has the ability to dene functions that accept arbitrary name-value arguments whose names and values are evaluated at runtime. For more information, see Keyword Arguments in the ofcial Python tutorial. If you pass an invalid keyword argument, a lookup function will raise TypeError. The database API supports about two dozen lookup types; a complete reference can be found in the eld lookup reference. To give you a taste of whats available, heres some of the more common lookups youll probably use: exact An exact match. For example:
>>> Entry.objects.get(headline__exact="Man bites dog")
If you dont provide a lookup type that is, if your keyword argument doesnt contain a double underscore the lookup type is assumed to be exact. For example, the following two statements are equivalent:
82
This is for convenience, because exact lookups are the common case. iexact A case-insensitive match. So, the query:
>>> Blog.objects.get(name__iexact="beatles blog")
Would match a Blog titled Beatles Blog, beatles blog, or even BeAtlES blOG. contains Case-sensitive containment test. For example:
Entry.objects.get(headline__contains=Lennon)
Note this will match the headline Today Lennon honored but not today lennon honored. Theres also a case-insensitive version, icontains. startswith, endswith Starts-with and ends-with search, respectively. There are also case-insensitive versions called istartswith and iendswith. Again, this only scratches the surface. A complete reference can be found in the eld lookup reference. Lookups that span relationships Django offers a powerful and intuitive way to follow relationships in lookups, taking care of the SQL JOINs for you automatically, behind the scenes. To span a relationship, just use the eld name of related elds across models, separated by double underscores, until you get to the eld you want. This example retrieves all Entry objects with a Blog whose name is Beatles Blog:
>>> Entry.objects.filter(blog__name__exact=Beatles Blog)
This spanning can be as deep as youd like. It works backwards, too. To refer to a reverse relationship, just use the lowercase name of the model. This example retrieves all Blog objects which have at least one Entry whose headline contains Lennon:
>>> Blog.objects.filter(entry__headline__contains=Lennon)
If you are ltering across multiple relationships and one of the intermediate models doesnt have a value that meets the lter condition, Django will treat it as if there is an empty (all values are NULL), but valid, object there. All this means is that no error will be raised. For example, in this lter:
Blog.objects.filter(entry__authors__name=Lennon)
(if there was a related Author model), if there was no author associated with an entry, it would be treated as if there was also no name attached, rather than raising an error because of the missing author. Usually this is exactly what you want to have happen. The only case where it might be confusing is if you are using isnull. Thus:
83
Blog.objects.filter(entry__authors__name__isnull=True)
will return Blog objects that have an empty name on the author and also those which have an empty author on the entry. If you dont want those latter objects, you could write:
Blog.objects.filter(entry__authors__isnull=False, entry__authors__name__isnull=True)
To select all blogs that contain an entry with Lennon in the headline as well as an entry that was published in 2008, we would write:
Blog.objects.filter(entry__headline__contains=Lennon).filter( entry__pub_date__year=2008)
In this second example, the rst lter restricted the queryset to all those blogs linked to that particular type of entry. The second lter restricted the set of blogs further to those that are also linked to the second type of entry. The entries select by the second lter may or may not be the same as the entries in the rst lter. We are ltering the Blog items with each lter statement, not the Entry items. All of this behavior also applies to exclude(): all the conditions in a single exclude() statement apply to a single instance (if those conditions are talking about the same multi-valued relation). Conditions in subsequent filter() or exclude() calls that refer to the same relation may end up ltering on different linked objects. Filters can reference elds on the model New in version 1.1: Please, see the release notes In the examples given so far, we have constructed lters that compare the value of a model eld with a constant. But what if you want to compare the value of a model eld with another eld on the same model?
84
Django provides the F() object to allow such comparisons. Instances of F() act as a reference to a model eld within a query. These references can then be used in query lters to compare the values of two different elds on the same model instance. For example, to nd a list of all blog entries that have had more comments than pingbacks, we construct an F() object to reference the comment count, and use that F() object in the query:
>>> from django.db.models import F >>> Entry.objects.filter(n_comments__gt=F(n_pingbacks))
Django supports the use of addition, subtraction, multiplication, division and modulo arithmetic with F() objects, both with constants and with other F() objects. To nd all the blog entries with more than twice as many comments as pingbacks, we modify the query:
>>> Entry.objects.filter(n_comments__gt=F(n_pingbacks) * 2)
To nd all the entries where the rating of the entry is less than the sum of the pingback count and comment count, we would issue the query:
>>> Entry.objects.filter(rating__lt=F(n_comments) + F(n_pingbacks))
You can also use the double underscore notation to span relationships in an F() object. An F() object with a double underscore will introduce any joins needed to access the related object. For example, to retrieve all the entries where the authors name is the same as the blog name, we could issue the query:
>>> Entry.objects.filter(authors__name=F(blog__name))
The pk lookup shortcut For convenience, Django provides a pk lookup shortcut, which stands for primary key. In the example Blog model, the primary key is the id eld, so these three statements are equivalent:
>>> Blog.objects.get(id__exact=14) # Explicit form >>> Blog.objects.get(id=14) # __exact is implied >>> Blog.objects.get(pk=14) # pk implies id__exact
The use of pk isnt limited to __exact queries any query term can be combined with pk to perform a query on the primary key of a model:
# Get blogs entries with id 1, 4 and 7 >>> Blog.objects.filter(pk__in=[1,4,7]) # Get all blog entries with id > 14 >>> Blog.objects.filter(pk__gt=14)
pk lookups also work across joins. For example, these three statements are equivalent:
>>> Entry.objects.filter(blog__id__exact=3) # Explicit form >>> Entry.objects.filter(blog__id=3) # __exact is implied >>> Entry.objects.filter(blog__pk=3) # __pk implies __id__exact
85
Escaping percent signs and underscores in LIKE statements The eld lookups that equate to LIKE SQL statements (iexact, contains, icontains, startswith, istartswith, endswith and iendswith) will automatically escape the two special characters used in LIKE statements the percent sign and the underscore. (In a LIKE statement, the percent sign signies a multiple-character wildcard and the underscore signies a single-character wildcard.) This means things should work intuitively, so the abstraction doesnt leak. For example, to retrieve all the entries that contain a percent sign, just use the percent sign as any other character:
>>> Entry.objects.filter(headline__contains=%)
Django takes care of the quoting for you; the resulting SQL will look something like this:
SELECT ... WHERE headline LIKE %\%%;
Same goes for underscores. Both percentage signs and underscores are handled for you transparently. Caching and QuerySets Each QuerySet contains a cache, to minimize database access. Its important to understand how it works, in order to write the most efcient code. In a newly created QuerySet, the cache is empty. The rst time a QuerySet is evaluated and, hence, a database query happens Django saves the query results in the QuerySets cache and returns the results that have been explicitly requested (e.g., the next element, if the QuerySet is being iterated over). Subsequent evaluations of the QuerySet reuse the cached results. Keep this caching behavior in mind, because it may bite you if you dont use your QuerySets correctly. For example, the following will create two QuerySets, evaluate them, and throw them away:
>>> print [e.headline for e in Entry.objects.all()] >>> print [e.pub_date for e in Entry.objects.all()]
That means the same database query will be executed twice, effectively doubling your database load. Also, theres a possibility the two lists may not include the same database records, because an Entry may have been added or deleted in the split second between the two requests. To avoid this problem, simply save the QuerySet and reuse it:
>>> queryset = Entry.objects.all() >>> print [p.headline for p in queryset] # Evaluate the query set. >>> print [p.pub_date for p in queryset] # Re-use the cache from the evaluation.
86
Q objects can be combined using the & and | operators. When an operator is used on two Q objects, it yields a new Q object. For example, this statement yields a single Q object that represents the OR of two "question__startswith" queries:
Q(question__startswith=Who) | Q(question__startswith=What)
You can compose statements of arbitrary complexity by combining Q objects with the & and | operators and use parenthetical grouping. Also, Q objects can be negated using the ~ operator, allowing for combined lookups that combine both a normal query and a negated (NOT) query:
Q(question__startswith=Who) | ~Q(pub_date__year=2005)
Each lookup function that takes keyword-arguments (e.g. filter(), exclude(), get()) can also be passed one or more Q objects as positional (not-named) arguments. If you provide multiple Q object arguments to a lookup function, the arguments will be ANDed together. For example:
Poll.objects.get( Q(question__startswith=Who), Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)) )
Lookup functions can mix the use of Q objects and keyword arguments. All arguments provided to a lookup function (be they keyword arguments or Q objects) are ANDed together. However, if a Q object is provided, it must precede the denition of any keyword arguments. For example:
Poll.objects.get( Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)), question__startswith=Who)
... would not be valid. See Also: The OR lookups examples in the Django unit tests show some possible uses of Q.
87
If a models primary key isnt called id, no problem. Comparisons will always use the primary key, whatever its called. For example, if a models primary key eld is called name, these two statements are equivalent:
>>> some_obj == other_obj >>> some_obj.name == other_obj.name
You can also delete objects in bulk. Every QuerySet has a delete() method, which deletes all members of that QuerySet. For example, this deletes all Entry objects with a pub_date year of 2005:
Entry.objects.filter(pub_date__year=2005).delete()
Keep in mind that this will, whenever possible, be executed purely in SQL, and so the delete() methods of individual object instances will not necessarily be called during the process. If youve provided a custom delete() method on a model class and want to ensure that it is called, you will need to manually delete instances of that model (e.g., by iterating over a QuerySet and calling delete() on each object individually) rather than using the bulk delete() method of a QuerySet. When Django deletes an object, it emulates the behavior of the SQL constraint ON DELETE CASCADE in other words, any objects which had foreign keys pointing at the object to be deleted will be deleted along with it. For example:
b = Blog.objects.get(pk=1) # This will delete the Blog and all of its Entry objects. b.delete()
Note that delete() is the only QuerySet method that is not exposed on a Manager itself. This is a safety mechanism to prevent you from accidentally requesting Entry.objects.delete(), and deleting all the entries. If you do want to delete all the objects, then you have to explicitly request a complete query set:
Entry.objects.all().delete()
88
You can only set non-relation elds and ForeignKey elds using this method. To update a non-relation eld, provide the new value as a constant. To update ForeignKey elds, set the new value to be the new model instance you want to point to. For example:
>>> b = Blog.objects.get(pk=1) # Change every Entry so that it belongs to this Blog. >>> Entry.objects.all().update(blog=b)
The update() method is applied instantly and returns the number of rows affected by the query. The only restriction on the QuerySet that is updated is that it can only access one database table, the models main table. You can lter based on related elds, but you can only update columns in the models main table. Example:
>>> b = Blog.objects.get(pk=1) # Update all the headlines belonging to this Blog. >>> Entry.objects.select_related().filter(blog=b).update(headline=Everything is the same)
Be aware that the update() method is converted directly to an SQL statement. It is a bulk operation for direct updates. It doesnt run any save() methods on your models, or emit the pre_save or post_save signals (which are a consequence of calling save()). If you want to save every item in a QuerySet and make sure that the save() method is called on each instance, you dont need any special function to handle that. Just loop over them and call save():
for item in my_queryset: item.save()
New in version 1.1: Please, see the release notes Calls to update can also use F() objects to update one eld based on the value of another eld in the model. This is especially useful for incrementing counters based upon their current value. For example, to increment the pingback count for every entry in the blog:
>>> Entry.objects.all().update(n_pingbacks=F(n_pingbacks) + 1)
However, unlike F() objects in lter and exclude clauses, you cant introduce joins when you use F() objects in an update you can only reference elds local to the model being updated. If you attempt to introduce a join with an F() object, a FieldError will be raised:
# THIS WILL RAISE A FieldError >>> Entry.objects.update(headline=F(blog__name))
89
Using the models at the top of this page, for example, an Entry object e can get its associated Blog object by accessing the blog attribute: e.blog. (Behind the scenes, this functionality is implemented by Python descriptors. This shouldnt really matter to you, but we point it out here for the curious.) Django also creates API accessors for the other side of the relationship the link from the related model to the model that denes the relationship. For example, a Blog object b has access to a list of all related Entry objects via the entry_set attribute: b.entry_set.all(). All examples in this section use the sample Blog, Author and Entry models dened at the top of this page. One-to-many relationships
Forward
If a model has a ForeignKey, instances of that model will have access to the related (foreign) object via a simple attribute of the model. Example:
>>> e = Entry.objects.get(id=2) >>> e.blog # Returns the related Blog object.
You can get and set via a foreign-key attribute. As you may expect, changes to the foreign key arent saved to the database until you call save(). Example:
>>> e = Entry.objects.get(id=2) >>> e.blog = some_blog >>> e.save()
If a ForeignKey eld has null=True set (i.e., it allows NULL values), you can assign None to it. Example:
>>> e = Entry.objects.get(id=2) >>> e.blog = None >>> e.save() # "UPDATE blog_entry SET blog_id = NULL ...;"
Forward access to one-to-many relationships is cached the rst time the related object is accessed. Subsequent accesses to the foreign key on the same object instance are cached. Example:
>>> e = Entry.objects.get(id=2) >>> print e.blog # Hits the database to retrieve the associated Blog. >>> print e.blog # Doesnt hit the database; uses cached version.
Note that the select_related() QuerySet method recursively prepopulates the cache of all one-to-many relationships ahead of time. Example:
>>> e = Entry.objects.select_related().get(id=2) >>> print e.blog # Doesnt hit the database; uses cached version. >>> print e.blog # Doesnt hit the database; uses cached version.
90
You can override the FOO_set name by setting the related_name parameter in the ForeignKey() denition. For example, if the Entry model was altered to blog = ForeignKey(Blog, related_name=entries), the above example code would look like this:
>>> b = Blog.objects.get(id=1) >>> b.entries.all() # Returns all Entry objects related to Blog. # b.entries is a Manager that returns QuerySets. >>> b.entries.filter(headline__contains=Lennon) >>> b.entries.count()
You cannot access a reverse ForeignKey Manager from the class; it must be accessed from an instance:
>>> Blog.entry_set Traceback: ... AttributeError: "Manager must be accessed via instance".
In addition to the QuerySet methods dened in Retrieving objects above, the ForeignKey Manager has additional methods used to handle the set of related objects. A synopsis of each is below, and complete details can be found in the related objects reference. add(obj1, obj2, ...) Adds the specied model objects to the related object set. create(**kwargs) Creates a new object, saves it and puts it in the related object set. Returns the newly created object. remove(obj1, obj2, ...) Removes the specied model objects from the related object set. clear() Removes all objects from the related object set. To assign the members of a related set in one fell swoop, just assign to it from any iterable object. The iterable can contain object instances, or just a list of primary key values. For example:
b = Blog.objects.get(id=1) b.entry_set = [e1, e2]
In this example, e1 and e2 can be full Entry instances, or integer primary key values. If the clear() method is available, any pre-existing objects will be removed from the entry_set before all objects in the iterable (in this case, a list) are added to the set. If the clear() method is not available, all objects in the iterable will be added without removing any existing elements.
91
Each reverse operation described in this section has an immediate effect on the database. Every addition, creation and deletion is immediately and automatically saved to the database. Many-to-many relationships Both ends of a many-to-many relationship get automatic API access to the other end. The API works just as a backward one-to-many relationship, above. The only difference is in the attribute naming: The model that denes the ManyToManyField uses the attribute name of that eld itself, whereas the reverse model uses the lowercased model name of the original model, plus _set (just like reverse one-to-many relationships). An example makes this easier to understand:
e = Entry.objects.get(id=3) e.authors.all() # Returns all Author objects for this Entry. e.authors.count() e.authors.filter(name__contains=John) a = Author.objects.get(id=5) a.entry_set.all() # Returns all Entry objects for this Author.
Like ForeignKey, ManyToManyField can specify related_name. In the above example, if the ManyToManyField in Entry had specied related_name=entries, then each Author instance would have an entries attribute instead of entry_set. One-to-one relationships One-to-one relationships are very similar to many-to-one relationships. If you dene a OneToOneField on your model, instances of that model will have access to the related object via a simple attribute of the model. For example:
class EntryDetail(models.Model): entry = models.OneToOneField(Entry) details = models.TextField() ed = EntryDetail.objects.get(id=2) ed.entry # Returns the related Entry object.
The difference comes in reverse queries. The related model in a one-to-one relationship also has access to a Manager object, but that Manager represents a single object, rather than a collection of objects:
e = Entry.objects.get(id=2) e.entrydetail # returns the related EntryDetail object
If no object has been assigned to this relationship, Django will raise a DoesNotExist exception. Instances can be assigned to the reverse relationship in the same way as you would assign the forward relationship:
e.entrydetail = ed
92
How are the backward relationships possible? Other object-relational mappers require you to dene relationships on both sides. The Django developers believe this is a violation of the DRY (Dont Repeat Yourself) principle, so Django only requires you to dene the relationship on one end. But how is this possible, given that a model class doesnt know which other model classes are related to it until those other model classes are loaded? The answer lies in the INSTALLED_APPS setting. The rst time any model is loaded, Django iterates over every model in INSTALLED_APPS and creates the backward relationships in memory as needed. Essentially, one of the functions of INSTALLED_APPS is to tell Django the entire model domain. Queries over related objects Queries involving related objects follow the same rules as queries involving normal value elds. When specifying the value for a query to match, you may use either an object instance itself, or the primary key value for the object. For example, if you have a Blog object b with id=5, the following three queries would be identical:
Entry.objects.filter(blog=b) # Query using object instance Entry.objects.filter(blog=b.id) # Query using id from instance Entry.objects.filter(blog=5) # Query using id directly
9.3 Aggregation
New in version 1.1: Please, see the release notes The topic guide on Djangos database-abstraction API described the way that you can use Django queries that create, retrieve, update and delete individual objects. However, sometimes you will need to retrieve values that are derived by summarizing or aggregating a collection of objects. This topic guide describes the ways that aggregate values can be generated and returned using Django queries. Throughout this guide, well refer to the following models. These models are used to track the inventory for a series of online bookstores:
class Author(models.Model): name = models.CharField(max_length=100) age = models.IntegerField() friends = models.ManyToManyField(self, blank=True) class Publisher(models.Model): name = models.CharField(max_length=300) num_awards = models.IntegerField()
9.3. Aggregation
93
class Book(models.Model): isbn = models.CharField(max_length=9) name = models.CharField(max_length=300) pages = models.IntegerField() price = models.DecimalField(max_digits=10, decimal_places=2) rating = models.FloatField() authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) pubdate = models.DateField() class Store(models.Model): name = models.CharField(max_length=300) books = models.ManyToManyField(Book)
What we need is a way to calculate summary values over the objects that belong to this QuerySet. This is done by appending an aggregate() clause onto the QuerySet:
>>> from django.db.models import Avg >>> Book.objects.all().aggregate(Avg(price)) {price__avg: 34.35}
The argument to the aggregate() clause describes the aggregate value that we want to compute - in this case, the average of the price eld on the Book model. A list of the aggregate functions that are available can be found in the QuerySet reference. aggregate() is a terminal clause for a QuerySet that, when invoked, returns a dictionary of name-value pairs. The name is an identier for the aggregate value; the value is the computed aggregate. The name is automatically generated from the name of the eld and the aggregate function. If you want to manually specify a name for the aggregate value, you can do so by providing that name when you specify the aggregate clause:
>>> Book.objects.aggregate(average_price=Avg(price)) {average_price: 34.35}
If you want to generate more than one aggregate, you just add another argument to the aggregate() clause. So, if we also wanted to know the maximum and minimum price of all books, we would issue the query:
>>> from django.db.models import Avg, Max, Min, Count >>> Book.objects.aggregate(Avg(price), Max(price), Min(price)) {price__avg: 34.35, price__max: Decimal(81.20), price__min: Decimal(12.99)}
94
As with aggregate(), the name for the annotation is automatically derived from the name of the aggregate function and the name of the eld being aggregated. You can override this default name by providing an alias when you specify the annotation:
>>> q = Book.objects.annotate(num_authors=Count(authors)) >>> q[0].num_authors 2 >>> q[1].num_authors 1
Unlike aggregate(), annotate() is not a terminal clause. The output of the annotate() clause is a QuerySet; this QuerySet can be modied using any other QuerySet operation, including filter(), order_by, or even additional calls to annotate().
This tells Django to retrieve the Store model, join (through the many-to-many relationship) with the Book model, and aggregate on the price eld of the book model to produce a minimum and maximum value.
9.3. Aggregation
95
The same rules apply to the aggregate() clause. If you wanted to know the lowest and highest price of any book that is available for sale in a store, you could use the aggregate:
>>> Store.objects.aggregate(min_price=Min(books__price), max_price=Max(books__price))
Join chains can be as deep as you require. For example, to extract the age of the youngest author of any book available for sale, you could issue the query:
>>> Store.objects.aggregate(youngest_age=Min(books__authors__age))
When used with an aggregate() clause, a lter has the effect of constraining the objects over which the aggregate is calculated. For example, you can generate the average price of all books with a title that starts with Django using the query:
>>> Book.objects.filter(name__startswith="Django").aggregate(Avg(price))
Filtering on annotations
Annotated values can also be ltered. The alias for the annotation can be used in filter() and exclude() clauses in the same way as any other model eld. For example, to generate a list of books that have more than one author, you can issue the query:
>>> Book.objects.annotate(num_authors=Count(authors)).filter(num_authors__gt=1)
This query generates an annotated result set, and then generates a lter based upon that annotation.
>>> Publisher.objects.filter(book__rating__gt=3.0).annotate(num_books=Count(book))
Both queries will return a list of Publishers that have at least one good book (i.e., a book with a rating exceeding 3.0). However, the annotation in the rst query will provide the total number of all books published by the publisher; the second query will only include good books in the annotated count. In the rst query, the annotation precedes the lter, so the lter has no effect on the annotation. In the second query, the lter preceeds the annotation, and as a result, the lter constrains the objects considered when calculating the annotation. order_by() Annotations can be used as a basis for ordering. When you dene an order_by() clause, the aggregates you provide can reference any alias dened as part of an annotate() clause in the query. For example, to order a QuerySet of books by the number of authors that have contributed to the book, you could use the following query:
>>> Book.objects.annotate(num_authors=Count(authors)).order_by(num_authors)
values() Ordinarily, annotations are generated on a per-object basis - an annotated QuerySet will return one result for each object in the original QuerySet. However, when a values() clause is used to constrain the columns that are returned in the result set, the method for evaluating annotations is slightly different. Instead of returning an annotated result for each result in the original QuerySet, the original results are grouped according to the unique combinations of the elds specied in the values() clause. An annotation is then provided for each unique group; the annotation is computed over all members of the group. For example, consider an author query that attempts to nd out the average rating of books written by each author:
>>> Author.objects.annotate(average_rating=Avg(book__rating))
This will return one result for each author in the database, annotated with their average book rating. However, the result will be slightly different if you use a values() clause:
>>> Author.objects.values(name).annotate(average_rating=Avg(book__rating))
In this example, the authors will be grouped by name, so you will only get an annotated result for each unique author name. This means if you have two authors with the same name, their results will be merged into a single result in the output of the query; the average will be computed as the average over the books written by both authors.
9.3. Aggregation
97
This will now yield one unique result for each author; however, only the authors name and the average_rating annotation will be returned in the output data. You should also note that average_rating has been explicitly included in the list of values to be returned. This is required because of the ordering of the values() and annotate() clause. If the values() clause precedes the annotate() clause, any annotations will be automatically added to the result set. However, if the values() clause is applied after the annotate() clause, you need to explicitly include the aggregate column.
The important part here is the default ordering on the name eld. If you want to count how many times each distinct data value appears, you might try this:
# Warning: not quite correct! Item.objects.values("data").annotate(Count("id"))
...which will group the Item objects by their common data values and then count the number of id values in each group. Except that it wont quite work. The default ordering by name will also play a part in the grouping, so this query will group by distinct (data, name) pairs, which isnt what you want. Instead, you should construct this queryset:
Item.objects.values("data").annotate(Count("id")).order_by()
...clearing any ordering in the query. You could also order by, say, data without any harmful effects, since that is already playing a role in the query. This behavior is the same as that noted in the queryset documentation for distinct() and the general rule is the same: normally you wont want extra columns playing a part in the result, so clear out the ordering, or at least make sure its restricted only to those elds you also select in a values() call. Note: You might reasonably ask why Django doesnt remove the extraneous columns for you. The main reason is consistency with distinct() and other places: Django never removes ordering constraints that you have specied (and we cant change those other methods behavior, as that would violate our API stability policy).
98
Aggregating annotations You can also generate an aggregate on the result of an annotation. When you dene an aggregate() clause, the aggregates you provide can reference any alias dened as part of an annotate() clause in the query. For example, if you wanted to calculate the average number of authors per book you rst annotate the set of books with the author count, then aggregate that author count, referencing the annotation eld:
>>> Book.objects.annotate(num_authors=Count(authors)).aggregate(Avg(num_authors)) {num_authors__avg: 1.66}
9.4 Managers
class Manager() A Manager is the interface through which database query operations are provided to Django models. At least one Manager exists for every model in a Django application. The way Manager classes work is documented in Making queries; this document specically touches on model options that customize Manager behavior.
Using this example model, Person.objects will generate an AttributeError exception, Person.people.all() will provide a list of all Person objects.
but
9.4. Managers
99
For example, this custom Manager offers a method with_counts(), which returns a list of all OpinionPoll objects, each with an extra num_responses attribute that is the result of an aggregate query:
class PollManager(models.Manager): def with_counts(self): from django.db import connection cursor = connection.cursor() cursor.execute(""" SELECT p.id, p.question, p.poll_date, COUNT(*) FROM polls_opinionpoll p, polls_response r WHERE p.id = r.poll_id GROUP BY 1, 2, 3 ORDER BY 3 DESC""") result_list = [] for row in cursor.fetchall(): p = self.model(id=row[0], question=row[1], poll_date=row[2]) p.num_responses = row[3] result_list.append(p) return result_list class OpinionPoll(models.Model): question = models.CharField(max_length=200) poll_date = models.DateField() objects = PollManager() class Response(models.Model): poll = models.ForeignKey(Poll) person_name = models.CharField(max_length=50) response = models.TextField()
With this example, youd use OpinionPoll.objects.with_counts() to return that list of OpinionPoll objects with num_responses attributes. Another thing to note about this example is that Manager methods can access self.model to get the model class to which theyre attached. Modifying initial Manager QuerySets A Managers base QuerySet returns all objects in the system. For example, using this model:
class Book(models.Model): title = models.CharField(max_length=100) author = models.CharField(max_length=50)
...the statement Book.objects.all() will return all books in the database. You can override a Managers base QuerySet by overriding the Manager.get_query_set() method. get_query_set() should return a QuerySet with the properties you require. For example, the following model has two Managers one that returns all objects, and one that returns only the books by Roald Dahl:
# First, define the Manager subclass. class DahlBookManager(models.Manager): def get_query_set(self): return super(DahlBookManager, self).get_query_set().filter(author=Roald Dahl)
100
# Then hook it into the Book model explicitly. class Book(models.Model): title = models.CharField(max_length=100) author = models.CharField(max_length=50) objects = models.Manager() # The default manager. dahl_objects = DahlBookManager() # The Dahl-specific manager.
With this sample model, Book.objects.all() will return all books Book.dahl_objects.all() will only return the ones written by Roald Dahl.
in
the
database,
but
Of course, because get_query_set() returns a QuerySet object, you can use filter(), exclude() and all the other QuerySet methods on it. So these statements are all legal:
Book.dahl_objects.all() Book.dahl_objects.filter(title=Matilda) Book.dahl_objects.count()
This example also pointed out another interesting technique: using multiple managers on the same model. You can attach as many Manager() instances to a model as youd like. This is an easy way to dene common lters for your models. For example:
class MaleManager(models.Manager): def get_query_set(self): return super(MaleManager, self).get_query_set().filter(sex=M) class FemaleManager(models.Manager): def get_query_set(self): return super(FemaleManager, self).get_query_set().filter(sex=F) class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) sex = models.CharField(max_length=1, choices=((M, Male), (F, Female))) people = models.Manager() men = MaleManager() women = FemaleManager()
This example allows you to request Person.men.all(), Person.people.all(), yielding predictable results.
Person.women.all(),
and
If you use custom Manager objects, take note that the rst Manager Django encounters (in the order in which theyre dened in the model) has a special status. Django interprets the rst Manager dened in a class as the default Manager, and several parts of Django will use that Manager exclusively for that model. As a result, its a good idea to be careful in your choice of default manager in order to avoid a situation where overriding get_query_set() results in an inability to retrieve objects youd like to work with.
9.4. Managers
101
If the normal plain manager class (django.db.models.Manager) is not appropriate for your circumstances, you can force Django to use the same class as the default manager for your model by setting the use_for_related_elds attribute on the manager class. This is documented fully below. Custom managers and model inheritance Class inheritance and model managers arent quite a perfect match for each other. Managers are often specic to the classes they are dened on and inheriting them in subclasses isnt necessarily a good idea. Also, because the rst manager declared is the default manager, it is important to allow that to be controlled. So heres how Django handles custom managers and model inheritance: 1. Managers dened on non-abstract base classes are not inherited by child classes. If you want to reuse a manager from a non-abstract base, redeclare it explicitly on the child class. These sorts of managers are likely to be fairly specic to the class they are dened on, so inheriting them can often lead to unexpected results (particularly as far as the default manager goes). Therefore, they arent passed onto child classes. 2. Managers from abstract base classes are always inherited by the child class, using Pythons normal name resolution order (names on the child class override all others; then come names on the rst parent class, and so on). Abstract base classes are designed to capture information and behavior that is common to their child classes. Dening common managers is an appropriate part of this common information. 3. The default manager on a class is either the rst manager declared on the class, if that exists, or the default manager of the rst abstract base class in the parent hierarchy, if that exists. If no default manager is explicitly declared, Djangos normal default manager is used. These rules provide the necessary exibility if you want to install a collection of custom managers on a group of models, via an abstract base class, but still customize the default manager. For example, suppose you have this base class:
class AbstractBase(models.Model): ... objects = CustomManager() class Meta: abstract = True
If you use this directly in a subclass, objects will be the default manager if you declare no managers in the base class:
class ChildA(AbstractBase): ... # This class has CustomManager as the default manager.
If you want to inherit from AbstractBase, but provide a different default manager, you can provide the default manager on the child class:
class ChildB(AbstractBase): ... # An explicit default manager. default_manager = OtherManager()
Here, default_manager is the default. The objects manager is still available, since its inherited. It just isnt used as the default. Finally for this example, suppose you want to add extra managers to the child class, but still use the default from AbstractBase. You cant add the new manager directly in the child class, as that would override the default and
102
you would have to also explicitly include all the managers from the abstract base class. The solution is to put the extra managers in another base class and introduce it into the inheritance hierarchy after the defaults:
class ExtraManager(models.Model): extra_manager = OtherManager() class Meta: abstract = True class ChildC(AbstractBase, ExtraManager): ... # Default manager is CustomManager, but OtherManager is # also available via the "extra_manager" attribute.
If this attribute is set on the default manager for a model (only the default manager is considered in these situations), Django will use that class whenever it needs to automatically create a manager for the class. Otherwise, it will use django.db.models.Manager. Historical Note Given the purpose for which its used, the name of this attribute (use_for_related_fields) might seem a little odd. Originally, the attribute only controlled the type of manager used for related eld access, which is where the name came from. As it became clear the concept was more broadly useful, the name hasnt been changed. This is primarily so that existing code will continue to work in future Django versions. Writing Correct Managers For Use In Automatic Manager Instances As already suggested by the django.contrib.gis example, above, the use_for_related_fields feature is primarily for managers that need to return a custom QuerySet subclass. In providing this functionality in your manager, there are a couple of things to remember.
9.4. Managers
103
You also shouldnt change the attribute on the class object after it has been used in a model, since the attributes value is processed when the model class is created and not subsequently reread. Set the attribute on the manager class when it is rst dened, as in the initial example of this section and everything will work smoothly.
104
Model table names Whered the name of the Person table come from in that example? By default, Django gures out a database table name by joining the models app label the name you used in manage.py startapp to the models class name, with an underscore between them. In the example weve assumed that the Person model lives in an app named myapp, so its table would be myapp_person. For more details check out the documentation for the db_table option, which also lets you manually set the database table name. Of course, this example isnt very exciting its exactly the same as running Person.objects.all(). However, raw() has a bunch of other options that make it very powerful. Mapping query elds to model elds raw() automatically maps elds in the query to elds on the model. The order of elds in your query doesnt matter. In other words, both of the following queries work identically:
>>> Person.objects.raw(SELECT id, first_name, last_name, birth_date FROM myapp_person) ... >>> Person.objects.raw(SELECT last_name, birth_date, first_name, id FROM myapp_person) ...
Matching is done by name. This means that you can use SQLs AS clauses to map elds in the query to model elds. So if you had some other table that had Person data in it, you could easily map it into Person instances:
>>> Person.objects.raw(SELECT first AS first_name, ... last AS last_name, ... bd AS birth_date, ... pk as id, ... FROM some_other_table)
As long as the names match, the model instances will be created correctly. Alternatively, you can map elds in the query to model elds using the translations argument to raw(). This is a dictionary mapping names of elds in the query to names of elds on the model. For example, the above query could also be written:
>>> name_map = {first: first_name, last: last_name, bd: birth_date, pk: id} >>> Person.objects.raw(SELECT * FROM some_other_table, translations=name_map)
105
Index lookups raw() supports indexing, so if you need only the rst result you can write:
>>> first_person = Person.objects.raw(SELECT * from myapp_person)[0]
However, the indexing and slicing are not performed at the database level. If you have a big amount of Person objects in your database, it is more efcient to limit the query at the SQL level:
>>> first_person = Person.objects.raw(SELECT * from myapp_person LIMIT 1)[0]
The Person objects returned by this query will be deferred model instances. This means that the elds that are omitted from the query will be loaded on demand. For example:
>>> for p in Person.objects.raw(SELECT id, first_name FROM myapp_person): ... print p.first_name, # This will be retrieved by the original query ... print p.last_name # This will be retrieved on demand ... John Smith Jane Jones
From outward appearances, this looks like the query has retrieved both the rst name and last name. However, this example actually issued 3 queries. Only the rst names were retrieved by the raw() query the last names were both retrieved on demand when they were printed. There is only one eld that you cant leave out - the primary key eld. Django uses the primary key to identify model instances, so it must always be included in a raw query. An InvalidQuery exception will be raised if you forget to include the primary key. Adding annotations You can also execute queries containing elds that arent dened on the model. For example, we could use PostgreSQLs age() function to get a list of people with their ages calculated by the database:
>>> people = Person.objects.raw(SELECT *, age(birth_date) AS age FROM myapp_person) >>> for p in people: ... print "%s is %s." % (p.first_name, p.age) John is 37. Jane is 42. ...
Passing parameters into raw() If you need to perform parameterized queries, you can use the params argument to raw():
106
>>> lname = Doe >>> Person.objects.raw(SELECT * FROM myapp_person WHERE last_name = %s, [lname])
params is a list of parameters. Youll use %s placeholders in the query string (regardless of your database engine); theyll be replaced with parameters from the params list. Warning: Do not use string formatting on raw queries! Its tempting to write the above query as:
>>> query = SELECT * FROM myapp_person WHERE last_name = %s % lname >>> Person.objects.raw(query)
Dont. Using the params list completely protects you from SQL injection attacks, a common exploit where attackers inject arbitrary SQL into your database. If you use string interpolation, sooner or later youll fall victim to SQL injection. As long as you remember to always use the params list youll be protected.
If you are using more than one database you can use django.db.connections to obtain the connection (and cursor) for a specic database. django.db.connections is a dictionary-like object that allows you to retrieve a specic connection using its alias:
from django.db import connections cursor = connections[my_db_alias].cursor()
107
Transactions and raw SQL If you are using transaction decorators (such as commit_on_success) to wrap your views and provide transaction control, you dont have to make a manual call to transaction.commit_unless_managed() you can manually commit if you want to, but you arent required to, since the decorator will commit for you. However, if you dont manually commit your changes, you will need to manually mark the transaction as dirty, using transaction.set_dirty():
@commit_on_success def my_custom_sql_view(request, value): from django.db import connection, transaction cursor = connection.cursor() # Data modifying operation cursor.execute("UPDATE bar SET foo = 1 WHERE baz = %s", [value]) # Since we modified data, mark the transaction as dirty transaction.set_dirty() # Data retrieval operation. This doesnt dirty the transaction, # so no call to set_dirty() is required. cursor.execute("SELECT foo FROM bar WHERE baz = %s", [value]) row = cursor.fetchone() return render_to_response(template.html, {row: row})
The call to set_dirty() is made automatically when you use the Django ORM to make data modifying database calls. However, when you use raw SQL, Django has no way of knowing if your SQL modies data or not. The manual call to set_dirty() ensures that Django knows that there are modications that must be committed. Connections and cursors connection and cursor mostly implement the standard Python DB-API (except when it comes to transaction handling). If youre not familiar with the Python DB-API, note that the SQL statement in cursor.execute() uses placeholders, "%s", rather than adding parameters directly within the SQL. If you use this technique, the underlying database library will automatically add quotes and escaping to your parameter(s) as necessary. (Also note that Django expects the "%s" placeholder, not the "?" placeholder, which is used by the SQLite Python bindings. This is for the sake of consistency and sanity.)
The order is quite important. The transaction middleware applies not only to view functions, but also for all middleware modules that come after it. So if you use the session middleware after the transaction middleware, session creation will be part of the transaction. An exception is CacheMiddleware, which is never affected. The cache middleware uses its own database cursor (which is mapped to its own database connection internally).
Within viewfunc(), transactions will be committed as soon as you call model.save(), model.delete(), or any other function that writes to the database. viewfunc2() will have this same behavior, but for the "my_other_database" connection.
109
django.db.transaction.commit_on_success Use the commit_on_success decorator to use a single transaction for all the work done in a function:
from django.db import transaction @transaction.commit_on_success def viewfunc(request): .... @transaction.commit_on_success(using="my_other_database") def viewfunc2(request): ....
If the function returns successfully, then Django will commit all work done within the function at that point. If the function raises an exception, though, Django will roll back the transaction. django.db.transaction.commit_manually Use the commit_manually decorator if you need full control over transactions. It tells Django youll be managing the transaction on your own. If your view changes data and doesnt TransactionManagementError exception. Manual transaction management looks like this:
from django.db import transaction @transaction.commit_manually def viewfunc(request): ... # You can commit/rollback however and whenever you want transaction.commit() ... # But youve got to remember to do it yourself! try: ... except: transaction.rollback() else: transaction.commit() @transaction.commit_manually(using="my_other_database") def viewfunc2(request): ....
commit()
or
rollback(),
Django
will
raise
An important note to users of earlier Django releases: The database connection.commit() and connection.rollback() methods (called db.commit() and db.rollback() in 0.91 and earlier) no longer exist. Theyve been replaced by transaction.commit() and transaction.rollback().
110
9.6.5 Savepoints
A savepoint is a marker within a transaction that enables you to roll back part of a transaction, rather than the full transaction. Savepoints are available to the PostgreSQL 8 and Oracle backends. Other backends will provide the savepoint functions, but they are empty operations - they wont actually do anything. Savepoints arent especially useful if you are using the default autocommit behaviour of Django. However, if you are using commit_on_success or commit_manually, each open transaction will build up a series of database operations, awaiting a commit or rollback. If you issue a rollback, the entire transaction is rolled back. Savepoints provide the ability to perform a ne-grained rollback, rather than the full rollback that would be performed by transaction.rollback(). Each of these functions takes a using argument which should be the name of a database for which the behavior applies. If no using argument is provided then the "default" database is used. Savepoints are controlled by three methods on the transaction object: savepoint(using=None) Creates a new savepoint. This marks a point in the transaction that is known to be in a good state. Returns the savepoint ID (sid). savepoint_commit(sid, using=None) Updates the savepoint to include any operations that have been performed since the savepoint was created, or since the last commit. savepoint_rollback(sid, using=None) Rolls the transaction back to the last point at which the savepoint was committed. The following example demonstrates the use of savepoints:
from django.db import transaction @transaction.commit_manually def viewfunc(request): a.save() # open transaction now contains a.save() sid = transaction.savepoint() b.save() # open transaction now contains a.save() and b.save() if want_to_keep_b: transaction.savepoint_commit(sid) # open transaction still contains a.save() and b.save()
111
Calling transaction.rollback() rolls back the entire transaction. Any uncommitted database operations will be lost. In this example, the changes made by a.save() would be lost, even though that operation raised no error itself. Savepoint rollback If you are using PostgreSQL 8 or later, you can use savepoints to control the extent of a rollback. Before performing a database operation that could fail, you can set or update the savepoint; that way, if the operation fails, you can roll back the single offending operation, rather than the entire transaction. For example:
a.save() # Succeeds, and never undone by savepoint rollback try: sid = transaction.savepoint() b.save() # Could throw exception transaction.savepoint_commit(sid)
112
In this example, a.save() will not be undone in the case where b.save() raises an exception. Database-level autocommit New in version 1.1: Please, see the release notes With PostgreSQL 8.2 or later, there is an advanced option to run PostgreSQL with database-level autocommit. If you use this option, there is no constantly open transaction, so it is always possible to continue after catching an exception. For example:
a.save() # succeeds try: b.save() # Could throw exception except IntegrityError: pass c.save() # succeeds
Note: This is not the same as the autocommit decorator. When using database level autocommit there is no database transaction at all. The autocommit decorator still uses transactions, automatically committing each transaction when a database modifying operation occurs.
113
If you attempt to access a database that you havent dened in your DATABASES setting, Django will raise a django.db.utils.ConnectionDoesNotExist exception.
If you dont want every application to be synchronized onto a particular database, you can dene a database router that implements a policy constraining the availability of particular models. Alternatively, if you want ne-grained control of synchronization, you can pipe all or part of the output of sqlall for a particular application directly into your database prompt, like this:
$ ./manage.py sqlall sales | ./manage.py dbshell
Using other management commands The other django-admin.py commands that interact with the database operate in the same way as syncdb they only ever operate on one database at a time, using --database to control the database used.
db_for_write(model, **hints) Suggest the database that should be used for writes of objects of type Model. If a database operation is able to provide any additional information that might assist in selecting a database, it will be provided in the hints dictionary. Details on valid hints are provided below. Returns None if there is no suggestion. allow_relation(obj1, obj2, **hints) Return True if a relation between obj1 and obj2 should be allowed, False if the relation should be prevented, or None if the router has no opinion. This is purely a validation operation, used by foreign key and many to many operations to determine if a relation should be allowed between two objects. allow_syncdb(db, model) Determine if the model should be synchronized onto the database with alias db. Return True if the model should be synchronized, False if it should not be synchronized, or None if the router has no opinion. This method can be used to determine the availability of a model on a given database. A router doesnt have to provide all these methods - it omit one or more of them. If one of the methods is omitted, Django will skip that router when performing the relevant check.
Hints
The hints received by the database router can be used to decide which database should receive a given request. At present, the only hint that will be provided is instance, an object instance that is related to the read or write operation that is underway. This might be the instance that is being saved, or it might be an instance that is being added in a many-to-many relation. In some cases, no instance hint will be provided at all. The router checks for the existence of an instance hint, and determine if that hint should be used to alter routing behavior. Using routers Database routers are installed using the DATABASE_ROUTERS setting. This setting denes a list of class names, each specifying a router that should be used by the master router (django.db.router). The master router is used by Djangos database operations to allocate database usage. Whenever a query needs to know which database to use, it calls the master router, providing a model and a hint (if available). Django then tries each router in turn until a database suggestion can be found. If no suggestion can be found, it tries the current _state.db of the hint instance. If a hint instance wasnt provided, or the instance doesnt currently have database state, the master router will allocate the default database. An example Example purposes only! This example is intended as a demonstration of how the router infrastructure can be used to alter database usage. It intentionally ignores some complex issues in order to demonstrate how routers are used. This example wont work if any of the models in myapp contain relationships to models outside of the other database. Cross-database relationships introduce referential integrity problems that Django cant currently handle. The master/slave conguration described is also awed it doesnt provide any solution for handling replication lag (i.e., query inconsistencies introduced because of the time taken for a write to propagate to the slaves). It also doesnt consider the interaction of transactions with the database utilization strategy.
115
So - what does this mean in practice? Say you want myapp to exist on the other database, and you want all other models in a master/slave relationship between the databases master, slave1 and slave2. To implement this, you would need 2 routers:
class MyAppRouter(object): """A router to control all database operations on models in the myapp application""" def db_for_read(self, model, **hints): "Point all operations on myapp models to other" if model._meta.app_label == myapp: return other return None def db_for_write(self, model, **hints): "Point all operations on myapp models to other" if model._meta.app_label == myapp: return other return None def allow_relation(self, obj1, obj2, **hints): "Allow any relation if a model in myapp is involved" if obj1._meta.app_label == myapp or obj2._meta.app_label == myapp: return True return None def allow_syncdb(self, db, model): "Make sure the myapp app only appears on the other db" if db == other: return model._meta.app_label == myapp elif model._meta.app_label == myapp: return False return None class MasterSlaveRouter(object): """A router that sets up a simple master/slave configuration""" def db_for_read(self, model, **hints): "Point all read operations to a random slave" return random.choice([slave1,slave2]) def db_for_write(self, model, **hints): "Point all write operations to the master" return master def allow_relation(self, obj1, obj2, **hints): "Allow any relation between two objects in the db pool" db_list = (master,slave1,slave2) if obj1._state.db in db_list and obj2._state.db in db_list: return True return None def allow_syncdb(self, db, model): "Explicitly put all models on all databases." return True
Then, in your settings le, add the following (substituting path.to. with the actual python path to the module where you dene the routers):
116
The order in which routers are processed is signicant. Routers will be queried in the order the are listed in the DATABASE_ROUTERS setting . In this example, the MyAppRouter is processed before the MasterSlaveRouter, and as a result, decisions concerning the models in myapp are processed before any other decision is made. If the DATABASE_ROUTERS setting listed the two routers in the other order, MasterSlaveRouter.allow_syncdb() would be processed rst. The catch-all nature of the MasterSlaveRouter implementation would mean that all models would be available on all databases. With this setup installed, lets run some Django code:
>>> # This retrieval will be performed on the credentials database >>> fred = User.objects.get(username=fred) >>> fred.first_name = Frederick >>> # This save will also be directed to credentials >>> fred.save() >>> # These retrieval will be randomly allocated to a slave database >>> dna = Person.objects.get(name=Douglas Adams) >>> # A new object has no database allocation when created >>> mh = Book(title=Mostly Harmless) >>> # This assignment will consult the router, and set mh onto >>> # the same database as the author object >>> mh.author = dna >>> # This save will force the mh instance onto the master database... >>> mh.save() >>> # ... but if we re-retrieve the object, it will come back on a slave >>> mh = Book.objects.get(title=Mostly Harmless)
117
Selecting a database for save() Use the using keyword to Model.save() to specify to which database the data should be saved. For example, to save an object to the legacy_users database, youd use this:
>>> my_object.save(using=legacy_users)
If you dont specify using, the save() method will save into the default database allocated by the routers.
In statement 1, a new Person object is saved to the first database. At this time, p doesnt have a primary key, so Django issues a SQL INSERT statement. This creates a primary key, and Django assigns that primary key to p. When the save occurs in statement 2, p already has a primary key value, and Django will attempt to use that primary key on the new database. If the primary key value isnt in use in the second database, then you wont have any problems the object will be copied to the new database. However, if the primary key of p is already in use on the second database, the existing object in the second database will be overridden when p is saved. You can avoid this in two ways. First, you can clear the primary key of the instance. If an object has no primary key, Django will treat it as a new object, avoiding any loss of data on the second database:
>>> >>> >>> >>> p = Person(name=Fred) p.save(using=first) p.pk = None # Clear the primary key. p.save(using=second) # Write a completely new object.
The second option is to use the force_insert option to save() to ensure that Django does a SQL INSERT:
>>> p = Person(name=Fred) >>> p.save(using=first) >>> p.save(using=second, force_insert=True)
This will ensure that the person named Fred will have the same primary key on both databases. If that primary key is already in use when you try to save onto the second database, an error will be raised. Selecting a database to delete from By default, a call to delete an existing object will be executed on the same database that was used to retrieve the object in the rst place:
118
>>> u = User.objects.using(legacy_users).get(username=fred) >>> u.delete() # will delete from the legacy_users database
To specify the database from which a model will be deleted, pass a using keyword argument to the Model.delete() method. This argument works just like the using keyword argument to save(). For example, if youre migrating a user from the legacy_users database to the new_users database, you might use these commands:
>>> user_obj.save(using=new_users) >>> user_obj.delete(using=legacy_users)
Using managers with multiple databases Use the db_manager() method on managers to give managers access to a non-default database. For example, say you have a custom manager method that touches the database User.objects.create_user(). Because create_user() is a manager method, not a QuerySet method, you cant do User.objects.using(new_users).create_user(). (The create_user() method is only available on User.objects, the manager, not on QuerySet objects derived from the manager.) The solution is to use db_manager(), like this:
User.objects.db_manager(new_users).create_user(...)
db_manager() returns a copy of the manager bound to the database you specify.
119
def save_model(self, request, obj, form, change): # Tell Django to save objects to the other database. obj.save(using=self.using) def queryset(self, request): # Tell Django to look for objects on the other database. return super(MultiDBModelAdmin, self).queryset(request).using(self.using)
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): # Tell Django to populate ForeignKey widgets using a query # on the other database. return super(MultiDBModelAdmin, self).formfield_for_foreignkey(db_field, request=request, usi
def formfield_for_manytomany(self, db_field, request=None, **kwargs): # Tell Django to populate ManyToMany widgets using a query # on the other database. return super(MultiDBModelAdmin, self).formfield_for_manytomany(db_field, request=request, usi
The implementation provided here implements a multi-database strategy where all objects of a given type are stored on a specic database (e.g., all User objects are in the other database). If your usage of multiple databases is more complex, your ModelAdmin will need to reect that strategy. Inlines can be handled in a similar fashion. They require three customized methods:
class MultiDBTabularInline(admin.TabularInline): using = other def queryset(self, request): # Tell Django to look for inline objects on the other database. return super(MultiDBTabularInline, self).queryset(request).using(self.using) def formfield_for_foreignkey(self, db_field, request=None, **kwargs): # Tell Django to populate ForeignKey widgets using a query # on the other database. return super(MultiDBTabularInline, self).formfield_for_foreignkey(db_field, request=request, def formfield_for_manytomany(self, db_field, request=None, **kwargs): # Tell Django to populate ManyToMany widgets using a query # on the other database. return super(MultiDBTabularInline, self).formfield_for_manytomany(db_field, request=request,
Once youve written your model admin denitions, they can be registered with any Admin instance:
from django.contrib import admin # Specialize the multi-db admin objects for use with specific models. class BookInline(MultiDBTabularInline): model = Book class PublisherAdmin(MultiDBModelAdmin): inlines = [BookInline] admin.site.register(Author, MultiDBModelAdmin) admin.site.register(Publisher, PublisherAdmin) othersite = admin.Site(othersite) othersite.register(Publisher, MultiDBModelAdmin)
120
This example sets up two admin sites. On the rst site, the Author and Publisher objects are exposed; Publisher objects have an tabular inline showing books published by that publisher. The second site exposes just publishers, without the inlines.
121
With everything that follows, remember to prole after every change to ensure that the change is a benet, and a big enough benet given the decrease in readability of your code. All of the suggestions below come with the caveat that in your circumstances the general principle might not apply, or might even be reversed.
Be careful when reading template code - the template system does not allow use of parentheses, but will call callables automatically, hiding the above distinction. Be careful with your own custom properties - it is up to you to implement caching. Use the with template tag To make use of the caching behaviour of QuerySet, you may need to use the with template tag.
122
Use iterator() When you have a lot of objects, the caching behaviour of the QuerySet can cause a large amount of memory to be used. In this case, QuerySet.iterator() may help.
123
Use QuerySet.defer() and only() Use defer() and only() if there are database columns you know that you wont need (or wont need in most cases) to avoid loading them. Note that if you do use them, the ORM will have to go and get them in a separate query, making this a pessimization if you use it inappropriately. Use QuerySet.count() ...if you only want the count, rather than doing len(queryset). Use QuerySet.exists() ...if you only want to nd out if at least one result exists, rather than if queryset. But: Dont overuse count() and exists() If you are going to need other data from the QuerySet, just evaluate it. For example, assuming an Email class that has a body attribute and a many-to-many relation to User, the following template code is optimal:
{% if display_inbox %} {% with user.emails.all as emails %} {% if emails %} <p>You have {{ emails|length }} email(s)</p> {% for email in emails %} <p>{{ email.body }}</p> {% endfor %} {% else %} <p>No messages today.</p> {% endif %} {% endwith %} {% endif %}
It is optimal because: 1. Since QuerySets are lazy, this does no database if display_inbox is False. 2. Use of with means that we store user.emails.all in a variable for later use, allowing its cache to be re-used. 3. The line {% if emails %} causes QuerySet.__nonzero__() to be called, which causes the user.emails.all() query to be run on the database, and at the least the rst line to be turned into an ORM object. If there arent any results, it will return False, otherwise True. 4. The use of {{ emails|length }} calls QuerySet.__len__(), lling out the rest of the cache without doing another query. 5. The for loop iterates over the already lled cache. In total, this code does either one or zero database queries. The only deliberate optimization performed is the use of the with tag. Using QuerySet.exists() or QuerySet.count() at any point would cause additional queries.
124
Use QuerySet.update() and delete() Rather than retrieve a load of objects, set some values, and save them individual, use a bulk SQL UPDATE statement, via QuerySet.update(). Similarly, do bulk deletes where possible. Note, however, that these bulk update methods cannot call the save() or delete() methods of individual instances, which means that any custom behaviour you have added for these methods will not be executed, including anything driven from the normal database object signals.
instead of:
entry.blog.id
125
126
CHAPTER
TEN
10.1.1 Overview
To design URLs for an app, you create a Python module informally called a URLconf (URL conguration). This module is pure Python code and is a simple mapping between URL patterns (as simple regular expressions) to Python callback functions (your views). This mapping can be as short or as long as needed. It can reference other mappings. And, because its pure Python code, it can be constructed dynamically.
127
10.1.3 Example
Heres a sample URLconf:
from django.conf.urls.defaults import * urlpatterns = patterns(, (r^articles/2003/$, news.views.special_case_2003), (r^articles/(\d{4})/$, news.views.year_archive), (r^articles/(\d{4})/(\d{2})/$, news.views.month_archive), (r^articles/(\d{4})/(\d{2})/(\d+)/$, news.views.article_detail), )
Notes: from django.conf.urls.defaults import * makes the patterns() function available. To capture a value from the URL, just put parenthesis around it. Theres no need to add a leading slash, because every URL has that. For example, its ^articles, not ^/articles. The r in front of each regular expression string is optional but recommended. It tells Python that a string is raw that nothing in the string should be escaped. See Dive Into Pythons explanation. Example requests: A request to /articles/2005/03/ would match the third entry in the list. Django would call the function news.views.month_archive(request, 2005, 03). /articles/2005/3/ would not match any URL patterns, because the third entry in the list requires two digits for the month. /articles/2003/ would match the rst pattern in the list, not the second one, because the patterns are tested in order, and the rst one is the rst test to pass. Feel free to exploit the ordering to insert special cases like this. /articles/2003 would not match any of these patterns, because each pattern requires that the URL end with a slash. /articles/2003/03/3/ would match the nal pattern. Django would call the function news.views.article_detail(request, 2003, 03, 3).
128
This accomplishes exactly the same thing as the previous example, with one subtle difference: The captured values are passed to view functions as keyword arguments rather than positional arguments. For example: A request to /articles/2005/03/ would call the function news.views.month_archive(request, year=2005, month=03), instead of news.views.month_archive(request, 2005, 03). A request to /articles/2003/03/3/ would call the function news.views.article_detail(request, year=2003, month=03, day=3). In practice, this means your URLconfs are slightly more explicit and less prone to argument-order bugs and you can reorder the arguments in your views function denitions. Of course, these benets come at the cost of brevity; some developers nd the named-group syntax ugly and too verbose. The matching/grouping algorithm Heres the algorithm the URLconf parser follows, with respect to named groups vs. non-named groups in a regular expression: If there are any named arguments, it will use those, ignoring non-named arguments. Otherwise, it will pass all nonnamed arguments as positional arguments. In both cases, it will pass any extra keyword arguments as keyword arguments. See Passing extra options to view functions below.
129
...where optional dictionary and optional name are optional. (See Passing extra options to view functions below.) Note: Because patterns() is a function call, it accepts a maximum of 255 arguments (URL patterns, in this case). This is a limit for all Python function calls. This is rarely a problem in practice, because youll typically structure your URL patterns modularly by using include() sections. However, on the off-chance you do hit the 255-argument limit, realize that patterns() returns a Python list, so you can split up the construction of the list.
urlpatterns = patterns(, ... ) urlpatterns += patterns(, ... )
Python lists have unlimited size, so theres no limit to how many URL patterns you can construct. The only limit is that you can only create 254 at a time (the 255th argument is the initial prex argument). url New in version 1.0: Please, see the release notes url(regex, view, kwargs=None, name=None, prex=) You can use the url() function, instead of a tuple, as an argument to patterns(). This is convenient if you want to specify a name without the optional extra arguments dictionary. For example:
urlpatterns = patterns(, url(r^index/$, index_view, name="main-view"), ... )
See Naming URL patterns for why the name parameter is useful. The prefix parameter has the same meaning as the rst argument to patterns() and is only relevant when youre passing a string as the view parameter. handler404 handler404 A callable, or a string representing the full Python import path to the view that should be called if none of the URL patterns match. By default, this is django.views.defaults.page_not_found. That default value should sufce. Changed in version 1.2: Previous versions of Django only accepted strings representing import paths.
130
handler500 handler500 A callable, or a string representing the full Python import path to the view that should be called in case of server errors. Server errors happen when you have runtime errors in view code. By default, this is django.views.defaults.server_error. That default value should sufce. Changed in version 1.2: Previous versions of Django only accepted strings representing import paths. include include(<module or pattern_list>) A function that takes a full Python import path to another URLconf module that should be included in this place. New in version 1.1: Please, see the release notes include() also accepts as an argument an iterable that returns URL patterns. See Including other URLconfs below.
...the year argument to news.views.year_archive() will be a string, not an integer, even though the \d{4} will only match integer strings. A convenient trick is to specify default parameters for your views arguments. Heres an example URLconf and view:
# URLconf urlpatterns = patterns(, (r^blog/$, blog.views.page), (r^blog/page(?P<num>\d+)/$, blog.views.page), ) # View (in blog/views.py) def page(request, num="1"): # Output the appropriate page of blog entries, according to num.
In the above example, both URL patterns point to the same view blog.views.page but the rst pattern doesnt capture anything from the URL. If the rst pattern matches, the page() function will use its default argument for num, "1". If the second pattern matches, page() will use whatever num value was captured by the regex.
10.1.8 Performance
Each regular expression in a urlpatterns is compiled the rst time its accessed. This makes the system blazingly fast.
131
In this example, each view has a common prex mysite.news.views. Instead of typing that out for each entry in urlpatterns, you can use the rst argument to the patterns() function to specify a prex to apply to each view function. With this in mind, the above example can be written more concisely as:
from django.conf.urls.defaults import * urlpatterns = patterns(mysite.news.views, (r^articles/(\d{4})/$, year_archive), (r^articles/(\d{4})/(\d{2})/$, month_archive), (r^articles/(\d{4})/(\d{2})/(\d+)/$, article_detail), )
Note that you dont put a trailing dot (".") in the prex. Django puts that in automatically. Multiple view prexes In practice, youll probably end up mixing and matching views to the point where the views in your urlpatterns wont have a common prex. However, you can still take advantage of the view prex shortcut to remove duplication. Just add multiple patterns() objects together, like this: Old:
from django.conf.urls.defaults import * urlpatterns = patterns(, (r^$, django.views.generic.date_based.archive_index), (r^(?P<year>\d{4})/(?P<month>[a-z]{3})/$, django.views.generic.date_based.archive_month), (r^tag/(?P<tag>\w+)/$, weblog.views.tag), )
New:
from django.conf.urls.defaults import * urlpatterns = patterns(django.views.generic.date_based, (r^$, archive_index), (r^(?P<year>\d{4})/(?P<month>[a-z]{3})/$,archive_month), ) urlpatterns += patterns(weblog.views,
132
(r^tag/(?P<tag>\w+)/$, tag), )
Note that the regular expressions in this example dont have a $ (end-of-string match character) but do include a trailing slash. Whenever Django encounters include(), it chops off whatever part of the URL matched up to that point and sends the remaining string to the included URLconf for further processing. New in version 1.1: Please, see the release notes Another possibility is to include additional URL patterns not by specifying the URLconf Python module dening them as the include argument but by using directly the pattern list as returned by patterns instead. For example:
from django.conf.urls.defaults import * extra_patterns = patterns(, url(rreports/(?P<id>\d+)/$, credit.views.report, name=credit-reports), url(rcharge/$, credit.views.charge, name=credit-charge), ) urlpatterns = patterns(, url(r^$, apps.main.views.homepage, name=site-homepage), (r^help/, include(apps.help.urls)), (r^credit/, include(extra_patterns)), )
This approach can be seen in use when you deploy an instance of the Django Admin application. The Django Admin is deployed as instances of a AdminSite; each AdminSite instance has an attribute urls that returns the url patterns available to that instance. It is this attribute that you include() into your projects urlpatterns when you deploy the admin instance. Captured parameters An included URLconf receives any captured parameters from parent URLconfs, so the following example is valid:
# In settings/urls/main.py urlpatterns = patterns(, (r^(?P<username>\w+)/blog/, include(foo.urls.blog)), ) # In foo/urls/blog.py urlpatterns = patterns(foo.views,
133
In the above example, the captured "username" variable is passed to the included URLconf, as expected. Dening URL Namespaces When you need to deploy multiple instances of a single application, it can be helpful to be able to differentiate between instances. This is especially important when using named URL patterns, since multiple instances of a single application will share named URLs. Namespaces provide a way to tell these named URLs apart. A URL namespace comes in two parts, both of which are strings: An application namespace. This describes the name of the application that is being deployed. Every instance of a single application will have the same application namespace. For example, Djangos admin application has the somewhat predictable application namespace of admin. An instance namespace. This identies a specic instance of an application. Instance namespaces should be unique across your entire project. However, an instance namespace can be the same as the application namespace. This is used to specify a default instance of an application. For example, the default Django Admin instance has an instance namespace of admin. URL Namespaces can be specied in two ways. Firstly, you can provide the application and instance namespace as arguments to include() when you construct your URL patterns. For example,:
(r^help/, include(apps.help.urls, namespace=foo, app_name=bar)),
This will include the URLs dened in apps.help.urls into the application namespace bar, with the instance namespace foo. Secondly, you can include an object that contains embedded namespace data. If you include() a patterns object, that object will be added to the global namespace. However, you can also include() an object that contains a 3-tuple containing:
(<patterns object>, <application namespace>, <instance namespace>)
This will include the nominated URL patterns into the given application and instance namespace. For example, the urls attribute of Djangos AdminSite object returns a 3-tuple that contains all the patterns in an admin site, plus the name of the admin instance, and the application namespace admin. Once you have dened namespaced URLs, you can reverse them. For details on reversing namespaced urls, see the documentation on reversing namespaced URLs.
134
In this example, for a request to /blog/2005/, Django will call the blog.views.year_archive() view, passing it these keyword arguments:
year=2005, foo=bar
This technique is used in generic views and in the syndication framework to pass metadata and options to views. Dealing with conicts Its possible to have a URL pattern which captures named keyword arguments, and also passes arguments with the same names in its dictionary of extra arguments. When this happens, the arguments in the dictionary will be used instead of the arguments captured in the URL. Passing extra options to include() Similarly, you can pass extra options to include(). When you pass extra options to include(), each line in the included URLconf will be passed the extra options. For example, these two URLconf sets are functionally identical: Set one:
# main.py urlpatterns = patterns(, (r^blog/, include(inner), {blogid: 3}), ) # inner.py urlpatterns = patterns(, (r^archive/$, mysite.views.archive), (r^about/$, mysite.views.about), )
Set two:
# main.py urlpatterns = patterns(, (r^blog/, include(inner)), ) # inner.py urlpatterns = patterns(, (r^archive/$, mysite.views.archive, {blogid: 3}), (r^about/$, mysite.views.about, {blogid: 3}), )
Note that extra options will always be passed to every line in the included URLconf, regardless of whether the lines view actually accepts those options as valid. For this reason, this technique is only useful if youre certain that every view in the included URLconf accepts the extra options youre passing.
135
You can accomplish the same thing by passing objects rather than strings. Just be sure to import the objects:
from mysite.views import archive, about, contact urlpatterns = patterns(, (r^archive/$, archive), (r^about/$, about), (r^contact/$, contact), )
The following example is functionally identical. Its just a bit more compact because it imports the module that contains the views, rather than importing each view individually:
from mysite import views urlpatterns = patterns(, (r^archive/$, views.archive), (r^about/$, views.about), (r^contact/$, views.contact), )
The style you use is up to you. Note that if you use this technique passing objects rather than strings the view prex (as explained in The view prex above) will have no effect.
This is completely valid, but it leads to problems when you try to do reverse URL matching (through the permalink() decorator or the url template tag). Continuing this example, if you wanted to retrieve the URL for the archive view, Djangos reverse URL matcher would get confused, because two URLpatterns point at that view. To solve this problem, Django supports named URL patterns. That is, you can give a name to a URL pattern in order to distinguish it from other patterns using the same view and parameters. Then, you can use this name in reverse URL matching. 136 Chapter 10. Handling HTTP requests
With these names in place (full-archive and arch-summary), you can target each pattern individually by using its name:
{% url arch-summary 1945 %} {% url full-archive 2007 %}
Even though both URL patterns refer to the archive view here, using the name parameter to url() allows you to tell them apart in templates. The string used for the URL name can contain any characters you like. You are not restricted to valid Python names. Note: When you name your URL patterns, make sure you use names that are unlikely to clash with any other applications choice of names. If you call your URL pattern comment, and another application does the same thing, theres no guarantee which URL will be inserted into your template when you use this name. Putting a prex on your URL names, perhaps derived from the application name, will decrease the chances of collision. We recommend something like myapp-comment instead of comment. URL namespaces New in version 1.1: Please, see the release notes Namespaced URLs are specied using the : operator. For example, the main index page of the admin application is referenced using admin:index. This indicates a namespace of admin, and a named URL of index. Namespaces can also be nested. The named URL foo:bar:whiz would look for a pattern named whiz in the namespace bar that is itself dened within the top-level namespace foo. When given a namespaced URL (e.g. myapp:index) to resolve, Django splits the fully qualied name into parts, and then tries the following lookup: 1. First, Django looks for a matching application namespace (in this example, myapp). This will yield a list of instances of that application. 2. If there is a current application dened, Django nds and returns the URL resolver for that instance. The current application can be specied as an attribute on the template context - applications that expect to have multiple deployments should set the current_app attribute on any Context or RequestContext that is used to render a template. The current application can also be specied manually as an argument to the reverse() function. 3. If there is no current application. Django looks for a default application instance. The default application instance is the instance that has an instance namespace matching the application namespace (in this example, an instance of the myapp called myapp). 4. If there is no default application instance, Django will pick the last deployed instance of the application, whatever its instance name may be. 5. If the provided namespace doesnt match an application namespace in step 1, Django will attempt a direct lookup of the namespace as an instance namespace. If there are nested namespaces, these steps are repeated for each part of the namespace until only the view name is unresolved. The view name will then be resolved into a URL in the namespace that has been found.
137
To show this resolution strategy in action, consider an example of two instances of myapp: one called foo, and one called bar. myapp has a main index page with a URL named index. Using this setup, the following lookups are possible: If one of the instances is current - say, if we were rendering a utility page in the instance bar - myapp:index will resolve to the index page of the instance bar. If there is no current instance - say, if we were rendering a page somewhere else on the site - myapp:index will resolve to the last registered instance of myapp. Since there is no default instance, the last instance of myapp that is registered will be used. This could be foo or bar, depending on the order they are introduced into the urlpatterns of the project. foo:index will always resolve to the index page of the instance foo. If there was also a default instance - i.e., an instance named myapp - the following would happen: If one of the instances is current - say, if we were rendering a utility page in the instance bar - myapp:index will resolve to the index page of the instance bar. If there is no current instance - say, if we were rendering a page somewhere else on the site - myapp:index will resolve to the index page of the default instance. foo:index will again resolve to the index page of the instance foo.
The reverse() function can reverse a large variety of regular expression patterns for URLs, but not every possible one. The main restriction at the moment is that the pattern cannot contain alternative choices using the vertical bar ("|") character. You can quite happily use such patterns for matching against incoming URLs and sending them off to views, but you cannot reverse such patterns. New in version 1.1: Please, see the release notes The current_app argument allows you to provide a hint to the resolver indicating the application to which the currently executing view belongs. This current_app argument is used as a hint to resolve application namespaces into URLs on specic application instances, according to the namespaced URL resolution strategy. Make sure your views are all correct As part of working out which URL names map to which patterns, the reverse() function has to import all of your URLconf les and examine the name of each view. This involves importing each view function. If there are any errors whilst importing any of your view functions, it will cause reverse() to raise an error, even if that view function is not the one you are trying to reverse. Make sure that any views you reference in your URLconf les exist and can be imported correctly. Do not include lines that reference views you havent written yet, because those views will not be importable.
138
resolve() The django.core.urlresolvers.resolve() function can be used for resolving URL paths to the corresponding view functions. It has the following signature: resolve(path, urlconf=None) path is the URL path you want to resolve. As with reverse() above, you dont need to worry about the urlconf parameter. The function returns the triple (view function, arguments, keyword arguments). For example, it can be used for testing if a view would raise a Http404 error before redirecting to it:
from urlparse import urlparse from django.core.urlresolvers import resolve from django.http import HttpResponseRedirect, Http404 def myview(request): next = request.META.get(HTTP_REFERER, None) or / response = HttpResponseRedirect(next) # modify the request and response as required, e.g. change locale # and set corresponding locale cookie view, args, kwargs = resolve(urlparse(next)[2]) kwargs[request] = request try: view(*args, **kwargs) except Http404: return HttpResponseRedirect(/) return response
permalink() The django.db.models.permalink() decorator is useful for writing short methods that return a full URL path. For example, a models get_absolute_url() method. See django.db.models.permalink() for more.
139
def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html)
Lets step through this code one line at a time: First, we import the class HttpResponse, which lives in the django.http module, along with Pythons datetime library. Next, we dene a function called current_datetime. This is the view function. Each view function takes an HttpRequest object as its rst parameter, which is typically named request. Note that the name of the view function doesnt matter; it doesnt have to be named in a certain way in order for Django to recognize it. Were calling it current_datetime here, because that name clearly indicates what it does. The view returns an HttpResponse object that contains the generated response. Each view function is responsible for returning an HttpResponse object. (There are exceptions, but well get to those later.) Djangos Time Zone Django includes a TIME_ZONE setting that defaults to America/Chicago. This probably isnt where you live, so you might want to change it in your settings le.
There isnt a specialized subclass for every possible HTTP response code, since many of them arent going to be that common. However, as documented in the HttpResponse documentation, you can also pass the HTTP status code into the constructor for HttpResponse to create a return class for any status code you like. For example:
def my_view(request): # ... # Return a "created" (201) response code. return HttpResponse(status=201)
Because 404 errors are by far the most common HTTP error, theres an easier way to handle those errors.
140
The Http404 exception When you return an error such as HttpResponseNotFound, youre responsible for dening the HTML of the resulting error page:
return HttpResponseNotFound(<h1>Page not found</h1>)
For convenience, and because its a good idea to have a consistent 404 error page across your site, Django provides an Http404 exception. If you raise Http404 at any point in a view function, Django will catch it and return the standard error page for your application, along with an HTTP error code 404. Example usage:
from django.http import Http404 def detail(request, poll_id): try: p = Poll.objects.get(pk=poll_id) except Poll.DoesNotExist: raise Http404 return render_to_response(polls/detail.html, {poll: p})
In order to use the Http404 exception to its fullest, you should create a template that is displayed when a 404 error is raised. This template should be called 404.html and located in the top level of your template tree.
Behind the scenes, Django determines the 404 view by looking for handler404. By default, URLconfs contain the following line:
from django.conf.urls.defaults import *
That takes care of setting handler404 in the can see in django/conf/urls/defaults.py, django.views.defaults.page_not_found by default. Three things to note about 404 views:
is
As set
you to
The 404 view is also called if Django doesnt nd a match after checking every regular expression in the URLconf.
141
If you dont dene your own 404 view and simply use the default, which is recommended you still have one obligation: you must create a 404.html template in the root of your template directory. The default 404 view will use that template for all 404 errors. The default 404 view will pass one variable to the template: request_path, which is the URL that resulted in the 404. The 404 view is passed a RequestContext and will have access to variables supplied by your TEMPLATE_CONTEXT_PROCESSORS setting (e.g., MEDIA_URL). If DEBUG is set to True (in your settings module), then your 404 view will never be used, and the traceback will be displayed instead. The 500 (server error) view Similarly, Django executes special-case behavior in the case of runtime errors in view code. If a view results in an exception, Django will, by default, call the view django.views.defaults.server_error, which loads and renders the template 500.html. This means you need to dene a 500.html template in your root template directory. This template will be used for all server errors. The default 500 view passes no variables to this template and is rendered with an empty Context to lessen the chance of additional errors. This server_error view should sufce for 99% of Web applications, but if you want to override the view, you can specify handler500 in your URLconf, like so:
handler500 = mysite.views.my_custom_error_view
Behind the scenes, Django determines the error view by looking for handler500. By default, URLconfs contain the following line:
from django.conf.urls.defaults import *
That takes care of setting handler500 in the can see in django/conf/urls/defaults.py, django.views.defaults.server_error by default.
is
As set
you to
142
A view handling this form will receive the le data in request.FILES, which is a dictionary containing a key for each FileField (or ImageField, or other FileField subclass) in the form. So the data from the above form would be accessible as request.FILES[file]. Note that request.FILES will only contain data if the request method was POST and the <form> that posted the request has the attribute enctype="multipart/form-data". Otherwise, request.FILES will be empty. Most of the time, youll simply pass the le data from request into the form as described in Binding uploaded les to a form. This would look something like:
from django.http import HttpResponseRedirect from django.shortcuts import render_to_response # Imaginary function to handle an uploaded file. from somewhere import handle_uploaded_file def upload_file(request): if request.method == POST: form = UploadFileForm(request.POST, request.FILES) if form.is_valid(): handle_uploaded_file(request.FILES[file]) return HttpResponseRedirect(/success/url/) else: form = UploadFileForm() return render_to_response(upload.html, {form: form})
Notice that we have to pass request.FILES into the forms constructor; this is how le data gets bound into a form. Handling uploaded les The nal piece of the puzzle is handling the actual le data from request.FILES. Each entry in this dictionary is an UploadedFile object a simple wrapper around an uploaded le. Youll usually use one of these methods to access the uploaded content: UploadedFile.read() Read the entire uploaded data from the le. Be careful with this method: if the uploaded le is huge it can overwhelm your system if you try to read it into memory. Youll probably want to use chunks() instead; see below. UploadedFile.multiple_chunks() Returns True if the uploaded le is big enough to require reading in multiple chunks. By default this will be any le larger than 2.5 megabytes, but thats congurable; see below. UploadedFile.chunks() A generator returning chunks of the le. If multiple_chunks() is True, you should use this method in a loop instead of read(). In practice, its often easiest simply to use chunks() all the time; see the example below. UploadedFile.name The name of the uploaded le (e.g. my_file.txt). UploadedFile.size The size, in bytes, of the uploaded le. There are a few other methods and attributes available on UploadedFile objects; see UploadedFile objects for a complete reference. Putting it all together, heres a common way you might handle an uploaded le:
def handle_uploaded_file(f): destination = open(some/file/name.txt, wb+) for chunk in f.chunks():
143
destination.write(chunk) destination.close()
Looping over UploadedFile.chunks() instead of using read() ensures that large les dont overwhelm your systems memory. Where uploaded data is stored Before you save uploaded les, the data needs to be stored somewhere. By default, if an uploaded le is smaller than 2.5 megabytes, Django will hold the entire contents of the upload in memory. This means that saving the le involves only a read from memory and a write to disk and thus is very fast. However, if an uploaded le is too large, Django will write the uploaded le to a temporary le stored in your systems temporary directory. On a Unix-like platform this means you can expect Django to generate a le called something like /tmp/tmpzfp6I6.upload. If an upload is large enough, you can watch this le grow in size as Django streams the data onto disk. These specics 2.5 megabytes; /tmp; etc. are simply reasonable defaults. Read on for details on how you can customize or completely replace upload behavior. Changing upload handler behavior Three settings control Djangos le upload behavior: FILE_UPLOAD_MAX_MEMORY_SIZE The maximum size, in bytes, for les that will be uploaded into memory. Files larger than FILE_UPLOAD_MAX_MEMORY_SIZE will be streamed to disk. Defaults to 2.5 megabytes. FILE_UPLOAD_TEMP_DIR The directory where FILE_UPLOAD_MAX_MEMORY_SIZE will be stored. uploaded les larger than
Defaults to your systems standard temporary directory (i.e. /tmp on most Unix-like systems). FILE_UPLOAD_PERMISSIONS The numeric mode (i.e. 0644) to set newly uploaded les to. For more information about what these modes mean, see the documentation for os.chmod If this isnt given or is None, youll get operating-system dependent behavior. On most platforms, temporary les will have a mode of 0600, and les saved from memory will be saved using the systems standard umask. Warning: If youre not familiar with le modes, please note that the leading 0 is very important: it indicates an octal number, which is the way that modes must be specied. If you try to use 644, youll get totally incorrect behavior. Always prex the mode with a 0. FILE_UPLOAD_HANDLERS The actual handlers for uploaded les. Changing this setting allows complete customization even replacement of Djangos upload process. See upload handlers, below, for details. Defaults to:
("django.core.files.uploadhandler.MemoryFileUploadHandler", "django.core.files.uploadhandler.TemporaryFileUploadHandler",)
Which means try to upload to memory rst, then fall back to temporary les.
144
However, unlike standard Python les, UploadedFile only understands \n (also known as Unix-style) line endings. If you know that you need to handle uploaded les with different line endings, youll need to do so in your view.
Together the MemoryFileUploadHandler and TemporaryFileUploadHandler provide Djangos default le upload behavior of reading small les into memory and large ones onto disk. You can write custom handlers that customize how Django handles les. You could, for example, use custom handlers to enforce user-level quotas, compress data on the y, render progress bars, and even send data to another storage location directly without storing it locally. Modifying upload handlers on the y Sometimes particular views require different upload behavior. In these cases, you can override upload handlers on a per-request basis by modifying request.upload_handlers. By default, this list will contain the upload handlers given by FILE_UPLOAD_HANDLERS, but you can modify the list as you would any other list. For instance, suppose youve written a ProgressBarUploadHandler that provides feedback on upload progress to some sort of AJAX widget. Youd add this handler to your upload handlers like this:
request.upload_handlers.insert(0, ProgressBarUploadHandler())
Youd probably want to use list.insert() in this case (instead of append()) because a progress bar handler would need to run before any other handlers. Remember, the upload handlers are processed in order. If you want to replace the upload handlers completely, you can just assign a new list:
145
request.upload_handlers = [ProgressBarUploadHandler()]
Note: You can only modify upload handlers before accessing request.POST or request.FILES it doesnt make sense to change upload handlers after upload handling has already started. If you try to modify request.upload_handlers after reading from request.POST or request.FILES Django will throw an error. Thus, you should always modify uploading handlers as early in your view as possible. Writing custom upload handlers All le upload handlers should be subclasses of django.core.files.uploadhandler.FileUploadHandler. You can dene upload handlers wherever you wish.
Required methods
Custom le upload handlers must dene the following methods: FileUploadHandler.receive_data_chunk(self, raw_data, start) Receives a chunk of data from the le upload. raw_data is a byte string containing the uploaded data. start is the position in the le where this raw_data chunk begins. The data you return will get fed into the subsequent upload handlers receive_data_chunk methods. In this way, one handler can be a lter for other handlers. Return None from receive_data_chunk to sort-circuit remaining upload handlers from getting this chunk.. This is useful if youre storing the uploaded data yourself and dont want future handlers to store a copy of the data. If you raise a StopUpload or a SkipFile exception, the upload will abort or the le will be completely skipped. FileUploadHandler.file_complete(self, file_size) Called when a le has nished uploading. The handler should return an UploadedFile object that will be stored in request.FILES. Handlers may also return None to indicate that the UploadedFile object should come from subsequent upload handlers.
Optional methods
Custom upload handlers may also dene any of the following optional methods or attributes: FileUploadHandler.chunk_size Size, in bytes, of the chunks Django should store into memory and feed into the handler. That is, this attribute controls the size of chunks fed into FileUploadHandler.receive_data_chunk. For maximum performance the chunk sizes should be divisible by 4 and should not exceed 2 GB (231 bytes) in size. When there are multiple chunk sizes provided by multiple handlers, Django will use the smallest chunk size dened by any handler. The default is 64*210 bytes, or 64 KB.
146
FileUploadHandler.new_file(self, field_name, file_name, content_type, content_length, chars Callback signaling that a new le upload is starting. This is called before any data has been fed to any upload handlers. field_name is a string name of the le <input> eld. file_name is the unicode lename that was provided by the browser. content_type is the MIME type provided by the browser E.g. image/jpeg. content_length is the length of the image given by the browser. Sometimes this wont be provided and will be None., None otherwise. charset is the character set (i.e. utf8) given by the browser. Like content_length, this sometimes wont be provided. This method may raise a StopFutureHandlers exception to prevent future handlers from handling this le. FileUploadHandler.upload_complete(self) Callback signaling that the entire upload (all les) has completed.
FileUploadHandler.handle_raw_input(self, input_data, META, content_length, boundary, encodi Allows the handler to completely override the parsing of the raw HTTP input. input_data is a le-like object that supports read()-ing. META is the same object as request.META. content_length is the length of the data in input_data. Dont read more than content_length bytes from input_data. boundary is the MIME boundary for this request. encoding is the encoding of the request. Return None if you want upload handling to continue, or a tuple of (POST, FILES) if you want to return the new data structures suitable for the request directly.
10.4.1 render_to_response
render_to_response(template, [dictionary], [context_instance], [mimetype]) Renders a given template with a given context dictionary and returns an HttpResponse object with that rendered text. Required arguments template The full name of a template to use or sequence of template names.
147
Optional arguments dictionary A dictionary of values to add to the template context. By default, this is an empty dictionary. If a value in the dictionary is callable, the view will call it just before rendering the template. context_instance The context instance to render the template with. By default, the template will be rendered with a Context instance (lled with values from dictionary). If you need to use context processors, render the template with a RequestContext instance instead. Your code might look something like this:
return render_to_response(my_template.html, my_data_dictionary, context_instance=RequestContext(request))
mimetype New in version 1.0: Please, see the release notes The MIME type to use for the resulting document. Defaults to the value of the DEFAULT_CONTENT_TYPE setting. Example The following example renders application/xhtml+xml: the template myapp/index.html with the MIME type
from django.shortcuts import render_to_response def my_view(request): # View code here... return render_to_response(myapp/index.html, {"foo": "bar"}, mimetype="application/xhtml+xml")
10.4.2 redirect
redirect(to, [permanent=False], *args, **kwargs) New in version 1.1: Please, see the release notes Returns an HttpResponseRedirect to the apropriate URL for the arguments passed. The arguments could be: A model: the models get_absolute_url() function will be called. A view name, possibly with arguments: urlresolvers.reverse() will be used to reverse-resolve the name. A URL, which will be used as-is for the redirect location. By default issues a temporary redirect; pass permanent=True to issue a permanent redirect 148 Chapter 10. Handling HTTP requests
Examples You can use the redirect() function in a number of ways. 1. By passing some object; that objects get_absolute_url() method will be called to gure out the redirect URL:
def my_view(request): ... object = MyModel.objects.get(...) return redirect(object)
2. By passing the name of a view and optionally some positional or keyword arguments; the URL will be reverse resolved using the reverse() method:
def my_view(request): ... return redirect(some-view-name, foo=bar)
By default, redirect() returns a temporary redirect. All of the above forms accept a permanent argument; if set to True a permanent redirect will be returned:
def my_view(request): ... object = MyModel.objects.get(...) return redirect(object, permanent=True)
10.4.3 get_object_or_404
get_object_or_404(klass, *args, **kwargs) Calls get() on a given model manager, but it raises django.http.Http404 instead of the models DoesNotExist exception. Required arguments klass A Model, Manager or QuerySet instance from which to get the object. **kwargs Lookup parameters, which should be in the format accepted by get() and filter().
149
Example The following example gets the object with the primary key of 1 from MyModel:
from django.shortcuts import get_object_or_404 def my_view(request): my_object = get_object_or_404(MyModel, pk=1)
Note: As with get(), an MultipleObjectsReturned exception will be raised if more than one object is found.
10.4.4 get_list_or_404
get_list_or_404(klass, *args, **kwargs) Returns the result of filter() on a given model manager, raising django.http.Http404 if the resulting list is empty. Required arguments klass A Model, Manager or QuerySet instance from which to get the object. **kwargs Lookup parameters, which should be in the format accepted by get() and filter(). Example The following example gets all published objects from MyModel:
from django.shortcuts import get_list_or_404 def my_view(request): my_objects = get_list_or_404(MyModel, published=True)
150
10.6 Middleware
Middleware is a framework of hooks into Djangos request/response processing. Its a light, low-level plugin system for globally altering Djangos input and/or output. Each middleware component is responsible for doing some specic function. For example, Django includes a middleware component, XViewMiddleware, that adds an "X-View" HTTP header to every response to a HEAD request. This document explains how middleware works, how you activate middleware, and how to write your own middleware. Django ships with some built-in middleware you can use right out of the box; theyre documented in the built-in middleware reference.
During the request phases (process_request() and process_view() middleware), Django applies middleware in the order its dened in MIDDLEWARE_CLASSES, top-down. During the response phases (process_response() and process_exception() middleware), the classes are applied in reverse order, from the bottom up. You can think of it like an onion: each middleware class is a layer that wraps the view:
151
A Django installation doesnt require any middleware e.g., MIDDLEWARE_CLASSES can be empty, if youd like but its strongly suggested that you at least use CommonMiddleware.
152
process_view process_view(self, request, view_func, view_args, view_kwargs) request is an HttpRequest object. view_func is the Python function that Django is about to use. (Its the actual function object, not the name of the function as a string.) view_args is a list of positional arguments that will be passed to the view, and view_kwargs is a dictionary of keyword arguments that will be passed to the view. Neither view_args nor view_kwargs include the rst view argument (request). process_view() is called just before Django calls the view. It should return either None or an HttpResponse object. If it returns None, Django will continue processing this request, executing any other process_view() middleware and, then, the appropriate view. If it returns an HttpResponse object, Django wont bother calling ANY other request, view or exception middleware, or the appropriate view; itll return that HttpResponse. Response middleware is always called on every response. process_response process_response(self, request, response) request is an HttpRequest object. response is the HttpResponse object returned by a Django view. process_response() must return an HttpResponse object. It could alter the given response, or it could create and return a brand-new HttpResponse. Unlike the process_request() and process_view() methods, the process_response() method is always called, even if the process_request() and process_view() methods of the same middleware class were skipped because an earlier middleware method returned an HttpResponse (this means that your process_response() method cannot rely on setup done in process_request(), for example). In addition, during the response phase the classes are applied in reverse order, from the bottom up. This means classes dened at the end of MIDDLEWARE_CLASSES will be run rst. process_exception process_exception(self, request, exception) request is an HttpRequest object. exception is an Exception object raised by the view function. Django calls process_exception() when a view raises an exception. process_exception() should return either None or an HttpResponse object. If it returns an HttpResponse object, the response will be returned to the browser. Otherwise, default exception handling kicks in. Again, middleware are run in reverse order during the response phase, which includes process_exception. If an exception middleware return a response, the middleware classes above that middleware will not be called at all. __init__ Most middleware classes wont need an initializer since middleware classes are essentially placeholders for the process_* methods. If you do need some global state you may use __init__ to set up. However, keep in mind a couple of caveats: Django initializes your middleware without any arguments, so you cant dene __init__ as requiring any arguments. Unlike the process_* methods which get called once per request, __init__ gets called only once, when the web server starts up.
10.6. Middleware
153
154
Using cached sessions For better performance, you may want to use a cache-based session backend. Changed in version 1.1: Django 1.0 did not include the cached_db session backend. To store session data using Djangos cache system, youll rst need to make sure youve congured your cache; see the cache documentation for details. Warning: You should only use cache-based sessions if youre using the Memcached cache backend. The localmemory cache backend doesnt retain data long enough to be a good choice, and itll be faster to use le or database sessions directly instead of sending everything through the le or database cache backends. Once your cache is congured, youve got two choices for how to store data in the cache: Set SESSION_ENGINE to "django.contrib.sessions.backends.cache" for a simple caching session store. Session data will be stored directly your cache. However, session data may not be persistent: cached data can be evicted if the cache lls up or if the cache server is restarted. For persistent, cached data, set SESSION_ENGINE to "django.contrib.sessions.backends.cached_db". This uses a write-through cache every write to the cache will also be written to the database. Session reads only use the database if the data is not already in the cache. Both session stores are quite fast, but the simple cache is faster because it disregards persistence. In most cases, the cached_db backend will be fast enough, but if you need that last bit of performance, and are willing to let session data be expunged from time to time, the cache backend is for you. If you use the cached_db session backend, you also need to follow the conguration instructions for the using database-backed sessions. Using le-based sessions To use le-based sessions, set the SESSION_ENGINE setting to "django.contrib.sessions.backends.file". You might also want to set the SESSION_FILE_PATH setting (which defaults to output from tempfile.gettempdir(), most likely /tmp) to control where Django stores session les. Be sure to check that your Web server has permissions to read and write to this location.
155
get(key, default=None) Example: fav_color = request.session.get(fav_color, red) keys() items() setdefault() clear() New in version 1.0: setdefault() and clear() are new in this version. It also has these methods: flush() New in version 1.0: Please, see the release notes Delete the current session data from the session and regenerate the session key value that is sent back to the user in the cookie. This is used if you want to ensure that the previous session data cant be accessed again from the users browser (for example, the django.contrib.auth.logout() function calls it). set_test_cookie() Sets a test cookie to determine whether the users browser supports cookies. Due to the way cookies work, you wont be able to test this until the users next page request. See Setting test cookies below for more information. test_cookie_worked() Returns either True or False, depending on whether the users browser accepted the test cookie. Due to the way cookies work, youll have to call set_test_cookie() on a previous, separate page request. See Setting test cookies below for more information. delete_test_cookie() Deletes the test cookie. Use this to clean up after yourself. set_expiry(value) New in version 1.0: Please, see the release notes Sets the expiration time for the session. You can pass a number of different values: If value is an integer, the session will expire after that many seconds of inactivity. For example, calling request.session.set_expiry(300) would make the session expire in 5 minutes. If value is a datetime or timedelta object, the session will expire at that specic date/time. If value is 0, the users session cookie will expire when the users Web browser is closed. If value is None, the session reverts to using the global session expiry policy. Reading a session is not considered activity for expiration purposes. Session expiration is computed from the last time the session was modied. get_expiry_age() New in version 1.0: Please, see the release notes Returns the number of seconds until this session expires. For sessions with no custom expiration (or those set to expire at browser close), this will equal settings.SESSION_COOKIE_AGE. get_expiry_date() New in version 1.0: Please, see the release notes Returns the date this session will expire. For sessions with no custom expiration (or those set to expire at browser close), this will equal the date settings.SESSION_COOKIE_AGE seconds from now. get_expire_at_browser_close() New in version 1.0: Please, see the release notes Returns either True or False, depending on whether the users session cookie will expire when the users Web browser is closed. You can edit request.session at any point in your view. You can edit it multiple times.
156
Session object guidelines Use normal Python strings as dictionary keys on request.session. This is more of a convention than a hard-and-fast rule. Session dictionary keys that begin with an underscore are reserved for internal use by Django. Dont override request.session with a new object, and dont access or set its attributes. Use it like a Python dictionary. Examples This simplistic view sets a has_commented variable to True after a user posts a comment. It doesnt let a user post a comment more than once:
def post_comment(request, new_comment): if request.session.get(has_commented, False): return HttpResponse("Youve already commented.") c = comments.Comment(comment=new_comment) c.save() request.session[has_commented] = True return HttpResponse(Thanks for your comment!)
The standard django.contrib.auth.logout() function actually does a bit more than this to prevent inadvertent data leakage. It calls request.session.flush(). We are using this example as a demonstration of how to work with session objects, not as a full logout() implementation.
157
Its good practice to use delete_test_cookie() to clean up after yourself. Do this after youve veried that the test cookie worked. Heres a typical usage example:
def login(request): if request.method == POST: if request.session.test_cookie_worked(): request.session.delete_test_cookie() return HttpResponse("Youre logged in.") else: return HttpResponse("Please enable cookies and try again.") request.session.set_test_cookie() return render_to_response(foo/login_form.html)
If youre using the django.contrib.sessions.backends.db backend, each session is just a normal Django model. The Session model is dened in django/contrib/sessions/models.py. Because its a normal model, you can access sessions using the normal Django database API:
>>> from django.contrib.sessions.models import Session >>> s = Session.objects.get(pk=2b1189a188b44ad18c35e113ac6ceead) >>> s.expire_date datetime.datetime(2005, 8, 20, 13, 35, 12)
Note that youll need to call get_decoded() to get the session dictionary. This is necessary because the dictionary is stored in an encoded format:
>>> s.session_data KGRwMQpTJ19hdXRoX3VzZXJfaWQnCnAyCkkxCnMuMTExY2ZjODI2Yj... >>> s.get_decoded() {user_id: 42}
158
# Session is modified. request.session[foo] = {} # Gotcha: Session is NOT modified, because this alters # request.session[foo] instead of request.session. request.session[foo][bar] = baz
In the last case of the above example, we can tell the session object explicitly that it has been modied by setting the modified attribute on the session object:
request.session.modified = True
To change this default behavior, set the SESSION_SAVE_EVERY_REQUEST setting to True. If SESSION_SAVE_EVERY_REQUEST is True, Django will save the session to the database on every single request. Note that the session cookie is only sent when a session has been created or modied. SESSION_SAVE_EVERY_REQUEST is True, the session cookie will be sent on every request. Similarly, the expires part of a session cookie is updated each time the session cookie is sent. If
10.7.9 Settings
A few Django settings give you control over session behavior:
159
SESSION_ENGINE New in version 1.0: Please, see the release notesChanged in version 1.1: The cached_db backend was added Default: django.contrib.sessions.backends.db Controls where Django stores session data. Valid values are: django.contrib.sessions.backends.db django.contrib.sessions.backends.file django.contrib.sessions.backends.cache django.contrib.sessions.backends.cached_db See conguring the session engine for more details. SESSION_FILE_PATH New in version 1.0: Please, see the release notes Default: /tmp/ If youre using le-based session storage, this sets the directory in which Django will store session data. SESSION_COOKIE_AGE Default: 1209600 (2 weeks, in seconds) The age of session cookies, in seconds. SESSION_COOKIE_DOMAIN Default: None The domain to use for session cookies. Set this to a string such as ".lawrence.com" (note the leading dot!) for cross-domain cookies, or use None for a standard domain cookie. SESSION_COOKIE_NAME Default: sessionid The name of the cookie to use for sessions. This can be whatever you want. SESSION_COOKIE_PATH New in version 1.0: Please, see the release notes Default: / The path set on the session cookie. This should either match the URL path of your Django installation or be parent of that path. This is useful if you have multiple Django instances running under the same hostname. They can use different cookie paths, and each instance will only see its own session cookie.
160
SESSION_COOKIE_SECURE Default: False Whether to use a secure cookie for the session cookie. If this is set to True, the cookie will be marked as secure, which means browsers may ensure that the cookie is only sent under an HTTPS connection. SESSION_EXPIRE_AT_BROWSER_CLOSE Default: False Whether to expire the session when the user closes his or her browser. See Browser-length sessions vs. persistent sessions above. SESSION_SAVE_EVERY_REQUEST Default: False Whether to save the session data on every request. If this is False (default), then the session data will only be saved if it has been modied that is, if any of its dictionary values have been assigned or deleted.
161
162
CHAPTER
ELEVEN
11.1 Overview
The library deals with these concepts: Widget A class that corresponds to an HTML form widget, e.g. <input type="text"> or <textarea>. This handles rendering of the widget as HTML. Field A class that is responsible for doing validation, e.g. an EmailField that makes sure its data is a valid e-mail address. Form A collection of elds that knows how to validate itself and display itself as HTML. Form Media The CSS and JavaScript resources that are required to render a form. The library is decoupled from the other Django components, such as the database layer, views and templates. It relies only on Django settings, a couple of django.utils helper functions and Djangos internationalization hooks (but youre not required to be using internationalization features to use this library).
163
from django import forms class ContactForm(forms.Form): subject = forms.CharField(max_length=100) message = forms.CharField() sender = forms.EmailField() cc_myself = forms.BooleanField(required=False)
A form is composed of Field objects. In this case, our form has four elds: subject, message, sender and cc_myself. CharField, EmailField and BooleanField are just three of the available eld types; a full list can be found in Form elds. If your form is going to be used to directly add or edit a Django model, you can use a ModelForm to avoid duplicating your model description.
There are three code paths here: 1. If the form has not been submitted, an unbound instance of ContactForm is created and passed to the template. 2. If the form has been submitted, a bound instance of the form is created using request.POST. If the submitted data is valid, it is processed and the user is re-directed to a thanks page. 3. If the form has been submitted but is invalid, the bound form instance is passed on to the template. Changed in version 1.0: The cleaned_data attribute was called clean_data in earlier releases. The distinction between bound and unbound forms is important. An unbound form does not have any data associated with it; when rendered to the user, it will be empty or will contain default values. A bound form does have submitted data, and hence can be used to tell if that data is valid. If an invalid bound form is rendered it can include inline error messages telling the user where they went wrong. See Bound and unbound forms for further information on the differences between bound and unbound forms.
164
The form only outputs its own elds; it is up to you to provide the surrounding <form> tags and the submit button. form.as_p will output the form with each form eld and accompanying label wrapped in a paragraph. Heres the output for our example template:
<form action="/contact/" method="post"> <p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></p> <p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></p> <p><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></p> <p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></p> <input type="submit" value="Submit" /> </form>
Note that each form eld has an ID attribute set to id_<field-name>, which is referenced by the accompanying label tag. This is important for ensuring forms are accessible to assistive technology such as screen reader software. You can also customize the way in which labels and ids are generated.
165
You can also use form.as_table to output table rows (youll need to provide your own <table> tags) and form.as_ul to output list items.
Each named form-eld can be output to the template using {{ form.name_of_field }}, which will produce the HTML needed to display the form widget. Using {{ form.name_of_field.errors }} displays a list of form errors, rendered as an unordered list. This might look like:
<ul class="errorlist"> <li>Sender is required.</li> </ul>
The list has a CSS class of errorlist to allow you to style its appearance. If you wish to further customize the display of errors you can do so by looping over them:
{% if form.subject.errors %} <ol> {% for error in form.subject.errors %} <li><strong>{{ error|escape }}</strong></li> {% endfor %} </ol> {% endif %}
<form action="/contact/" method="post"> {% for field in form %} <div class="fieldWrapper"> {{ field.errors }} {{ field.label_tag }}: {{ field }} </div> {% endfor %} <p><input type="submit" value="Send message" /></p> </form>
Within this loop, {{ field }} is an instance of BoundField. BoundField also has the following attributes, which can be useful in your templates: {{ field.label }} The label of the eld, e.g. E-mail address. {{ field.label_tag }} The elds label wrapped in the appropriate HTML <label> tag, e.g. <label for="id_email">E-mail address</label> {{ field.html_name }} The name of the eld that will be used in the input elements name eld. This takes the form prex into account, if it has been set. {{ field.help_text }} Any help text that has been associated with the eld. {{ field.errors }} Outputs a <ul class="errorlist"> containing any validation errors corresponding to this eld. You can customize the presentation of the errors with a {% for error in field.errors %} loop. In this case, each object in the loop is a simple string containing the error message. field.is_hidden This attribute is True if the form eld is a hidden eld and False otherwise. Its not particularly useful as a template variable, but could be useful in conditional tests such as:
{% if field.is_hidden %} {# Do something special #} {% endif %}
Looping over hidden and visible elds If youre manually laying out a form in a template, as opposed to relying on Djangos default form layout, you might want to treat <input type="hidden"> elds differently than non-hidden elds. For example, because hidden elds dont display anything, putting error messages next to the eld could cause confusion for your users so errors for those elds should be handled differently. Django provides two methods on a form that allow you to loop over the hidden and visible elds independently: hidden_fields() and visible_fields(). Heres a modication of an earlier example that uses these two methods:
<form action="/contact/" method="post"> {% for field in form.visible_fields %} <div class="fieldWrapper"> {# Include the hidden fields in the form #} {% if forloop.first %} {% for hidden in form.hidden_fields %} {{ hidden }} {% endfor %} {% endif %} {{ field.errors }}
167
{{ field.label_tag }}: {{ field }} </div> {% endfor %} <p><input type="submit" value="Send message" /></p> </form>
This example does not handle any errors in the hidden elds. Usually, an error in a hidden eld is a sign of form tampering, since normal form interaction wont alter them. However, you could easily insert some error displays for those form errors, as well. New in version 1.1: The hidden_fields and visible_fields methods are new in Django 1.1.
If the form object passed to a template has a different name within the context, you can alias it using the with tag:
<form action="/comments/add/" method="post"> {% with comment_form as form %} {% include "form_snippet.html" %} {% endwith %} <p><input type="submit" value="Submit comment" /></p> </form>
If you nd yourself doing this often, you might consider creating a custom inclusion tag.
168
In this case, it would be redundant to dene the eld types in your form, because youve already dened the elds in your model. For this reason, Django provides a helper class that let you create a Form class from a Django model. For example:
>>> from django.forms import ModelForm # Create the form class. >>> class ArticleForm(ModelForm): ... class Meta: ... model = Article # Creating a form to add an article. >>> form = ArticleForm() # Creating a form to change an existing article. >>> article = Article.objects.get(pk=1) >>> form = ArticleForm(instance=article)
Field types
The generated Form class will have a form eld for every model eld. Each model eld has a corresponding default form eld. For example, a CharField on a model is represented as a CharField on a form. A model ManyToManyField is represented as a MultipleChoiceField. Here is the full list of conversions:
169
Form eld Not represented in the form IntegerField with min_value set to -9223372036854775808 and max_value set to 9223372036854775807. BooleanField BooleanField CharField CharField with max_length set to the model elds max_length CommaSeparatedIntegerField CharField DateField DateField DateTimeField DateTimeField DecimalField DecimalField EmailField EmailField FileField FileField FilePathField CharField FloatField FloatField ForeignKey ModelChoiceField (see below) ImageField ImageField IntegerField IntegerField IPAddressField IPAddressField ManyToManyField ModelMultipleChoiceField (see below) NullBooleanField CharField PhoneNumberField USPhoneNumberField (from django.contrib.localflavor.us) PositiveIntegerField IntegerField PositiveSmallIntegerField IntegerField SlugField SlugField SmallIntegerField IntegerField TextField CharField with widget=forms.Textarea TimeField TimeField URLField URLField with verify_exists set to the model elds verify_exists XMLField CharField with widget=forms.Textarea New in version 1.0: The FloatField form eld and DecimalField model and form elds are new in Django 1.0.New in version 1.2: The BigIntegerField is new in Django 1.2. As you might expect, the ForeignKey and ManyToManyField model eld types are special cases: ForeignKey is represented by django.forms.ModelChoiceField, which is a ChoiceField whose choices are a model QuerySet. ManyToManyField is represented by django.forms.ModelMultipleChoiceField, which is a MultipleChoiceField whose choices are a model QuerySet. In addition, each generated form eld has attributes set as follows: If the model eld has blank=True, then required is set to False on the form eld. Otherwise, required=True. The form elds label is set to the verbose_name of the model eld, with the rst character capitalized. The form elds help_text is set to the help_text of the model eld. If the model eld has choices set, then the form elds widget will be set to Select, with choices coming from the model elds choices. The choices will normally include the blank choice which is selected by default. If the eld is required, this forces the user to make a selection. The blank choice will not be included if the model eld has blank=False and an explicit default value (the default value will be initially selected instead). Finally, note that you can override the form eld used for a given model eld. See Overriding the default eld types or widgets below.
170
A full example
Consider this set of models:
from django.db import models from django.forms import ModelForm TITLE_CHOICES = ( (MR, Mr.), (MRS, Mrs.), (MS, Ms.), ) class Author(models.Model): name = models.CharField(max_length=100) title = models.CharField(max_length=3, choices=TITLE_CHOICES) birth_date = models.DateField(blank=True, null=True) def __unicode__(self): return self.name class Book(models.Model): name = models.CharField(max_length=100) authors = models.ManyToManyField(Author) class AuthorForm(ModelForm): class Meta: model = Author class BookForm(ModelForm): class Meta: model = Book
With these models, the ModelForm subclasses above would be roughly equivalent to this (the only difference being the save() method, which well discuss in a moment.):
class AuthorForm(forms.Form): name = forms.CharField(max_length=100) title = forms.CharField(max_length=3, widget=forms.Select(choices=TITLE_CHOICES)) birth_date = forms.DateField(required=False) class BookForm(forms.Form): name = forms.CharField(max_length=100) authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all())
171
Note that save() will raise a ValueError if the data in the form doesnt validate i.e., if form.errors. This save() method accepts an optional commit keyword argument, which accepts either True or False. If you call save() with commit=False, then it will return an object that hasnt yet been saved to the database. In this case, its up to you to call save() on the resulting model instance. This is useful if you want to do custom processing on the object before saving it, or if you want to use one of the specialized model saving options. commit is True by default. Another side effect of using commit=False is seen when your model has a many-to-many relation with another model. If your model has a many-to-many relation and you specify commit=False when you save a form, Django cannot immediately save the form data for the many-to-many relation. This is because it isnt possible to save manyto-many data for an instance until the instance exists in the database. To work around this problem, every time you save a form using commit=False, Django adds a save_m2m() method to your ModelForm subclass. After youve manually saved the instance produced by the form, you can invoke save_m2m() to save the many-to-many form data. For example:
# Create a form instance with POST data. >>> f = AuthorForm(request.POST) # Create, but dont save the new author instance. >>> new_author = f.save(commit=False) # Modify the author in some way. >>> new_author.some_field = some_value # Save the new instance. >>> new_author.save() # Now, save the many-to-many data for the form. >>> f.save_m2m()
Calling save_m2m() is only required if you use save(commit=False). When you use a simple save() on a form, all data including many-to-many data is saved without the need for any additional method calls. For example: 172 Chapter 11. Working with forms
# Create a form instance with POST data. >>> a = Author() >>> f = AuthorForm(request.POST, instance=a) # Create and save the new author instance. Theres no need to do anything else. >>> new_author = f.save()
Other than the save() and save_m2m() methods, a ModelForm works exactly the same way as any other forms form. For example, the is_valid() method is used to check for validity, the is_multipart() method is used to determine whether a form requires multipart le upload (and hence whether request.FILES must be passed to the form), etc. See Binding uploaded les to a form for more information.
Since the Author model has only 3 elds, name, title, and birth_date, the forms above will contain exactly the same elds. Note: If you specify fields or exclude when creating a form with ModelForm, then the elds that are not in the resulting form will not be set by the forms save() method. Django will prevent any attempt to save an incomplete model, so if the model does not allow the missing elds to be empty, and does not provide a default value for the missing elds, any attempt to save() a ModelForm with missing elds will fail. To avoid this failure, you must instantiate your model with initial values for the missing, but required elds:
author = Author(title=Mr) form = PartialAuthorForm(request.POST, instance=author) form.save()
Alternatively, you can use save(commit=False) and manually set any extra required elds:
173
See the section on saving forms for more details on using save(commit=False).
The widgets dictionary accepts either widget instances (e.g., Textarea(...)) or classes (e.g., Textarea). If you want to further customize a eld including its type, label, etc. you can do this by declaratively specifying elds like you would in a regular Form. Declared elds will override the default ones generated by using the model attribute. For example, if you wanted to use MyDateFormField for the pub_date eld, you could do the following:
class ArticleForm(ModelForm): pub_date = MyDateFormField() class Meta: model = Article
If you want to override a elds default label, then specify the label parameter when declaring the form eld:
>>> class ArticleForm(ModelForm): ... pub_date = DateField(label=Publication date) ... ... class Meta: ... model = Article
Note: If you explicitly instantiate a form eld like this, Django assumes that you want to completely dene its behavior; therefore, default attributes (such as max_length or required) are not drawn from the corresponding model. If you want to maintain the behavior specied in the model, you must set the relevant arguments explicitly when declaring the form eld.
174
and you want to do some custom validation for headline, while keeping the blank and help_text values as specied, you might dene ArticleForm like this:
class ArticleForm(ModelForm): headline = MyFormField(max_length=200, required=False, help_text="Use puns liberally") class Meta: model = Article
See the form eld documentation for more information on elds and their arguments.
the author eld would be rendered rst. If we wanted the title eld to be rendered rst, we could specify the following ModelForm:
>>> class BookForm(ModelForm): ... class Meta: ... model = Book ... fields = [title, author]
175
Form inheritance
As with basic forms, you can extend and reuse ModelForms by inheriting them. This is useful if you need to declare extra elds or extra methods on a parent class for use in a number of forms derived from models. For example, using the previous ArticleForm class:
>>> class EnhancedArticleForm(ArticleForm): ... def clean_pub_date(self): ... ...
This creates a form that behaves identically to ArticleForm, except theres some extra validation and cleaning for the pub_date eld. You can also subclass the parents Meta inner class if you want to change the Meta.fields or Meta.excludes lists:
>>> class RestrictedArticleForm(EnhancedArticleForm): ... class Meta(ArticleForm.Meta): ... exclude = [body]
This adds the extra method from the EnhancedArticleForm and modies the original ArticleForm.Meta to remove one eld. There are a couple of things to note, however. Normal Python name resolution rules apply. If you have multiple base classes that declare a Meta inner class, only the rst one will be used. This means the childs Meta, if it exists, otherwise the Meta of the rst parent, etc. For technical reasons, a subclass cannot inherit from both a ModelForm and a Form simultaneously. Chances are these notes wont affect you unless youre trying to do something tricky with subclassing.
This will create a formset that is capable of working with the data associated with the Author model. It works just like a regular formset:
176
>>> formset = AuthorFormSet() >>> print formset <input type="hidden" name="form-TOTAL_FORMS" value="1" id="id_form-TOTAL_FORMS" /><input type="hidden <tr><th><label for="id_form-0-name">Name:</label></th><td><input id="id_form-0-name" type="text" name <tr><th><label for="id_form-0-title">Title:</label></th><td><select name="form-0-title" id="id_form-0 <option value="" selected="selected">---------</option> <option value="MR">Mr.</option> <option value="MRS">Mrs.</option> <option value="MS">Ms.</option> </select></td></tr> <tr><th><label for="id_form-0-birth_date">Birth date:</label></th><td><input type="text" name="form-0
Note: modelformset_factory uses formset_factory to generate formsets. This means that a model formset is just an extension of a basic formset that knows how to interact with a particular model.
If you want to return a formset that doesnt include any pre-existing instances of the model, you can specify an empty QuerySet:
>>> AuthorFormSet(queryset=Author.objects.none())
Using fields restricts the formset to use only the given elds. Alternatively, you can take an opt-out approach, specifying which elds to exclude:
>>> AuthorFormSet = modelformset_factory(Author, exclude=(birth_date,))
177
The save() method returns the instances that have been saved to the database. If a given instances data didnt change in the bound data, the instance wont be saved to the database and wont be included in the return value (instances, in the above example). Pass commit=False to return the unsaved model instances:
# dont save to the database >>> instances = formset.save(commit=False) >>> for instance in instances: ... # do something with instance ... instance.save()
This gives you the ability to attach data to the instances before saving them to the database. If your formset contains a ManyToManyField, youll also need to call formset.save_m2m() to ensure the many-to-many relationships are saved properly.
If the value of max_num is greater than the number of existing related objects, up to extra additional blank forms will be added to the formset, so long as the total number of forms does not exceed max_num:
>>> AuthorFormSet = modelformset_factory(Author, max_num=4, extra=2) >>> formset = AuthorFormSet(queryset=Author.objects.order_by(name)) >>> for form in formset.forms: ... print form.as_table() <tr><th><label for="id_form-0-name">Name:</label></th><td><input id="id_form-0-name" <tr><th><label for="id_form-1-name">Name:</label></th><td><input id="id_form-1-name" <tr><th><label for="id_form-2-name">Name:</label></th><td><input id="id_form-2-name" <tr><th><label for="id_form-3-name">Name:</label></th><td><input id="id_form-3-name"
Changed in version 1.2: Please, see the release notes A max_num value of None (the default) puts no limit on the number of forms displayed.
178
As you can see, the view logic of a model formset isnt drastically different than that of a normal formset. The only difference is that we call formset.save() to save the data into the database. (This was described above, in Saving objects in the formset.)
Note that we pass the queryset argument in both the POST and GET cases in this example. 11.3. Further topics 179
Second, you can manually render the formset, but let the form deal with itself:
<form method="post" action=""> {{ formset.management_form }} {% for form in formset.forms %} {{ form }} {% endfor %} </form>
When you manually render the forms yourself, be sure to render the management form as shown above. See the management form documentation. Third, you can manually render each eld:
<form method="post" action=""> {{ formset.management_form }} {% for form in formset.forms %} {% for field in form %} {{ field.label_tag }}: {{ field }} {% endfor %} {% endfor %} </form>
If you opt to use this third method and you dont iterate over the elds with a {% for %} loop, youll need to render the primary key eld. For example, if you were rendering the name and age elds of a model:
<form method="post" action=""> {{ formset.management_form }} {% for form in formset.forms %} {{ form.id }} <ul> <li>{{ form.name }}</li> <li>{{ form.age }}</li> </ul> {% endfor %} </form>
Notice how we need to explicitly render {{ form.id }}. This ensures that the model formset, in the POST case, will work correctly. (This example assumes a primary key named id. If youve explicitly dened your own primary key that isnt called id, make sure it gets rendered.) Inline formsets Inline formsets is a small abstraction layer on top of model formsets. These simplify the case of working with related objects via a foreign key. Suppose you have these two models:
180
class Author(models.Model): name = models.CharField(max_length=100) class Book(models.Model): author = models.ForeignKey(Author) title = models.CharField(max_length=100)
If you want to create a formset that allows you to edit books belonging to a particular author, you could do this:
>>> >>> >>> >>> from django.forms.models import inlineformset_factory BookFormSet = inlineformset_factory(Author, Book) author = Author.objects.get(name=uMike Royko) formset = BookFormSet(instance=author)
Notice how we pass instance in both the POST and GET cases.
181
11.3.2 Formsets
A formset is a layer of abstraction to working with multiple forms on the same page. It can be best compared to a data grid. Lets say you have the following form:
>>> from django import forms >>> class ArticleForm(forms.Form): ... title = forms.CharField() ... pub_date = forms.DateField()
You might want to allow the user to create several articles at once. To create a formset out of an ArticleForm you would do:
>>> from django.forms.formsets import formset_factory >>> ArticleFormSet = formset_factory(ArticleForm)
You now have created a formset named ArticleFormSet. The formset gives you the ability to iterate over the forms in the formset and display them as you would with a regular form:
>>> formset = ArticleFormSet() >>> for form in formset.forms: ... print form.as_table() <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub
As you can see it only displayed one empty form. The number of empty forms that is displayed is controlled by the extra parameter. By default, formset_factory denes one extra form; the following example will display two blank forms:
>>> ArticleFormSet = formset_factory(ArticleForm, extra=2)
Using initial data with a formset Initial data is what drives the main usability of a formset. As shown above you can dene the number of extra forms. What this means is that you are telling the formset how many additional forms to show in addition to the number of forms it generates from the initial data. Lets take a look at an example:
>>> ArticleFormSet = formset_factory(ArticleForm, extra=2) >>> formset = ArticleFormSet(initial=[ ... {title: uDjango is now open source, ... pub_date: datetime.date.today()}, ... ])
>>> for form in formset.forms: ... print form.as_table() <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" va <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub <tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" id <tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub <tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id <tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub
There are now a total of three forms showing above. One for the initial data that was passed in and two extra forms. Also note that we are passing in a list of dictionaries as the initial data.
182
See Also: Creating formsets from models with model formsets. Limiting the maximum number of forms The max_num parameter to formset_factory gives you the ability to limit the maximum number of empty forms the formset will display:
>>> ArticleFormSet = formset_factory(ArticleForm, extra=2, max_num=1) >>> formset = ArticleFormset() >>> for form in formset.forms: ... print form.as_table() <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub
Changed in version 1.2: Please, see the release notes If the value of max_num is greater than the number of existing objects, up to extra additional blank forms will be added to the formset, so long as the total number of forms does not exceed max_num. A max_num value of None (the default) puts no limit on the number of forms displayed. Please note that the default value of max_num was changed from 0 to None in version 1.2 to allow 0 as a valid value. Formset validation Validation with a formset is almost identical to a regular Form. There is an is_valid method on the formset to provide a convenient way to validate all forms in the formset:
>>> ArticleFormSet = formset_factory(ArticleForm) >>> formset = ArticleFormSet({}) >>> formset.is_valid() True
We passed in no data to the formset which is resulting in a valid form. The formset is smart enough to ignore extra forms that were not changed. If we provide an invalid article:
>>> data = { ... form-TOTAL_FORMS: u2, ... form-INITIAL_FORMS: u0, ... form-MAX_NUM_FORMS: u, ... form-0-title: uTest, ... form-0-pub_date: u16 June 1904, ... form-1-title: uTest, ... form-1-pub_date: u, # <-- this date is missing but required ... } >>> formset = ArticleFormSet(data) >>> formset.is_valid() False >>> formset.errors [{}, {pub_date: [uThis field is required.]}]
As we can see, formset.errors is a list whose entries correspond to the forms in the formset. Validation was performed for each of the two forms, and the expected error message appears for the second item.
183
It is used to keep track of how many form instances are being displayed. If you are adding new forms via JavaScript, you should increment the count elds in this form as well. The management form is available as an attribute of the formset itself. When rendering a formset in a template, you can include all the management data by rendering {{ my_formset.management_form }} (substituting the name of your formset as appropriate). New in version 1.1: Please, see the release notes
empty_form
BaseFormSet provides an additional attribute empty_form which returns a form instance with a prex of __prefix__ for easier use in dynamic forms with JavaScript.
184
for i in range(0, self.total_form_count()): form = self.forms[i] title = form.cleaned_data[title] if title in titles: raise forms.ValidationError, "Articles in a set must have distinct titles." titles.append(title)
>>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet) >>> data = { ... form-TOTAL_FORMS: u2, ... form-INITIAL_FORMS: u0, ... form-MAX_NUM_FORMS: u, ... form-0-title: uTest, ... form-0-pub_date: u16 June 1904, ... form-1-title: uTest, ... form-1-pub_date: u23 June 1912, ... } >>> formset = ArticleFormSet(data) >>> formset.is_valid() False >>> formset.errors [{}, {}] >>> formset.non_form_errors() [uArticles in a set must have distinct titles.]
The formset clean method is called after all the Form.clean methods have been called. The errors will be found using the non_form_errors() method on the formset. Dealing with ordering and deletion of forms Common use cases with a formset is dealing with ordering and deletion of the form instances. This has been dealt with for you. The formset_factory provides two optional parameters can_order and can_delete that will do the extra work of adding the extra elds and providing simpler ways of getting to that data.
can_order
Default: False Lets create a formset with the ability to order:
>>> ArticleFormSet = formset_factory(ArticleForm, can_order=True) >>> formset = ArticleFormSet(initial=[ ... {title: uArticle #1, pub_date: datetime.date(2008, 5, 10)}, ... {title: uArticle #2, pub_date: datetime.date(2008, 5, 11)}, ... ]) >>> for form in formset.forms: ... print form.as_table() <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" va <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub <tr><th><label for="id_form-0-ORDER">Order:</label></th><td><input type="text" name="form-0-ORDER" va <tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" va <tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub <tr><th><label for="id_form-1-ORDER">Order:</label></th><td><input type="text" name="form-1-ORDER" va <tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id
185
This adds an additional eld to each form. This new eld is named ORDER and is an forms.IntegerField. For the forms that came from the initial data it automatically assigned them a numeric value. Lets look at what will happen when the user changes these values:
>>> data = { ... form-TOTAL_FORMS: u3, ... form-INITIAL_FORMS: u2, ... form-MAX_NUM_FORMS: u, ... form-0-title: uArticle #1, ... form-0-pub_date: u2008-05-10, ... form-0-ORDER: u2, ... form-1-title: uArticle #2, ... form-1-pub_date: u2008-05-11, ... form-1-ORDER: u1, ... form-2-title: uArticle #3, ... form-2-pub_date: u2008-05-01, ... form-2-ORDER: u0, ... } >>> formset = ArticleFormSet(data, initial=[ ... {title: uArticle #1, pub_date: datetime.date(2008, 5, 10)}, ... {title: uArticle #2, pub_date: datetime.date(2008, 5, 11)}, ... ]) >>> formset.is_valid() True >>> for form in formset.ordered_forms: ... print form.cleaned_data {pub_date: datetime.date(2008, 5, 1), ORDER: 0, title: uArticle #3} {pub_date: datetime.date(2008, 5, 11), ORDER: 1, title: uArticle #2} {pub_date: datetime.date(2008, 5, 10), ORDER: 2, title: uArticle #1}
can_delete
Default: False Lets create a formset with the ability to delete:
>>> ArticleFormSet = formset_factory(ArticleForm, can_delete=True) >>> formset = ArticleFormSet(initial=[ ... {title: uArticle #1, pub_date: datetime.date(2008, 5, 10)}, ... {title: uArticle #2, pub_date: datetime.date(2008, 5, 11)}, ... ]) >>> for form in formset.forms: .... print form.as_table() <input type="hidden" name="form-TOTAL_FORMS" value="3" id="id_form-TOTAL_FORMS" /><input type="hidden <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" va <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub <tr><th><label for="id_form-0-DELETE">Delete:</label></th><td><input type="checkbox" name="form-0-DEL <tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" va <tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub <tr><th><label for="id_form-1-DELETE">Delete:</label></th><td><input type="checkbox" name="form-1-DEL <tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id
186
Similar to can_order this adds a new eld to each form named DELETE and is a forms.BooleanField. When data comes through marking any of the delete elds you can access them with deleted_forms:
>>> data = { ... form-TOTAL_FORMS: u3, ... form-INITIAL_FORMS: u2, ... form-MAX_NUM_FORMS: u, ... form-0-title: uArticle #1, ... form-0-pub_date: u2008-05-10, ... form-0-DELETE: uon, ... form-1-title: uArticle #2, ... form-1-pub_date: u2008-05-11, ... form-1-DELETE: u, ... form-2-title: u, ... form-2-pub_date: u, ... form-2-DELETE: u, ... } >>> formset = ArticleFormSet(data, initial=[ ... {title: uArticle #1, pub_date: datetime.date(2008, 5, 10)}, ... {title: uArticle #2, pub_date: datetime.date(2008, 5, 11)}, ... ]) >>> [form.cleaned_data for form in formset.deleted_forms] [{DELETE: True, pub_date: datetime.date(2008, 5, 10), title: uArticle #1}]
Adding additional elds to a formset If you need to add additional elds to the formset this can be easily accomplished. The formset base class provides an add_fields method. You can simply override this method to add your own elds or even redene the default elds/attributes of the order and deletion elds:
>>> class BaseArticleFormSet(BaseFormSet): ... def add_fields(self, form, index): ... super(BaseArticleFormSet, self).add_fields(form, index) ... form.fields["my_field"] = forms.CharField()
>>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet) >>> formset = ArticleFormSet() >>> for form in formset.forms: ... print form.as_table() <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub <tr><th><label for="id_form-0-my_field">My field:</label></th><td><input type="text" name="form-0-my_
Using a formset in views and templates Using a formset inside a view is as easy as using a regular Form class. The only thing you will want to be aware of is making sure to use the management form inside the template. Lets look at a sample view:
187
def manage_articles(request): ArticleFormSet = formset_factory(ArticleForm) if request.method == POST: formset = ArticleFormSet(request.POST, request.FILES) if formset.is_valid(): # do something with the formset.cleaned_data else: formset = ArticleFormSet() return render_to_response(manage_articles.html, {formset: formset})
However the above can be slightly shortcutted and let the formset itself deal with the management form:
<form method="post" action=""> <table> {{ formset }} </table> </form>
The above ends up calling the as_table method on the formset class.
You would then render the formsets as normal. It is important to point out that you need to pass prefix on both the POST and non-POST cases so that it is rendered and processed correctly.
188
This code denes a CalendarWidget, which will be based on TextInput. Every time the CalendarWidget is used on a form, that form will be directed to include the CSS le pretty.css, and the JavaScript les animations.js and actions.js. This static media denition is converted at runtime into a widget property named media. The media for a CalendarWidget instance can be retrieved through this property:
>>> w = CalendarWidget() >>> print w.media <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" /> <script type="text/javascript" src="http://media.example.com/animations.js"></script> <script type="text/javascript" src="http://media.example.com/actions.js"></script>
Heres a list of all possible Media options. There are no required options.
189
css
A dictionary describing the CSS les required for various forms of output media. The values in the dictionary should be a tuple/list of le names. See the section on media paths for details of how to specify paths to media les. The keys in the dictionary are the output media types. These are the same types accepted by CSS les in media declarations: all, aural, braille, embossed, handheld, print, projection, screen, tty and tv. If you need to have different stylesheets for different media types, provide a list of CSS les for each output medium. The following example would provide two CSS options one for the screen, and one for print:
class Media: css = { screen: (pretty.css,), print: (newspaper.css,) }
If a group of CSS les are appropriate for multiple output media types, the dictionary key can be a comma separated list of output media types. In the following example, TVs and projectors will have the same media requirements:
class Media: css = { screen: (pretty.css,), tv,projector: (lo_res.css,), print: (newspaper.css,) }
If this last CSS denition were to be rendered, it would become the following HTML:
<link href="http://media.example.com/pretty.css" type="text/css" media="screen" rel="stylesheet" /> <link href="http://media.example.com/lo_res.css" type="text/css" media="tv,projector" rel="stylesheet <link href="http://media.example.com/newspaper.css" type="text/css" media="print" rel="stylesheet" />
js
A tuple describing the required JavaScript les. See the section on media paths for details of how to specify paths to media les.
extend
A boolean dening inheritance behavior for media declarations. By default, any object using a static media denition will inherit all the media associated with the parent widget. This occurs regardless of how the parent denes its media requirements. For example, if we were to extend our basic Calendar widget from the example above:
class FancyCalendarWidget(CalendarWidget): class Media: css = { all: (fancy.css,) } js = (whizbang.js,) >>> w = FancyCalendarWidget()
190
>>> print w.media <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" /> <link href="http://media.example.com/fancy.css" type="text/css" media="all" rel="stylesheet" /> <script type="text/javascript" src="http://media.example.com/animations.js"></script> <script type="text/javascript" src="http://media.example.com/actions.js"></script> <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
The FancyCalendar widget inherits all the media from its parent widget. If you dont want media to be inherited in this way, add an extend=False declaration to the media declaration:
class FancyCalendarWidget(CalendarWidget): class Media: extend = False css = { all: (fancy.css,) } js = (whizbang.js,) >>> w = FancyCalendarWidget() >>> print w.media <link href="http://media.example.com/fancy.css" type="text/css" media="all" rel="stylesheet" /> <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
If you require even more control over media inheritance, dene your media using a dynamic property. Dynamic properties give you complete control over which media les are inherited, and which are not. Media as a dynamic property If you need to perform some more sophisticated manipulation of media requirements, you can dene the media property directly. This is done by dening a widget property that returns an instance of forms.Media. The constructor for forms.Media accepts css and js keyword arguments in the same format as that used in a static media denition. For example, the static media denition for our Calendar Widget could also be dened in a dynamic fashion:
class CalendarWidget(forms.TextInput): def _media(self): return forms.Media(css={all: (pretty.css,)}, js=(animations.js, actions.js)) media = property(_media)
See the section on Media objects for more details on how to construct return values for dynamic media properties. Paths in media denitions Paths used to specify media can be either relative or absolute. If a path starts with /, http:// or https://, it will be interpreted as an absolute path, and left as-is. All other paths will be prepended with the value of settings.MEDIA_URL. For example, if the MEDIA_URL for your site was http://media.example.com/:
class CalendarWidget(forms.TextInput): class Media: css = { all: (/css/pretty.css,), } js = (animations.js, http://othersite.com/actions.js)
191
>>> w = CalendarWidget() >>> print w.media <link href="/css/pretty.css" type="text/css" media="all" rel="stylesheet" /> <script type="text/javascript" src="http://media.example.com/animations.js"></script> <script type="text/javascript" src="http://othersite.com/actions.js"></script>
Media objects When you interrogate the media attribute of a widget or form, the value that is returned is a forms.Media object. As we have already seen, the string representation of a Media object is the HTML required to include media in the <head> block of your HTML page. However, Media objects have some other interesting properties.
Media subsets
If you only want media of a particular type, you can use the subscript operator to lter out a medium of interest. For example:
>>> w = CalendarWidget() >>> print w.media <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" /> <script type="text/javascript" src="http://media.example.com/animations.js"></script> <script type="text/javascript" src="http://media.example.com/actions.js"></script> >>> print w.media[css] <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
When you use the subscript operator, the value that is returned is a new Media object but one that only contains the media of interest.
192
Media on Forms Widgets arent the only objects that can have media denitions forms can also dene media. The rules for media denitions on forms are the same as the rules for widgets: declarations can be static or dynamic; path and inheritance rules for those declarations are exactly the same. Regardless of whether you dene a media declaration, all Form objects have a media property. The default value for this property is the result of adding the media denitions for all widgets that are part of the form:
class ContactForm(forms.Form): date = DateField(widget=CalendarWidget) name = CharField(max_length=40, widget=OtherWidget) >>> f = ContactForm() >>> f.media <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" /> <script type="text/javascript" src="http://media.example.com/animations.js"></script> <script type="text/javascript" src="http://media.example.com/actions.js"></script> <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
If you want to associate additional media with a form for example, CSS for form layout simply add a media declaration to the form:
class ContactForm(forms.Form): date = DateField(widget=CalendarWidget) name = CharField(max_length=40, widget=OtherWidget) class Media: css = { all: (layout.css,) } >>> f = ContactForm() >>> f.media <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" /> <link href="http://media.example.com/layout.css" type="text/css" media="all" rel="stylesheet" /> <script type="text/javascript" src="http://media.example.com/animations.js"></script> <script type="text/javascript" src="http://media.example.com/actions.js"></script> <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
193
194
CHAPTER
TWELVE
195
Form eld Not represented in the form IntegerField with min_value set to -9223372036854775808 and max_value set to 9223372036854775807. BooleanField BooleanField CharField CharField with max_length set to the model elds max_length CommaSeparatedIntegerField CharField DateField DateField DateTimeField DateTimeField DecimalField DecimalField EmailField EmailField FileField FileField FilePathField CharField FloatField FloatField ForeignKey ModelChoiceField (see below) ImageField ImageField IntegerField IntegerField IPAddressField IPAddressField ManyToManyField ModelMultipleChoiceField (see below) NullBooleanField CharField PhoneNumberField USPhoneNumberField (from django.contrib.localflavor.us) PositiveIntegerField IntegerField PositiveSmallIntegerField IntegerField SlugField SlugField SmallIntegerField IntegerField TextField CharField with widget=forms.Textarea TimeField TimeField URLField URLField with verify_exists set to the model elds verify_exists XMLField CharField with widget=forms.Textarea New in version 1.0: The FloatField form eld and DecimalField model and form elds are new in Django 1.0.New in version 1.2: The BigIntegerField is new in Django 1.2. As you might expect, the ForeignKey and ManyToManyField model eld types are special cases: ForeignKey is represented by django.forms.ModelChoiceField, which is a ChoiceField whose choices are a model QuerySet. ManyToManyField is represented by django.forms.ModelMultipleChoiceField, which is a MultipleChoiceField whose choices are a model QuerySet. In addition, each generated form eld has attributes set as follows: If the model eld has blank=True, then required is set to False on the form eld. Otherwise, required=True. The form elds label is set to the verbose_name of the model eld, with the rst character capitalized. The form elds help_text is set to the help_text of the model eld. If the model eld has choices set, then the form elds widget will be set to Select, with choices coming from the model elds choices. The choices will normally include the blank choice which is selected by default. If the eld is required, this forces the user to make a selection. The blank choice will not be included if the model eld has blank=False and an explicit default value (the default value will be initially selected instead). Finally, note that you can override the form eld used for a given model eld. See Overriding the default eld types or widgets below.
196
With these models, the ModelForm subclasses above would be roughly equivalent to this (the only difference being the save() method, which well discuss in a moment.):
class AuthorForm(forms.Form): name = forms.CharField(max_length=100) title = forms.CharField(max_length=3, widget=forms.Select(choices=TITLE_CHOICES)) birth_date = forms.DateField(required=False) class BookForm(forms.Form): name = forms.CharField(max_length=100) authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all())
12.1. ModelForm
197
Note that save() will raise a ValueError if the data in the form doesnt validate i.e., if form.errors. This save() method accepts an optional commit keyword argument, which accepts either True or False. If you call save() with commit=False, then it will return an object that hasnt yet been saved to the database. In this case, its up to you to call save() on the resulting model instance. This is useful if you want to do custom processing on the object before saving it, or if you want to use one of the specialized model saving options. commit is True by default. Another side effect of using commit=False is seen when your model has a many-to-many relation with another model. If your model has a many-to-many relation and you specify commit=False when you save a form, Django cannot immediately save the form data for the many-to-many relation. This is because it isnt possible to save manyto-many data for an instance until the instance exists in the database. To work around this problem, every time you save a form using commit=False, Django adds a save_m2m() method to your ModelForm subclass. After youve manually saved the instance produced by the form, you can invoke save_m2m() to save the many-to-many form data. For example:
# Create a form instance with POST data. >>> f = AuthorForm(request.POST) # Create, but dont save the new author instance. >>> new_author = f.save(commit=False) # Modify the author in some way. >>> new_author.some_field = some_value # Save the new instance. >>> new_author.save() # Now, save the many-to-many data for the form. >>> f.save_m2m()
Calling save_m2m() is only required if you use save(commit=False). When you use a simple save() on a form, all data including many-to-many data is saved without the need for any additional method calls. For example:
198
# Create a form instance with POST data. >>> a = Author() >>> f = AuthorForm(request.POST, instance=a) # Create and save the new author instance. Theres no need to do anything else. >>> new_author = f.save()
Other than the save() and save_m2m() methods, a ModelForm works exactly the same way as any other forms form. For example, the is_valid() method is used to check for validity, the is_multipart() method is used to determine whether a form requires multipart le upload (and hence whether request.FILES must be passed to the form), etc. See Binding uploaded les to a form for more information.
Since the Author model has only 3 elds, name, title, and birth_date, the forms above will contain exactly the same elds. Note: If you specify fields or exclude when creating a form with ModelForm, then the elds that are not in the resulting form will not be set by the forms save() method. Django will prevent any attempt to save an incomplete model, so if the model does not allow the missing elds to be empty, and does not provide a default value for the missing elds, any attempt to save() a ModelForm with missing elds will fail. To avoid this failure, you must instantiate your model with initial values for the missing, but required elds:
author = Author(title=Mr) form = PartialAuthorForm(request.POST, instance=author) form.save()
Alternatively, you can use save(commit=False) and manually set any extra required elds:
12.1. ModelForm
199
See the section on saving forms for more details on using save(commit=False).
The widgets dictionary accepts either widget instances (e.g., Textarea(...)) or classes (e.g., Textarea). If you want to further customize a eld including its type, label, etc. you can do this by declaratively specifying elds like you would in a regular Form. Declared elds will override the default ones generated by using the model attribute. For example, if you wanted to use MyDateFormField for the pub_date eld, you could do the following:
class ArticleForm(ModelForm): pub_date = MyDateFormField() class Meta: model = Article
If you want to override a elds default label, then specify the label parameter when declaring the form eld:
>>> class ArticleForm(ModelForm): ... pub_date = DateField(label=Publication date) ... ... class Meta: ... model = Article
Note: If you explicitly instantiate a form eld like this, Django assumes that you want to completely dene its behavior; therefore, default attributes (such as max_length or required) are not drawn from the corresponding model. If you want to maintain the behavior specied in the model, you must set the relevant arguments explicitly when declaring the form eld.
200
and you want to do some custom validation for headline, while keeping the blank and help_text values as specied, you might dene ArticleForm like this:
class ArticleForm(ModelForm): headline = MyFormField(max_length=200, required=False, help_text="Use puns liberally") class Meta: model = Article
See the form eld documentation for more information on elds and their arguments.
the author eld would be rendered rst. If we wanted the title eld to be rendered rst, we could specify the following ModelForm:
>>> class BookForm(ModelForm): ... class Meta: ... model = Book ... fields = [title, author]
12.1. ModelForm
201
This creates a form that behaves identically to ArticleForm, except theres some extra validation and cleaning for the pub_date eld. You can also subclass the parents Meta inner class if you want to change the Meta.fields or Meta.excludes lists:
>>> class RestrictedArticleForm(EnhancedArticleForm): ... class Meta(ArticleForm.Meta): ... exclude = [body]
This adds the extra method from the EnhancedArticleForm and modies the original ArticleForm.Meta to remove one eld. There are a couple of things to note, however. Normal Python name resolution rules apply. If you have multiple base classes that declare a Meta inner class, only the rst one will be used. This means the childs Meta, if it exists, otherwise the Meta of the rst parent, etc. For technical reasons, a subclass cannot inherit from both a ModelForm and a Form simultaneously. Chances are these notes wont affect you unless youre trying to do something tricky with subclassing.
This will create a formset that is capable of working with the data associated with the Author model. It works just like a regular formset:
202
>>> formset = AuthorFormSet() >>> print formset <input type="hidden" name="form-TOTAL_FORMS" value="1" id="id_form-TOTAL_FORMS" /><input type="hidden <tr><th><label for="id_form-0-name">Name:</label></th><td><input id="id_form-0-name" type="text" name <tr><th><label for="id_form-0-title">Title:</label></th><td><select name="form-0-title" id="id_form-0 <option value="" selected="selected">---------</option> <option value="MR">Mr.</option> <option value="MRS">Mrs.</option> <option value="MS">Ms.</option> </select></td></tr> <tr><th><label for="id_form-0-birth_date">Birth date:</label></th><td><input type="text" name="form-0
Note: modelformset_factory uses formset_factory to generate formsets. This means that a model formset is just an extension of a basic formset that knows how to interact with a particular model.
If you want to return a formset that doesnt include any pre-existing instances of the model, you can specify an empty QuerySet:
>>> AuthorFormSet(queryset=Author.objects.none())
12.2.2 Controlling which elds are used with fields and exclude
By default, a model formset uses all elds in the model that are not marked with editable=False. However, this can be overridden at the formset level:
>>> AuthorFormSet = modelformset_factory(Author, fields=(name, title))
Using fields restricts the formset to use only the given elds. Alternatively, you can take an opt-out approach, specifying which elds to exclude:
>>> AuthorFormSet = modelformset_factory(Author, exclude=(birth_date,))
203
The save() method returns the instances that have been saved to the database. If a given instances data didnt change in the bound data, the instance wont be saved to the database and wont be included in the return value (instances, in the above example). Pass commit=False to return the unsaved model instances:
# dont save to the database >>> instances = formset.save(commit=False) >>> for instance in instances: ... # do something with instance ... instance.save()
This gives you the ability to attach data to the instances before saving them to the database. If your formset contains a ManyToManyField, youll also need to call formset.save_m2m() to ensure the many-to-many relationships are saved properly.
If the value of max_num is greater than the number of existing related objects, up to extra additional blank forms will be added to the formset, so long as the total number of forms does not exceed max_num:
>>> AuthorFormSet = modelformset_factory(Author, max_num=4, extra=2) >>> formset = AuthorFormSet(queryset=Author.objects.order_by(name)) >>> for form in formset.forms: ... print form.as_table() <tr><th><label for="id_form-0-name">Name:</label></th><td><input id="id_form-0-name" <tr><th><label for="id_form-1-name">Name:</label></th><td><input id="id_form-1-name" <tr><th><label for="id_form-2-name">Name:</label></th><td><input id="id_form-2-name" <tr><th><label for="id_form-3-name">Name:</label></th><td><input id="id_form-3-name"
Changed in version 1.2: Please, see the release notes A max_num value of None (the default) puts no limit on the number of forms displayed.
204
As you can see, the view logic of a model formset isnt drastically different than that of a normal formset. The only difference is that we call formset.save() to save the data into the database. (This was described above, in Saving objects in the formset.)
Note that we pass the queryset argument in both the POST and GET cases in this example.
205
Second, you can manually render the formset, but let the form deal with itself:
<form method="post" action=""> {{ formset.management_form }} {% for form in formset.forms %} {{ form }} {% endfor %} </form>
When you manually render the forms yourself, be sure to render the management form as shown above. See the management form documentation. Third, you can manually render each eld:
<form method="post" action=""> {{ formset.management_form }} {% for form in formset.forms %} {% for field in form %} {{ field.label_tag }}: {{ field }} {% endfor %} {% endfor %} </form>
If you opt to use this third method and you dont iterate over the elds with a {% for %} loop, youll need to render the primary key eld. For example, if you were rendering the name and age elds of a model:
<form method="post" action=""> {{ formset.management_form }} {% for form in formset.forms %} {{ form.id }} <ul> <li>{{ form.name }}</li> <li>{{ form.age }}</li> </ul> {% endfor %} </form>
Notice how we need to explicitly render {{ form.id }}. This ensures that the model formset, in the POST case, will work correctly. (This example assumes a primary key named id. If youve explicitly dened your own primary key that isnt called id, make sure it gets rendered.)
206
class Author(models.Model): name = models.CharField(max_length=100) class Book(models.Model): author = models.ForeignKey(Author) title = models.CharField(max_length=100)
If you want to create a formset that allows you to edit books belonging to a particular author, you could do this:
>>> >>> >>> >>> from django.forms.models import inlineformset_factory BookFormSet = inlineformset_factory(Author, Book) author = Author.objects.get(name=uMike Royko) formset = BookFormSet(instance=author)
Notice how we pass instance in both the POST and GET cases.
207
208
CHAPTER
THIRTEEN
13.1 Templates
A template is simply a text le. It can generate any text-based format (HTML, XML, CSV, etc.). A template contains variables, which get replaced with values when the template is evaluated, and tags, which control the logic of the template. Below is a minimal template that illustrates a few basics. Each element will be explained later in this document.:
{% extends "base_generic.html" %} {% block title %}{{ section.title }}{% endblock %} {% block content %} <h1>{{ section.title }}</h1> {% for story in story_list %} <h2> <a href="{{ story.get_absolute_url }}"> {{ story.headline|upper }} </a> </h2> <p>{{ story.tease|truncatewords:"100" }}</p>
209
{% endfor %} {% endblock %}
Philosophy Why use a text-based template instead of an XML-based one (like Zopes TAL)? We wanted Djangos template language to be usable for more than just XML/HTML templates. At World Online, we use it for e-mails, JavaScript and CSV. You can use the template language for any text-based format. Oh, and one more thing: Making humans edit XML is sadistic!
13.2 Variables
Variables look like this: {{ variable }}. When the template engine encounters a variable, it evaluates that variable and replaces it with the result. Use a dot (.) to access attributes of a variable. Behind the scenes Technically, when the template system encounters a dot, it tries the following lookups, in this order: Dictionary lookup Attribute lookup Method call List-index lookup In the above example, {{ section.title }} will be replaced with the title attribute of the section object. If you use a variable that doesnt exist, the template system will insert the TEMPLATE_STRING_IF_INVALID setting, which is set to (the empty string) by default. value of the
See Using the built-in reference, below, for help on nding what variables are available in a given template.
13.3 Filters
You can modify variables for display by using lters. Filters look like this: {{ name|lower }}. This displays the value of the {{ name }} variable after being ltered through the lower lter, which converts text to lowercase. Use a pipe (|) to apply a lter. Filters can be chained. The output of one lter is applied to the next. {{ text|escape|linebreaks }} is a common idiom for escaping text contents, then converting line breaks to <p> tags. Some lters take arguments. A lter argument looks like this: {{ bio|truncatewords:30 }}. This will display the rst 30 words of the bio variable. Filter arguments that contain spaces must be quoted; for example, to join a list with commas and spaced youd use {{ list|join:", " }}. Django provides about thirty built-in template lters. You can read all about them in the built-in lter reference. To give you a taste of whats available, here are some of the more commonly used template lters: default If a variable is false or empty, use given default. Otherwise, use the value of the variable For example:
210
{{ value|default:"nothing" }}
If value isnt provided or is empty, the above will display nothing. length Returns the length of the value. This works for both strings and lists; for example:
{{ value|length }}
If value is [a, b, c, d], the output will be 4. striptags Strips all [X]HTML tags. For example:
{{ value|striptags }}
If value is "<b>Joel</b> <button>is</button> a <span>slug</span>", the output will be "Joel is a slug". Again, these are just a few examples; see the built-in lter reference for the complete list. You can also create your own custom template lters; see Custom template tags and lters.
13.4 Tags
Tags look like this: {% tag %}. Tags are more complex than variables: Some create text in the output, some control ow by performing loops or logic, and some load external information into the template to be used by later variables. Some tags require beginning and ending tags (i.e. {% tag %} ... %}). tag contents ... {% endtag
Django ships with about two dozen built-in template tags. You can read all about them in the built-in tag reference. To give you a taste of whats available, here are some of the more commonly used tags: for Loop over each item in an array. For example, to display a list of athletes provided in athlete_list:
<ul> {% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% endfor %} </ul>
if and else Evaluates a variable, and if that variable is true the contents of the block are displayed:
{% if athlete_list %} Number of athletes: {{ athlete_list|length }} {% else %} No athletes. {% endif %}
In the above, if athlete_list is not empty, the number of athletes will be displayed by the {{ athlete_list|length }} variable. You can also use lters and various operators in the if tag:
13.4. Tags
211
{% if athlete_list|length > 1 %} Team: {% for athlete in athlete_list %} ... {% endfor %} {% else %} Athlete: {{ athlete_list.0.name }} {% endif %}
block and extends Set up template inheritance (see below), a powerful way of cutting down on boilerplate in templates. Again, the above is only a selection of the whole list; see the built-in tag reference for the complete list. You can also create your own custom template tags; see Custom template tags and lters.
13.5 Comments
To comment-out part of a line in a template, use the comment syntax: {# #}. For example, this template would render as hello:
{# greeting #}hello
A comment can contain any template code, invalid or not. For example:
{# {% if foo %}bar{% else %} #}
This syntax can only be used for single-line comments (no newlines are permitted between the {# and #} delimiters). If you need to comment out a multiline portion of the template, see the comment tag.
212
This template, which well call base.html, denes a simple HTML skeleton document that you might use for a simple two-column page. Its the job of child templates to ll the empty blocks with content. In this example, the {% block %} tag denes three blocks that child templates can ll in. All the block tag does is to tell the template engine that a child template may override those portions of the template. A child template might look like this:
{% extends "base.html" %} {% block title %}My amazing blog{% endblock %} {% block content %} {% for entry in blog_entries %} <h2>{{ entry.title }}</h2> <p>{{ entry.body }}</p> {% endfor %} {% endblock %}
The {% extends %} tag is the key here. It tells the template engine that this template extends another template. When the template system evaluates this template, rst it locates the parent in this case, base.html. At that point, the template engine will notice the three {% block %} tags in base.html and replace those blocks with the contents of the child template. Depending on the value of blog_entries, the output might look like:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <link rel="stylesheet" href="style.css" /> <title>My amazing blog</title> </head> <body> <div id="sidebar"> <ul> <li><a href="/">Home</a></li> <li><a href="/blog/">Blog</a></li> </ul> </div> <div id="content"> <h2>Entry one</h2> <p>This is my first entry.</p> <h2>Entry two</h2> <p>This is my second entry.</p> </div> </body> </html>
213
Note that since the child template didnt dene the sidebar block, the value from the parent template is used instead. Content within a {% block %} tag in a parent template is always used as a fallback. You can use as many levels of inheritance as needed. One common way of using inheritance is the following three-level approach: Create a base.html template that holds the main look-and-feel of your site. Create a base_SECTIONNAME.html template for each section of your site. For example, base_news.html, base_sports.html. These templates all extend base.html and include sectionspecic styles/design. Create individual templates for each type of page, such as a news article or blog entry. These templates extend the appropriate section template. This approach maximizes code reuse and makes it easy to add items to shared content areas, such as section-wide navigation. Here are some tips for working with inheritance: If you use {% extends %} in a template, it must be the rst template tag in that template. Template inheritance wont work, otherwise. More {% block %} tags in your base templates are better. Remember, child templates dont have to dene all parent blocks, so you can ll in reasonable defaults in a number of blocks, then only dene the ones you need later. Its better to have more hooks than fewer hooks. If you nd yourself duplicating content in a number of templates, it probably means you should move that content to a {% block %} in a parent template. If you need to get the content of the block from the parent template, the {{ block.super }} variable will do the trick. This is useful if you want to add to the contents of a parent block instead of completely overriding it. Data inserted using {{ block.super }} will not be automatically escaped (see the next section), since it was already escaped, if necessary, in the parent template. For extra readability, you can optionally give a name to your {% endblock %} tag. For example:
{% block content %} ... {% endblock content %}
In larger templates, this technique helps you see which {% block %} tags are being closed. Finally, note that you cant dene 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 doesnt just provide a hole to ll it also denes the content that lls the hole in the parent. If there were two similarly-named {% block %} tags in a template, that templates parent wouldnt know which one of the blocks content to use.
At rst, this seems like a harmless way to display a users name, but consider what would happen if the user entered his name as this:
214
<script>alert(hello)</script>
...which means the browser would pop-up a JavaScript alert box! Similarly, what if the name contained a < symbol, like this? <b>username That would result in a rendered template like this:
Hello, <b>username
...which, in turn, would result in the remainder of the Web page being bolded! Clearly, user-submitted data shouldnt be trusted blindly and inserted directly into your Web pages, because a malicious user could use this kind of hole to do potentially bad things. This type of security exploit is called a Cross Site Scripting (XSS) attack. To avoid this problem, you have two options: One, you can make sure to run each untrusted variable through the escape lter (documented below), which converts potentially harmful HTML characters to unharmful ones. This was the default solution in Django for its rst few years, but the problem is that it puts the onus on you, the developer / template author, to ensure youre escaping everything. Its easy to forget to escape data. Two, you can take advantage of Djangos automatic HTML escaping. The remainder of this section describes how auto-escaping works. By default in Django, every template automatically escapes the output of every variable tag. Specically, these ve characters are escaped: < is converted to < > is converted to > (single quote) is converted to ' " (double quote) is converted to " & is converted to & Again, we stress that this behavior is on by default. If youre using Djangos template system, youre protected.
215
For individual variables To disable auto-escaping for an individual variable, use the safe lter:
This will be escaped: {{ data }} This will not be escaped: {{ data|safe }}
Think of safe as shorthand for safe from further escaping or can be safely interpreted as HTML. In this example, if data contains <b>, the output will be:
This will be escaped: <b> This will not be escaped: <b>
For template blocks To control auto-escaping for a template, wrap the template (or just a particular section of the template) in the autoescape tag, like so:
{% autoescape off %} Hello {{ name }} {% endautoescape %}
The autoescape tag takes either on or off as its argument. At times, you might want to force auto-escaping when it would otherwise be disabled. Here is an example template:
Auto-escaping is on by default. Hello {{ name }} {% autoescape off %} This will not be auto-escaped: {{ data }}. Nor this: {{ other_data }} {% autoescape on %} Auto-escaping applies again: {{ name }} {% endautoescape %} {% endautoescape %}
The auto-escaping tag passes its effect onto templates that extend the current one as well as templates included via the include tag, just like all block tags. For example:
# base.html {% autoescape off %} <h1>{% block title %}{% endblock %}</h1> {% block content %} {% endblock %} {% endautoescape %}
# child.html {% extends "base.html" %} {% block title %}This & that{% endblock %} {% block content %}{{ greeting }}{% endblock %}
216
Because auto-escaping is turned off in the base template, it will also be turned off in the child template, resulting in the following rendered HTML when the greeting variable contains the string <b>Hello!</b>:
<h1>This & that</h1> <b>Hello!</b>
13.7.2 Notes
Generally, template authors dont need to worry about auto-escaping very much. Developers on the Python side (people writing views and custom lters) need to think about the cases in which data shouldnt be escaped, and mark data appropriately, so things Just Work in the template. If youre creating a template that might be used in situations where youre not sure whether auto-escaping is enabled, then add an escape lter to any variable that needs escaping. When auto-escaping is on, theres no danger of the escape lter double-escaping data the escape lter does not affect auto-escaped variables.
All string literals are inserted without any automatic escaping into the template they act as if they were all passed through the safe lter. The reasoning behind this is that the template author is in control of what goes into the string literal, so they can make sure the text is correctly escaped when the template is written. This means you would write
{{ data|default:"3 < 2" }}
...rather than
{{ data|default:"3 < 2" }} <-- Bad! Dont do this.
This doesnt affect what happens to data coming from the variable itself. The variables contents are still automatically escaped, if necessary, because theyre beyond the control of the template author.
217
After youve followed those steps, you can start browsing the documentation by going to your admin interface and clicking the Documentation link in the upper right of the page. The reference is divided into 4 sections: tags, lters, models, and views. The tags and lters sections describe all the built-in tags (in fact, the tag and lter references below come directly from those pages) as well as any custom tag or lter libraries available. The views page is the most valuable. Each URL in your site has a separate entry here, and clicking on a URL will show you: The name of the view function that generates that view. A short description of what the view does. The context, or a list of variables available in the views template. The name of the template or templates that are used for that view. Each view documentation page also has a bookmarklet that you can use to jump from any page to the documentation page for that view. Because Django-powered sites usually use database objects, the models section of the documentation page describes each type of object in the system along with all the elds available on that object. Taken together, the documentation pages should tell you every tag, lter, variable and object available to you in a given template.
In the above, the load tag loads the comments tag library, which then makes the comment_form tag available for use. Consult the documentation area in your admin to nd the list of custom libraries in your installation. The {% load %} tag can take multiple library names, separated by spaces. Example:
{% load comments i18n %}
See Custom template tags and lters for information on writing your own custom template libraries.
218
CHAPTER
FOURTEEN
GENERIC VIEWS
Writing Web applications can be monotonous, because we repeat certain patterns again and again. Django tries to take away some of that monotony at the model and template layers, but Web developers also experience this boredom at the view level. Djangos generic views were developed to ease that pain. They take certain common idioms and patterns found in view development and abstract them so that you can quickly write common views of data without having to write too much code. We can recognize certain common tasks, like displaying a list of objects, and write code that displays a list of any object. Then the model in question can be passed as an extra argument to the URLconf. Django ships with generic views to do the following: Perform common simple tasks: redirect to a different page and render a given template. Display list and detail pages for a single object. If we were creating an application to manage conferences then a talk_list view and a registered_user_list view would be examples of list views. A single talk page is an example of what we call a detail view. Present date-based objects in year/month/day archive pages, associated detail, and latest pages. The Django Weblogs (http://www.djangoproject.com/weblog/) year, month, and day archives are built with these, as would be a typical newspapers archives. Allow users to create, update, and delete objects with or without authorization. Taken together, these views provide easy interfaces to perform the most common tasks developers encounter.
219
Though this might seem a bit magical at rst glance look, a view with no code! , actually the direct_to_template view simply grabs information from the extra-parameters dictionary and uses that information when rendering the view. Because this generic view and all the others is a regular view function like any other, we can reuse it inside our own views. As an example, lets extend our about example to map URLs of the form /about/<whatever>/ to statically rendered about/<whatever>.html. Well do this by rst modifying the URLconf to point to a view function:
from django.conf.urls.defaults import * from django.views.generic.simple import direct_to_template from mysite.books.views import about_pages urlpatterns = patterns(, (^about/$, direct_to_template, { template: about.html }), (^about/(\w+)/$, about_pages), )
Here were treating direct_to_template like any other function. Since it returns an HttpResponse, we can simply return it as-is. The only slightly tricky business here is dealing with missing templates. We dont want a nonexistent template to cause a server error, so we catch TemplateDoesNotExist exceptions and return 404 errors instead. Is there a security vulnerability here? Sharp-eyed readers may have noticed a possible security hole: were constructing the template name using interpolated content from the browser (template="about/%s.html" % page). At rst glance, this looks like a classic directory traversal vulnerability. But is it really? Not exactly. Yes, a maliciously crafted value of page could cause directory traversal, but although page is taken from the request URL, not every value will be accepted. The key is in the URLconf: were using the regular expression \w+ to match the page part of the URL, and \w only accepts letters and numbers. Thus, any malicious characters (dots and slashes, here) will be rejected by the URL resolver before they reach the view itself.
220
# models.py 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 Meta: ordering = ["-name"] class Book(models.Model): title = models.CharField(max_length=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField()
To build a list page of all publishers, wed use a URLconf along these lines:
from django.conf.urls.defaults import * from django.views.generic import list_detail from mysite.books.models import Publisher publisher_info = { "queryset" : Publisher.objects.all(), } urlpatterns = patterns(, (r^publishers/$, list_detail.object_list, publisher_info) )
Thats all the Python code we need to write. We still need to write a template, however. We could explicitly tell the object_list view which template to use by including a template_name key in the extra arguments dictionary, but in the absence of an explicit template Django will infer one from the objects name. In this case, the inferred template will be "books/publisher_list.html" the books part comes from the name of the app that denes the model, while the publisher bit is just the lowercased version of the models name. This template will be rendered against a context containing a variable called object_list that contains all the publisher objects. A very simple template might look like the following:
{% extends "base.html" %} {% block content %} <h2>Publishers</h2> <ul> {% for publisher in object_list %} <li>{{ publisher.name }}</li> {% endfor %} </ul> {% endblock %}
221
Thats really all there is to it. All the cool features of generic views come from changing the info dictionary passed to the generic view. The generic views reference documents all the generic views and all their options in detail; the rest of this document will consider some of the common ways you might customize and extend generic views.
Providing a useful template_object_name is always a good idea. Your coworkers who design templates will thank you.
222
This would populate a {{ book_list }} variable in the template context. This pattern can be used to pass any information down into the template for the generic view. Its very handy. However, theres actually a subtle bug here can you spot it? The problem has to do with when the queries in extra_context are evaluated. Because this example puts Book.objects.all() in the URLconf, it will be evaluated only once (when the URLconf is rst loaded). Once you add or remove books, youll notice that the generic view doesnt reect those changes until you reload the Web server (see Caching and QuerySets for more information about when QuerySets are cached and evaluated). Note: This problem doesnt apply to the queryset generic view argument. Since Django knows that particular QuerySet should never be cached, the generic view takes care of clearing the cache when each view is rendered. The solution is to use a callback in extra_context instead of a value. Any callable (i.e., a function) thats passed to extra_context will be evaluated when the view is rendered (instead of only once). You could do this with an explicitly dened function:
def get_books(): return Book.objects.all() publisher_info = { "queryset" : Publisher.objects.all(), "template_object_name" : "publisher", "extra_context" : {"book_list" : get_books} }
or you could use a less obvious but shorter version that relies on the fact that Book.objects.all is itself a callable:
publisher_info = { "queryset" : Publisher.objects.all(), "template_object_name" : "publisher", "extra_context" : {"book_list" : Book.objects.all} }
Notice the lack of parentheses after Book.objects.all; this references the function without actually calling it (which the generic view will do later).
Thats a pretty simple example, but it illustrates the idea nicely. Of course, youll usually want to do more than just reorder objects. If you want to present a list of books by a particular publisher, you can use the same technique:
223
acme_books = { "queryset": Book.objects.filter(publisher__name="Acme Publishing"), "template_name" : "books/acme_list.html" } urlpatterns = patterns(, (r^publishers/$, list_detail.object_list, publisher_info), (r^books/acme/$, list_detail.object_list, acme_books), )
Notice that along with a ltered queryset, were also using a custom template name. If we didnt, the generic view would use the same template as the vanilla object list, which might not be what we want. Also notice that this isnt a very elegant way of doing publisher-specic books. If we want to add another publisher page, wed need another handful of lines in the URLconf, and more than a few publishers would get unreasonable. Well deal with this problem in the next section. Note: If you get a 404 when requesting /books/acme/, check to ensure you actually have a Publisher with the name ACME Publishing. Generic views have an allow_empty parameter for this case. See the generic views reference for more details.
224
This works because theres really nothing special about generic views theyre just Python functions. Like any view function, generic views expect a certain set of arguments and return HttpResponse objects. Thus, its incredibly easy to wrap a small function around a generic view that does additional work before (or after; see the next section) handing things off to the generic view. Note: Notice that in the preceding example we passed the current publisher being displayed in the extra_context. This is usually a good idea in wrappers of this nature; it lets the template know which parent object is currently being browsed.
The generic object_detail view, of course, wouldnt know anything about this eld, but once again we could easily write a custom view to keep that eld updated. First, wed need to add an author detail bit in the URLconf to point to a custom view:
from mysite.books.views import author_detail urlpatterns = patterns(, #... (r^authors/(?P<author_id>\d+)/$, author_detail), )
225
# Show the detail page return list_detail.object_detail( request, queryset = Author.objects.all(), object_id = author_id, )
Note: This code wont actually work unless you create a books/author_detail.html template. We can use a similar idiom to alter the response returned by the generic view. If we wanted to provide a downloadable plain-text version of the list of authors, we could use a view like this:
def author_list_plaintext(request): response = list_detail.object_list( request, queryset = Author.objects.all(), mimetype = "text/plain", template_name = "books/author_list.txt" ) response["Content-Disposition"] = "attachment; filename=authors.txt" return response
This works because the generic views return simple HttpResponse objects that can be treated like dictionaries to set HTTP headers. This Content-Disposition business, by the way, instructs the browser to download and save the page instead of displaying it in the browser.
226
CHAPTER
FIFTEEN
MANAGING FILES
New in version 1.0: Please, see the release notes This document describes Djangos le access APIs. By default, Django stores les locally, using the MEDIA_ROOT and MEDIA_URL settings. The examples below assume that youre using these defaults. However, Django provides ways to write custom le storage systems that allow you to completely customize where and how Django stores les. The second half of this document describes how these storage systems work.
Any Car instance will have a photo attribute that you can use to get at the details of the attached photo:
>>> car = Car.objects.get(name="57 Chevy") >>> car.photo <ImageFieldFile: chevy.jpg> >>> car.photo.name ucars/chevy.jpg >>> car.photo.path u/media/cars/chevy.jpg >>> car.photo.url uhttp://media.example.com/cars/chevy.jpg
This object car.photo in the example is a File object, which means it has all the methods and attributes described below.
227
Most of the time youll simply use a File that Djangos given you (i.e. a le attached to a model as above, or perhaps an uploaded le). If you need to construct a File yourself, the easiest way is to create one using a Python built-in file object:
>>> from django.core.files import File # Create a Python file object using open() >>> f = open(/tmp/hello.world, w) >>> myfile = File(f)
Now you can use any of the File attributes and methods documented in The File object.
228
ArguDescription ment location Optional. Absolute path to the directory that will hold the les. If omitted, it will be set to the value of your MEDIA_ROOT setting. base_url Optional. URL that serves the les stored at this location. If omitted, it will default to the value of your MEDIA_URL setting. For example, the following code will store uploaded les under /media/photos regardless of what your MEDIA_ROOT setting is:
from django.db import models from django.core.files.storage import FileSystemStorage fs = FileSystemStorage(location=/media/photos) class Car(models.Model): ... photo = models.ImageField(storage=fs)
Custom storage systems work the same way: you can pass them in as the storage argument to a FileField.
229
230
CHAPTER
SIXTEEN
Unit tests tests that are expressed as methods on a Python class that subclasses unittest.TestCase. For example:
import unittest class MyFuncTestCase(unittest.TestCase):
231
def testBasic(self): a = [larry, curly, moe] self.assertEquals(my_func(a, 0), larry) self.assertEquals(my_func(a, 1), curly)
You can choose the test framework you like, depending on which syntax you prefer, or you can mix and match, using one framework for some of your code and the other framework for other code. You can also use any other Python test frameworks, as well explain in a bit.
Because tests often make great documentation, putting tests directly in your docstrings is an effective way to document and test your code. For a given Django application, the test runner looks for doctests in two places: The models.py le. You can dene module-level doctests and/or a doctest for individual models. Its common practice to put application-level doctests in the module docstring and model-level doctests in the model docstrings. A le called tests.py in the application directory i.e., the directory that holds models.py. This le is a hook for any and all doctests you want to write that arent necessarily related to models. Here is an example model doctest:
# models.py from django.db import models class Animal(models.Model): """ An animal that knows how to make noise # Create some animals >>> lion = Animal.objects.create(name="lion", sound="roar") >>> cat = Animal.objects.create(name="cat", sound="meow") # Make em speak >>> lion.speak() The lion says "roar" >>> cat.speak()
232
The cat says "meow" """ name = models.CharField(max_length=20) sound = models.CharField(max_length=20) def speak(self): return The %s says "%s" % (self.name, self.sound)
When you run your tests, the test runner will nd this docstring, notice that portions of it look like an interactive Python session, and execute those lines while checking that the results match. In the case of model tests, note that the test runner takes care of creating its own test database. That is, any test that accesses a database by creating and saving model instances, for example will not affect your production database. However, the database is not refreshed between doctests, so if your doctest requires a certain state you should consider ushing the database or loading a xture. (See the section on xtures, below, for more on this.) Note that to use this feature, the database user Django is connecting as must have CREATE DATABASE rights. For more details about how doctest works, see the standard library documentation for doctest.
When you run your tests, the default behavior of the test utility is to nd all the test cases (that is, subclasses of unittest.TestCase) in models.py and tests.py, automatically build a test suite out of those test cases, and run that suite. There is a second way to dene the test suite for a module: if you dene a function called suite() in either models.py or tests.py, the Django test runner will use that function to construct the test suite for that module. This follows the suggested organization for unit tests. See the Python documentation for more details on how to construct a complex test suite. For more details about unittest, see the standard library unittest documentation.
233
By default, this will run every test in every application in INSTALLED_APPS. If you only want to run tests for a particular application, add the application name to the command line. For example, if your INSTALLED_APPS contains myproject.polls and myproject.animals, you can run the myproject.animals unit tests alone with this command:
$ ./manage.py test animals
Note that we used animals, not myproject.animals. New in version 1.0: You can now choose which test to run. You can be even more specic by naming an individual test case. To run a single test case in an application (for example, the AnimalTestCase described in the Writing unit tests section), add the name of the test case to the label on the command line:
$ ./manage.py test animals.AnimalTestCase
And it gets even more granular than that! To run a single test method inside a test case, add the name of the test method to the label:
$ ./manage.py test animals.AnimalTestCase.testFluffyAnimals
New in version 1.2: The ability to select individual doctests was added. You can use the same rules if youre using doctests. Django will use the test label as a path to the test method or class that you want to run. If your models.py or tests.py has a function with a doctest, or class with a class-level doctest, you can invoke that test by appending the name of the test method or class to the label:
234
If you want to run the doctest for a specic method in a class, add the name of the method to the label:
$ ./manage.py test animals.Classifier.run
If youre using a __test__ dictionary to specify doctests for a module, Django will use the label as a key in the __test__ dictionary for dened in models.py and tests.py. New in version 1.2: You can now trigger a graceful exit from a test run by pressing Ctrl-C. If you press Ctrl-C while the tests are running, the test runner will wait for the currently running test to complete and then exit gracefully. During a graceful exit the test runner will output details of any test failures, report on how many tests were run and how many errors and failures were encountered, and destroy any test databases as usual. Thus pressing Ctrl-C can be very useful if you forget to pass the --failfast option, notice that some tests are unexpectedly failing, and want to get details on the failures without waiting for the full test run to complete. If you do not want to wait for the currently running test to nish, you can press Ctrl-C a second time and the test run will halt immediately, but not gracefully. No details of the tests run before the interruption will be reported, and any test databases created by the run will not be destroyed.
235
slave: { ENGINE: django.db.backends.mysql, NAME: myproject, HOST: dbslave, TEST_MIRROR: default # ... plus some other settings } }
In this setup, we have two database servers: dbmaster, described by the database alias default, and dbslave described by the alias slave. As you might expect, dbslave has been congured by the database administrator as a read slave of dbmaster, so in normal activity, any write to default will appear on slave. If Django created two independent test databases, this would break any tests that expected replication to occur. However, the slave database has been congured as a test mirror (using the TEST_MIRROR setting), indicating that under testing, slave should be treated as a mirror of default. When the test environment is congured, a test version of slave will not be created. Instead the connection to slave will be redirected to point at default. As a result, writes to default will appear on slave but because they are actually the same database, not because there is data replication between the two databases.
This tells you that the test runner is creating a test database, as described in the previous section. Once the test database has been created, Django will run your tests. If everything goes well, youll see something like this:
---------------------------------------------------------------------Ran 22 tests in 0.221s OK
If there are test failures, however, youll see full details about which tests failed:
====================================================================== FAIL: Doctest: ellington.core.throttle.models ---------------------------------------------------------------------Traceback (most recent call last): File "/dev/django/test/doctest.py", line 2153, in runTest raise self.failureException(self.format_failure(new.getvalue()))
236
AssertionError: Failed doctest test for myapp.models File "/dev/myapp/models.py", line 0, in models ---------------------------------------------------------------------File "/dev/myapp/models.py", line 14, in myapp.models Failed example: throttle.check("actor A", "action one", limit=2, hours=1) Expected: True Got: False ---------------------------------------------------------------------Ran 2 tests in 0.048s FAILED (failures=1)
A full explanation of this error output is beyond the scope of this document, but its pretty intuitive. You can consult the documentation of Pythons unittest library for details. Note that the return code for the test-runner script is the total number of failed and erroneous tests. If all the tests pass, the return code is 0. This feature is useful if youre using the test-runner script in a shell script and need to test for success or failure at that level.
237
Overview and a quick example To use the test client, instantiate django.test.client.Client and retrieve Web pages:
>>> from django.test.client import Client >>> c = Client() >>> response = c.post(/login/, {username: john, password: smith}) >>> response.status_code 200 >>> response = c.get(/customer/details/) >>> response.content <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 ...
As this example suggests, you can instantiate Client from within a session of the Python interactive interpreter. Note a few important things about how the test client works: The test client does not require the Web server to be running. In fact, it will run just ne with no Web server running at all! Thats because it avoids the overhead of HTTP and deals directly with the Django framework. This helps make the unit tests run quickly. When retrieving pages, remember to specify the path of the URL, not the whole domain. For example, this is correct:
>>> c.get(/login/)
This is incorrect:
>>> c.get(http://www.example.com/login/)
The test client is not capable of retrieving Web pages that are not powered by your Django project. If you need to retrieve other Web pages, use a Python standard library module such as urllib or urllib2. To resolve URLs, the test client uses whatever URLconf is pointed-to by your ROOT_URLCONF setting. Although the above example would work in the Python interactive interpreter, some of the test clients functionality, notably the template-related functionality, is only available while tests are running. The reason for this is that Djangos test runner performs a bit of black magic in order to determine which template was loaded by a given view. This black magic (essentially a patching of Djangos template system in memory) only happens during test running. Making requests Use the django.test.client.Client class to make requests. It requires no arguments at time of construction: class Client() Once you have a Client instance, you can call any of the following methods: get(path, data={}, follow=False, **extra) Makes a GET request on the provided path and returns a Response object, which is documented below. The key-value pairs in the data dictionary are used to create a GET data payload. For example:
>>> c = Client() >>> c.get(/customers/details/, {name: fred, age: 7})
...will result in the evaluation of a GET request equivalent to: 238 Chapter 16. Testing Django applications
/customers/details/?name=fred&age=7
The extra keyword arguments parameter can be used to specify headers to be sent in the request. For example:
>>> c = Client() >>> c.get(/customers/details/, {name: fred, age: 7}, ... HTTP_X_REQUESTED_WITH=XMLHttpRequest)
...will send the HTTP header HTTP_X_REQUESTED_WITH to the details view, which is a good way to test code paths that use the django.http.HttpRequest.is_ajax() method. New in version 1.1: Please, see the release notes If you already have the GET arguments in URL-encoded form, you can use that encoding instead of using the data argument. For example, the previous GET request could also be posed as:
>>> c = Client() >>> c.get(/customers/details/?name=fred&age=7)
If you provide a URL with both an encoded GET data and a data argument, the data argument will take precedence. If you set follow to True the client will follow any redirects and a redirect_chain attribute will be set in the response object containing tuples of the intermediate urls and status codes. If you had an url /redirect_me/ that redirected to /next/, that redirected to /final/, this is what youd see:
>>> response = c.get(/redirect_me/, follow=True) >>> response.redirect_chain [(uhttp://testserver/next/, 302), (uhttp://testserver/final/, 302)]
post(path, data={}, content_type=MULTIPART_CONTENT, follow=False, **extra) Makes a POST request on the provided path and returns a Response object, which is documented below. The key-value pairs in the data dictionary are used to submit POST data. For example:
>>> c = Client() >>> c.post(/login/, {name: fred, passwd: secret})
If you provide content_type (e.g., text/xml for an XML payload), the contents of data will be sent as-is in the POST request, using content_type in the HTTP Content-Type header. If you dont provide a value for content_type, the values in data will be transmitted with a content type of multipart/form-data. In this case, the key-value pairs in data will be encoded as a multipart message and used to create the POST data payload.
239
To submit multiple values for a given key for example, to specify the selections for a <select multiple> provide the values as a list or tuple for the required key. For example, this value of data would submit three selected values for the eld named choices:
{choices: (a, b, d)}
Submitting les is a special case. To POST a le, you need only provide the le eld name as a key, and a le handle to the le you wish to upload as a value. For example:
>>> >>> >>> >>> c = Client() f = open(wishlist.doc) c.post(/customers/wishes/, {name: fred, attachment: f}) f.close()
(The name attachment here is not relevant; use whatever name your le-processing code expects.) Note that if you wish to use the same le handle for multiple post() calls then you will need to manually reset the le pointer between posts. The easiest way to do this is to manually close the le after it has been provided to post(), as demonstrated above. You should also ensure that the le is opened in a way that allows the data to be read. If your le contains binary data such as an image, this means you will need to open the le in rb (read binary) mode. The extra argument acts the same as for Client.get(). Changed in version 1.1: Please, see the release notes If the URL you request with a POST contains encoded parameters, these parameters will be made available in the request.GET data. For example, if you were to make the request:
>>> c.post(/login/?vistor=true, {name: fred, passwd: secret})
... the view handling this request could interrogate request.POST to retrieve the username and password, and could interrogate request.GET to determine if the user was a visitor. If you set follow to True the client will follow any redirects and a redirect_chain attribute will be set in the response object containing tuples of the intermediate urls and status codes. head(path, data={}, follow=False, **extra) New in version 1.1: Please, see the release notes Makes a HEAD request on the provided path and returns a Response object. Useful for testing RESTful interfaces. Acts just like Client.get() except it does not return a message body. If you set follow to True the client will follow any redirects and a redirect_chain attribute will be set in the response object containing tuples of the intermediate urls and status codes. options(path, data={}, follow=False, **extra) New in version 1.1: Please, see the release notes Makes an OPTIONS request on the provided path and returns a Response object. Useful for testing RESTful interfaces. If you set follow to True the client will follow any redirects and a redirect_chain attribute will be set in the response object containing tuples of the intermediate urls and status codes. The extra argument acts the same as for Client.get(). put(path, data={}, content_type=MULTIPART_CONTENT, follow=False, **extra) New in version 1.1: Please, see the release notes Makes a PUT request on the provided path and returns a Response object. Useful for testing RESTful interfaces. Acts just like Client.post() except with the PUT request method. If you set follow to True the client will follow any redirects and a redirect_chain attribute will be set in the response object containing tuples of the intermediate urls and status codes.
240
delete(path, follow=False, **extra) New in version 1.1: Please, see the release notes Makes an DELETE request on the provided path and returns a Response object. Useful for testing RESTful interfaces. If you set follow to True the client will follow any redirects and a redirect_chain attribute will be set in the response object containing tuples of the intermediate urls and status codes. The extra argument acts the same as for Client.get(). login(**credentials) New in version 1.0: Please, see the release notes If your site uses Djangos authentication system and you deal with logging in users, you can use the test clients login() method to simulate the effect of a user logging into the site. After you call this method, the test client will have all the cookies and session data required to pass any login-based tests that may form part of a view. The format of the credentials argument depends on which authentication backend youre using (which is congured by your AUTHENTICATION_BACKENDS setting). If youre using the standard authentication backend provided by Django (ModelBackend), credentials should be the users username and password, provided as keyword arguments:
>>> c = Client() >>> c.login(username=fred, password=secret) # Now you can access a view thats only available to logged-in users.
If youre using a different authentication backend, this method may require different credentials. It requires whichever credentials are required by your backends authenticate() method. login() returns True if it the credentials were accepted and login was successful. Finally, youll need to remember to create user accounts before you can use this method. As we explained above, the test runner is executed using a test database, which contains no users by default. As a result, user accounts that are valid on your production site will not work under test conditions. Youll need to create users as part of the test suite either manually (using the Django model API) or with a test xture. Remember that if you want your test user to have a password, you cant set the users password by setting the password attribute directly you must use the set_password() function to store a correctly hashed password. Alternatively, you can use the create_user() helper method to create a new user with a correctly hashed password. logout() New in version 1.0: Please, see the release notes If your site uses Djangos authentication system, the logout() method can be used to simulate the effect of a user logging out of your site. After you call this method, the test client will have all the cookies and session data cleared to defaults. Subsequent requests will appear to come from an AnonymousUser. Testing responses The get() and post() methods both return a Response object. This Response object is not the same as the HttpResponse object returned Django views; the test response object has some additional data useful for test code to verify. Specically, a Response object has the following attributes: class Response()
241
client The test client that was used to make the request that resulted in the response. content The body of the response, as a string. This is the nal page content as rendered by the view, or any error message. context The template Context instance that was used to render the template that produced the response content. If the rendered page used multiple templates, then context will be a list of Context objects, in the order in which they were rendered. New in version 1.1: Please, see the release notes Regardless of the number of templates used during rendering, you can retrieve context values using the [] operator. For example, the context variable name could be retrieved using:
>>> response = client.get(/foo/) >>> response.context[name] Arthur
request The request data that stimulated the response. status_code The HTTP status of the response, as an integer. See RFC2616 for a full list of HTTP status codes. template The Template instance that was used to render the nal content. Use template.name to get the templates le name, if the template was loaded from a le. (The name is a string such as admin/index.html.) If the rendered page used multiple templates e.g., using template inheritance then template will be a list of Template instances, in the order in which they were rendered. You can also use dictionary syntax on the response object to query the value of any settings in the HTTP headers. For example, you could determine the content type of a response using response[Content-Type]. Exceptions If you point the test client at a view that raises an exception, that exception will be visible in the test case. You can then use a standard try...except block or unittest.TestCase.assertRaises() to test for exceptions. The only exceptions that are not visible to the test client are Http404, PermissionDenied and SystemExit. Django catches these exceptions internally and converts them into the appropriate HTTP response codes. In these cases, you can check response.status_code in your test. Persistent state The test client is stateful. If a response returns a cookie, then that cookie will be stored in the test client and sent with all subsequent get() and post() requests. Expiration policies for these cookies are not followed. If you want a cookie to expire, either delete it manually or create a new Client instance (which will effectively delete all cookies). A test client has two attributes that store persistent state information. You can access these properties as part of a test condition.
242
cookies A Python SimpleCookie object, containing the current values of all the client cookies. See the Cookie module documentation for more. session A dictionary-like object containing session information. See the session documentation for full details. Example The following is a simple unit test using the test client:
import unittest from django.test.client import Client class SimpleTest(unittest.TestCase): def setUp(self): # Every test needs a client. self.client = Client() def test_details(self): # Issue a GET request. response = self.client.get(/customer/details/) # Check that the response is 200 OK. self.failUnlessEqual(response.status_code, 200) # Check that the rendered context contains 5 customers. self.failUnlessEqual(len(response.context[customers]), 5)
16.3.2 TestCase
Normal Python unit test classes extend a base class of unittest.TestCase. Django provides an extension of this base class: class TestCase() This class provides some additional capabilities that can be useful for testing Web sites. Converting a normal unittest.TestCase to a Django TestCase is easy: just change the base class of your test from unittest.TestCase to django.test.TestCase. All of the standard Python unit test functionality will continue to be available, but it will be augmented with some useful additions. New in version 1.1: Please, see the release notes class TransactionTestCase() Django TestCase classes make use of database transaction facilities, if available, to speed up the process of resetting the database to a known state at the beginning of each test. A consequence of this, however, is that the effects of transaction commit and rollback cannot be tested by a Django TestCase class. If your test requires testing of such transactional behavior, you should use a Django TransactionTestCase. TransactionTestCase and TestCase are identical except for the manner in which the database is reset to a known state and the ability for test code to test the effects of commit and rollback. A TransactionTestCase resets the database before the test runs by truncating all tables and reloading initial data. A TransactionTestCase may call commit and rollback and observe the effects of these calls on the database. A TestCase, on the other hand, does not truncate tables and reload initial data at the beginning of a test. Instead, it encloses the test code in a database transaction that is rolled back at the end of the test. It also prevents the code under
243
test from issuing any commit or rollback operations on the database, to ensure that the rollback at the end of the test restores the database to its initial state. In order to guarantee that all TestCase code starts with a clean database, the Django test runner runs all TestCase tests rst, before any other tests (e.g. doctests) that may alter the database without restoring it to its original state. When running on a database that does not support rollback (e.g. MySQL with the MyISAM storage engine), TestCase falls back to initializing the database by truncating tables and reloading initial data. Note: The TestCase use of rollback to un-do the effects of the test code may reveal previously-undetected errors in test code. For example, test code that assumes primary keys values will be assigned starting at one may nd that assumption no longer holds true when rollbacks instead of table truncation are being used to reset the database. Similarly, the reordering of tests so that all TestCase classes run rst may reveal unexpected dependencies on test case ordering. In such cases a quick x is to switch the TestCase to a TransactionTestCase. A better long-term x, that allows the test to take advantage of the speed benet of TestCase, is to x the underlying test problem. Default test client New in version 1.0: Please, see the release notes client Every test case in a django.test.TestCase instance has access to an instance of a Django test client. This client can be accessed as self.client. This client is recreated for each test, so you dont have to worry about state (such as cookies) carrying over from one test to another. This means, instead of instantiating a Client in each test:
import unittest from django.test.client import Client class SimpleTest(unittest.TestCase): def test_details(self): client = Client() response = client.get(/customer/details/) self.failUnlessEqual(response.status_code, 200) def test_index(self): client = Client() response = client.get(/customer/index/) self.failUnlessEqual(response.status_code, 200)
244
Fixture loading fixtures A test case for a database-backed Web site isnt much use if there isnt any data in the database. To make it easy to put test data into the database, Djangos custom TestCase class provides a way of loading xtures. A xture is a collection of data that Django knows how to import into a database. For example, if your site has user accounts, you might set up a xture of fake user accounts in order to populate your database during tests. The most straightforward way of creating a xture is to use the manage.py dumpdata command. This assumes you already have some data in your database. See the dumpdata documentation for more details. Note: If youve ever run manage.py syncdb, youve already used a xture without even knowing it! When you call syncdb in the database for the rst time, Django installs a xture called initial_data. This gives you a way of populating a new database with any initial data, such as a default set of categories. Fixtures with other names can always be installed manually using the manage.py loaddata command. Once youve created a xture and placed it in a fixtures directory in one of your INSTALLED_APPS, you can use it in your unit tests by specifying a fixtures class attribute on your django.test.TestCase subclass:
from django.test import TestCase from myapp.models import Animal class AnimalTestCase(TestCase): fixtures = [mammals.json, birds] def setUp(self): # Test definitions as before. call_setup_methods() def testFluffyAnimals(self): # A test that uses the fixtures. call_some_test_code()
Heres specically what will happen: At the start of each test case, before setUp() is run, Django will ush the database, returning the database to the state it was in directly after syncdb was called. Then, all the named xtures are installed. In this example, Django will install any JSON xture named mammals, followed by any xture named birds. See the loaddata documentation for more details on dening and installing xtures. This ush/load procedure is repeated for each test in the test case, so you can be certain that the outcome of a test will not be affected by another test, or by the order of test execution. URLconf conguration New in version 1.0: Please, see the release notes urls If your application provides views, you may want to include tests that use the test client to exercise those views. However, an end user is free to deploy the views in your application at any URL of their choosing. This means that your tests cant rely upon the fact that your views will be available at a particular URL. In order to provide a reliable URL space for your test, django.test.TestCase provides the ability to customize the URLconf conguration for the duration of the execution of a test suite. If your TestCase instance denes an
245
urls attribute, the TestCase will use the value of that attribute as the ROOT_URLCONF for the duration of that test. For example:
from django.test import TestCase class TestMyViews(TestCase): urls = myapp.test_urls def testIndexPageView(self): # Here youd test your view using Client. call_some_test_code()
This test case will use the contents of myapp.test_urls as the URLconf for the duration of the test case. Multi-database support multi_db New in version 1.2: Please, see the release notes Django sets up a test database corresponding to every database that is dened in the DATABASES denition in your settings le. However, a big part of the time taken to run a Django TestCase is consumed by the call to flush that ensures that you have a clean database at the start of each test run. If you have multiple databases, multiple ushes are required (one for each database), which can be a time consuming activity especially if your tests dont need to test multi-database activity. As an optimization, Django only ushes the default database at the start of each test run. If your setup contains multiple databases, and you have a test that requires every database to be clean, you can use the multi_db attribute on the test suite to request a full ush. For example:
class TestMyViews(TestCase): multi_db = True def testIndexPageView(self): call_some_test_code()
This test case will ush all the test databases before running testIndexPageView. Emptying the test outbox New in version 1.0: Please, see the release notes If you use Djangos custom TestCase class, the test runner will clear the contents of the test e-mail outbox at the start of each test case. For more detail on e-mail services during tests, see E-mail services. Assertions New in version 1.0: Please, see the release notesChanged in version 1.2: Addded msg_prefix argument. As Pythons normal unittest.TestCase class implements assertion methods such as assertTrue and assertEquals, Djangos custom TestCase class provides a number of custom assertion methods that are useful for testing Web applications:
246
The failure messages given by the assertion methods can be customized with the msg_prefix argument. This string will be prexed to any failure message generated by the assertion. This allows you to provide additional details that may help you to identify the location and cause of an failure in your test suite. assertContains(response, text, count=None, status_code=200, msg_prex=) Asserts that a Response instance produced the given status_code and that text appears in the content of the response. If count is provided, text must occur exactly count times in the response. assertNotContains(response, text, status_code=200, msg_prex=) Asserts that a Response instance produced the given status_code and that text does not appears in the content of the response. assertFormError(response, form, eld, errors, msg_prex=) Asserts that a eld on a form raises the provided list of errors when rendered on the form. form is the name the Form instance was given in the template context. field is the name of the eld on the form to check. If field has a value of None, non-eld errors (errors you can access via form.non_field_errors()) will be checked. errors is an error string, or a list of error strings, that are expected as a result of form validation. assertTemplateUsed(response, template_name, msg_prex=) Asserts that the template with the given name was used in rendering the response. The name is a string such as admin/index.html. assertTemplateNotUsed(response, template_name, msg_prex=) Asserts that the template with the given name was not used in rendering the response. assertRedirects(response, expected_url, status_code=302, target_status_code=200, msg_prex=) Asserts that the response return a status_code redirect status, it redirected to expected_url (including any GET data), and the nal page was received with target_status_code. New in version 1.1: Please, see the release notes If your request used the follow argument, the expected_url and target_status_code will be the url and status code for the nal point of the redirect chain.
247
class EmailTest(TestCase): def test_send_email(self): # Send message. mail.send_mail(Subject here, Here is the message., [email protected], [[email protected]], fail_silently=False) # Test that one message has been sent. self.assertEquals(len(mail.outbox), 1) # Verify that the subject of the first message is correct. self.assertEquals(mail.outbox[0].subject, Subject here)
As noted previously, the test outbox is emptied at the start of every test in a Django TestCase. To empty the outbox manually, assign the empty list to mail.outbox:
from django.core import mail # Empty the test outbox mail.outbox = []
248
class DjangoTestSuiteRunner(verbosity=1, interactive=True, failfast=True, **kwargs) verbosity determines the amount of notication and debug information that will be printed to the console; 0 is no output, 1 is normal output, and 2 is verbose output. If interactive is True, the test suite has permission to ask the user for instructions when the test suite is executed. An example of this behavior would be asking for permission to delete an existing test database. If interactive is False, the test suite must be able to run without any manual intervention. If failfast is True, the test suite will stop running after the rst test failure is detected. Django will, from time to time, extend the capabilities of the test runner by adding new arguments. The **kwargs declaration allows for this expansion. If you subclass DjangoTestSuiteRunner or write your own test runner, ensure accept and handle the **kwargs parameter. run_tests(test_labels, extra_tests=None, **kwargs) Run the test suite. test_labels is a list of strings describing the tests to be run. A test label can take one of three forms: app.TestCase.test_method Run a single test method in a test case. app.TestCase Run all the test methods in a test case. app Search for and run all tests in the named application. If test_labels has a value of None, the test runner should run search for tests in all the applications in INSTALLED_APPS. extra_tests is a list of extra TestCase instances to add to the suite that is executed by the test runner. These extra tests are run in addition to those discovered in the modules listed in test_labels. This method should return the number of tests that failed. setup_test_environment(**kwargs) Sets up the test environment ready for testing. build_suite(test_labels, extra_tests=None, **kwargs) Constructs a test suite that matches the test labels provided. test_labels is a list of strings describing the tests to be run. A test label can take one of three forms: app.TestCase.test_method Run a single test method in a test case. app.TestCase Run all the test methods in a test case. app Search for and run all tests in the named application. If test_labels has a value of None, the test runner should run search for tests in all the applications in INSTALLED_APPS. extra_tests is a list of extra TestCase instances to add to the suite that is executed by the test runner. These extra tests are run in addition to those discovered in the modules listed in test_labels. Returns a TestSuite instance ready to be run. setup_databases(**kwargs) Creates the test databases. Returns a data structure that provides enough detail to undo the changes that have been made. This data will be provided to the teardown_databases() function at the conclusion of testing. run_suite(suite, **kwargs) Runs the test suite. Returns the result produced by the running the test suite.
249
teardown_databases(old_cong, **kwargs) Destroys the test databases, restoring pre-test conditions. old_config is a data structure dening the changes in the database conguration that need to be reversed. It is the return value of the setup_databases() method. teardown_test_environment(**kwargs) Restores the pre-test environment. suite_result(suite, result, **kwargs) Computes and returns a return code based on a test suite, and the result from that test suite.
250
CHAPTER
SEVENTEEN
17.1 Overview
The auth system consists of: Users Permissions: Binary (yes/no) ags designating whether a user may perform a certain task. Groups: A generic way of applying labels and permissions to more than one user. Messages: A simple way to queue messages for given users. Deprecated since version 1.2: The Messages component of the auth system will be removed in Django 1.4.
17.2 Installation
Authentication support is bundled as a Django application in django.contrib.auth. To install it, do the following: 1. Put django.contrib.auth and django.contrib.contenttypes in your INSTALLED_APPS setting. (The Permission model in django.contrib.auth depends on django.contrib.contenttypes.) 2. Run the command manage.py syncdb. Note that the default settings.py le created by django-admin.py startproject includes django.contrib.auth and django.contrib.contenttypes in INSTALLED_APPS for convenience. If your INSTALLED_APPS already contains these apps, feel free to run manage.py syncdb again; you can run that command as many times as youd like, and each time itll only install whats needed. The syncdb command creates the necessary database tables, creates permission objects for all installed apps that need em, and prompts you to create a superuser account the rst time you run it. Once youve taken those steps, thats it.
251
17.3 Users
class User()
252
jects can access their related objects in the same way as any other Django model:
myuser.groups = [group_list] myuser.groups.add(group, group, ...) myuser.groups.remove(group, group, ...) myuser.groups.clear() myuser.user_permissions = [permission_list] myuser.user_permissions.add(permission, permission, ...) myuser.user_permissions.remove(permission, permission, ...) myuser.user_permissions.clear()
In addition to those automatic API methods, User objects have the following custom methods: is_anonymous() Always returns False. This is a way of differentiating User and AnonymousUser objects. Generally, you should prefer using is_authenticated() to this method. is_authenticated() Always returns True. This is a way to tell if the user has been authenticated. This does not imply any permissions, and doesnt check if the user is active - it only indicates that the user has provided a valid username and password. get_full_name() Returns the first_name plus the last_name, with a space in between. set_password(raw_password) Sets the users password to the given raw string, taking care of the password hashing. Doesnt save the User object. check_password(raw_password) Returns True if the given raw string is the correct password for the user. (This takes care of the password hashing in making the comparison.) set_unusable_password() New in version 1.0: Please, see the release notes Marks the user as having no password set. This isnt the same as having a blank string for a password. check_password() for this user will never return True. Doesnt save the User object. You may need this if authentication for your application takes place against an existing external source such as an LDAP directory. has_usable_password() New in version 1.0: Please, see the release notes Returns False if set_unusable_password() has been called for this user. get_group_permissions(obj=None) Returns a list of permission strings that the user has, through his/her groups. New in version 1.2: Please, see the release notes If obj is passed in, only returns the group permissions for this specic object. get_all_permissions(obj=None) Returns a list of permission strings that the user has, both through group and user permissions. New in version 1.2: Please, see the release notes If obj is passed in, only returns the permissions for this specic object. has_perm(perm, obj=None) Returns True if the user has the specied permission, where perm is in the format "<app label>.<permission codename>". (see permissions section below). If the user is inactive, this method will always return False. New in version 1.2: Please, see the release notes If obj is passed in, this method wont check for a permission for the model, but for this specic object.
17.3. Users
253
has_perms(perm_list, obj=None) Returns True if the user has each of the specied permissions, where each perm is in the format "<app label>.<permission codename>". If the user is inactive, this method will always return False. New in version 1.2: Please, see the release notes If obj is passed in, this method wont check for permissions for the model, but for the specic object. has_module_perms(package_name) Returns True if the user has any permissions in the given package (the Django app label). If the user is inactive, this method will always return False. get_and_delete_messages() Returns a list of Message objects in the users queue and deletes the messages from the queue. email_user(subject, message, from_email=None) Sends an e-mail to the user. If from_email is None, Django uses the DEFAULT_FROM_EMAIL.
get_profile() Returns a site-specic prole for this user. Raises django.contrib.auth.models.SiteProfileNotAvailable if the current site doesnt allow proles. For information on how to dene a site-specic user prole, see the section on storing additional user information below. Manager functions class UserManager() The User model has a custom manager that has the following helper functions: create_user(username, email, password=None) Creates, saves and returns a User. The username and password are set as given. The domain portion of email is automatically convered to lowercase, and the returned User object will have is_active set to True. If no password is provided, set_unusable_password() will be called. See Creating users for example usage.
make_random_password(length=10, allowed_chars=abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ2345 Returns a random password with the given length and given string of allowed characters. (Note that the default value of allowed_chars doesnt contain letters that can cause user confusion, including: i, l, I, and 1 (lowercase letter i, lowercase letter L, uppercase letter i, and the number one) o, O, and 0 (uppercase letter o, lowercase letter o, and zero)
254
You can also create users using the Django admin site. Assuming youve enabled the admin site and hooked it to the URL /admin/, the Add user page is at /admin/auth/user/add/. You should also see a link to Users in the Auth section of the main admin index page. The Add user admin page is different than standard admin pages in that it requires you to choose a username and password before allowing you to edit the rest of the users elds. Also note: if you want your own user account to be able to create users using the Django admin site, youll need to give yourself permission to add users and change users (i.e., the Add user and Change user permissions). If your account has permission to add users but not to change them, you wont be able to add users. Why? Because if you have permission to add users, you have the power to create superusers, which can then, in turn, change other users. So Django requires add and change permissions as a slight security measure. Changing passwords New in version 1.2: The manage.py changepassword command was added. manage.py changepassword offers a method of changing a Users password from the command line. It prompts you to change the password of a given user which you must enter twice. If they both match, the new password will be changed immediately. If you do not supply a user, the command will attempt to change the password whose username matches the current user. You can also change a password programmatically, using set_password():
>>> >>> >>> >>> from django.contrib.auth.models import User u = User.objects.get(username__exact=john) u.set_password(new password) u.save()
Dont set the password attribute directly unless you know what youre doing. This is explained in the next section.
17.3.3 Passwords
The password attribute of a User object is a string in this format:
hashtype$salt$hash
Thats hashtype, salt and hash, separated by the dollar-sign character. Hashtype is either sha1 (default), md5 or crypt the algorithm used to perform a one-way hash of the password. Salt is a random string used to salt the raw password to create the hash. Note that the crypt method is only supported on platforms that have the standard Python crypt module available. New in version 1.0: Support for the crypt module is new in Django 1.0. For example:
sha1$a1976$a36cc8cbf81742a8fb52e221aaeab48ed7f58ab4
The set_password() and check_password() functions handle the setting and checking of these values behind the scenes. Previous Django versions, such as 0.90, used simple MD5 hashes without password salts. For backwards compatibility, those are still supported; theyll be converted automatically to the new style the rst time check_password() works correctly for a given user.
17.3. Users
255
In practice, you probably wont need to use AnonymousUser objects on your own, but theyre used by Web requests, as explained in the next section.
You will be prompted for a password. After you enter one, the user will be created immediately. If you leave off the --username or the --email options, it will prompt you for those values. If youre using an older release of Django, the old way of creating a superuser on the command line still works:
python /path/to/django/contrib/auth/create_superuser.py
...where /path/to is the path to the Django codebase on your lesystem. The manage.py command is preferred because it gures out the correct path and environment for you.
256
2. The name of the model (not case sensitive) class. For example, if the prole model was a class named UserProfile and was dened inside an application named accounts, the appropriate setting would be:
AUTH_PROFILE_MODULE = accounts.UserProfile
When a user prole model has been dened and specied in this manner, each User object will have a method get_profile() which returns the instance of the user prole model associated with that User. The method get_profile() does not create the prole, if it does not exist. You need to register a handler for the signal django.db.models.signals.post_save on the User model, and, in the handler, if created=True, create the associated user prole. For more information, see Chapter 12 of the Django book.
257
login() To log a user in, in a view, use login(). It takes an HttpRequest object and a User object. login() saves the users ID in the session, using Djangos session framework, so, as mentioned above, youll need to make sure to have the session middleware installed. This example shows how you might use both authenticate() and login():
from django.contrib.auth import authenticate, login def my_view(request): username = request.POST[username] password = request.POST[password] user = authenticate(username=username, password=password) if user is not None: if user.is_active: login(request, user) # Redirect to a success page. else: # Return a disabled account error message else: # Return an invalid login error message.
Calling authenticate() rst When youre manually logging a user in, you must call authenticate() before you call login(). authenticate() sets an attribute on the User noting which authentication backend successfully authenticated that user (see the backends documentation for details), and this information is needed later during the login process.
Note that logout() doesnt throw any errors if the user wasnt logged in. Changed in version 1.0: Calling logout() now cleans session data. When you call logout(), the session data for the current request is completely cleaned out. All existing data is removed. This is to prevent another person from using the same web browser to log in and have access to the previous users session data. If you want to put anything into the session that will be available to the user immediately after logging out, do that after calling django.contrib.auth.logout(). 258 Chapter 17. User authentication in Django
The login_required decorator login_required() As a shortcut, you can use the convenient login_required() decorator:
from django.contrib.auth.decorators import login_required @login_required def my_view(request): ...
login_required() does the following: If the user isnt logged in, redirect to settings.LOGIN_URL (/accounts/login/ by default), passing the current absolute URL in the query string. The name of the GET argument is determined by the redirect_field_name argument provided to the decorator. The default argument name is next. For example: /accounts/login/?next=/polls/3/. If the user is logged in, execute the view normally. The view code is free to assume the user is logged in. Note that youll need to map the appropriate Django view to settings.LOGIN_URL. For example, using the defaults, add the following line to your URLconf:
(r^accounts/login/$, django.contrib.auth.views.login),
259
If called via GET, it displays a login form that POSTs to the same URL. More on this in a bit. If called via POST, it tries to log the user in. If login is successful, the view redirects to the URL specied in next. If next isnt provided, it redirects to settings.LOGIN_REDIRECT_URL (which defaults to /accounts/profile/). If login isnt successful, it redisplays the login form. Its your responsibility to provide the login form in a template called registration/login.html by default. This template gets passed four template context variables: form: A Form object representing the login form. See the forms documentation for more on Form objects. next: The URL to redirect to after successful login. This may contain a query string, too. site: The current Site, according to the SITE_ID setting. If you dont have the site framework installed, this will be set to an instance of RequestSite, which derives the site name and domain from the current HttpRequest. site_name: An alias for site.name. If you dont have the site framework installed, this will be set to the value of request.META[SERVER_NAME]. For more on sites, see The sites framework. If youd prefer not to call the template registration/login.html, you can pass the template_name parameter via the extra arguments to the view in your URLconf. For example, this URLconf line would use myapp/login.html instead:
You can also specify the name of the GET eld which contains the URL to redirect to after login by passing redirect_field_name to the view. By default, the eld is called next. Heres a sample registration/login.html template you can use as a starting point. It assumes you have a base.html template that denes a content block:
{% extends "base.html" %} {% block content %} {% if form.errors %} <p>Your username and password didnt match. Please try again.</p> {% endif %} <form method="post" action="{% url django.contrib.auth.views.login %}">{% csrf_token %} <table> <tr> <td>{{ form.username.label_tag }}</td> <td>{{ form.username }}</td> </tr> <tr> <td>{{ form.password.label_tag }}</td> <td>{{ form.password }}</td> </tr> </table> <input type="submit" value="login" /> <input type="hidden" name="next" value="{{ next }}" /> </form> {% endblock %}
260
New in version 1.2: Please, see the release notes If you are using alternate authentication (see Other authentication sources) you can pass a custom authentication form to the login view via the authentication_form parameter. This form must accept a request keyword argument in its __init__ method, and provide a get_user method which returns the authenticated user object (this method is only ever called after successful form validation).
261
password_reset(request, [is_admin_site, template_name, email_template_name, password_reset_form, token_generator, post_reset_redirect]) Allows a user to reset their password, and sends them the new password in an e-mail. Optional arguments: template_name: The full name of a template to use for displaying the password reset form. This will default to registration/password_reset_form.html if not supplied. email_template_name: The full name of a template to use for generating the e-mail with the new password. This will default to registration/password_reset_email.html if not supplied. password_reset_form: PasswordResetForm. Form that will be used to set the password. Defaults to
token_generator: Instance of the class to check the password. This will default to default_token_generator, its an instance of django.contrib.auth.tokens.PasswordResetTokenGenerator. post_reset_redirect: The URL to redirect to after a successful password change. Template context: form: The form for resetting the users password. password_reset_done(request, [template_name]) The page shown after a user has reset their password. Optional arguments: template_name: The full name of a template to use. registration/password_reset_done.html if not supplied. redirect_to_login(next, [login_url, redirect_eld_name]) Redirects to the login page, and then back to another URL after a successful login. Required arguments: next: The URL to redirect to after a successful login. Optional arguments: login_url: The URL of the login page to redirect to. This will default to settings.LOGIN_URL if not supplied. redirect_field_name: The name of a GET eld containing the URL to redirect to after log out. Overrides next if the given GET parameter is passed. password_reset_confirm(request, [uidb36, token, template_name, token_generator, set_password_form, post_reset_redirect]) Presents a form for entering a new password. Optional arguments: uidb36: The users id encoded in base 36. This will default to None. token: Token to check that the password is valid. This will default to None. template_name: The full name of a template to display the conrm password view. Default value is registration/password_reset_confirm.html. token_generator: Instance of the class to check the password. This will default to default_token_generator, its an instance of django.contrib.auth.tokens.PasswordResetTokenGenerator. This will default to
262
set_password_form: SetPasswordForm.
post_reset_redirect: URL to redirect after the password reset done. This will default to None. password_reset_complete(request, [template_name]) Presents a view which informs the user that the password has been successfully changed. Optional arguments: template_name: The full name of a template to display the view. registration/password_reset_complete.html. This will default to
263
Were using this particular test as a relatively simple example. However, if you just want to test whether a permission is available to a user, you can use the permission_required() decorator, described later in this document. user_passes_test() takes a required argument: a callable that takes a User object and returns True if the user is allowed to view the page. Note that user_passes_test() does not automatically check that the User is not anonymous. user_passes_test() takes an optional login_url argument, which lets you specify the URL for your login page (settings.LOGIN_URL by default). For example:
from django.contrib.auth.decorators import user_passes_test @user_passes_test(lambda u: u.has_perm(polls.can_vote), login_url=/login/) def my_view(request): ...
The permission_required decorator permission_required() Its a relatively common task to check whether a user has a particular permission. For that reason, Django provides a shortcut for that case: the permission_required() decorator. Using this decorator, the earlier example can be written as:
from django.contrib.auth.decorators import permission_required @permission_required(polls.can_vote) def my_view(request): ...
As for the User.has_perm() method, permission names take the form "<app label>.<permission codename>" (i.e. polls.can_vote for a permission on a model in the polls application). Note that permission_required() also takes an optional login_url parameter. Example:
from django.contrib.auth.decorators import permission_required @permission_required(polls.can_vote, login_url=/loginpage/) def my_view(request): ...
264
from django.views.generic.date_based import object_detail @login_required def limited_object_detail(*args, **kwargs): return object_detail(*args, **kwargs)
17.5 Permissions
Django comes with a simple permissions system. It provides a way to assign permissions to specic users and groups of users. Its used by the Django admin site, but youre welcome to use it in your own code. The Django admin site uses permissions as follows: Access to view the add form and add an object is limited to users with the add permission for that type of object. Access to view the change list, view the change form and change an object is limited to users with the change permission for that type of object. Access to delete an object is limited to users with the delete permission for that type of object. Permissions are set globally per type of object, not per specic object instance. For example, its possible to say Mary may change news stories, but its not currently possible to say Mary may change news stories, but only the ones she created herself or Mary may only change news stories that have a certain status, publication date or ID. The latter functionality is something Django developers are currently discussing.
17.5. Permissions
265
class USCitizen(models.Model): # ... class Meta: permissions = ( ("can_drive", "Can drive"), ("can_vote", "Can vote in elections"), ("can_drink", "Can drink alcohol"), )
The only thing this does is create those extra permissions when you run manage.py syncdb.
17.6.1 Users
When rendering a template RequestContext, the currently logged-in user, either a User instance or an AnonymousUser instance, is stored in the template variable {{ user }}:
266
{% if user.is_authenticated %} <p>Welcome, {{ user.username }}. Thanks for logging in.</p> {% else %} <p>Welcome, new user. Please log in.</p> {% endif %}
This template context variable is not available if a RequestContext is not being used.
17.6.2 Permissions
The currently logged-in users permissions are stored in the template variable {{ perms }}. This is an instance of django.core.context_processors.PermWrapper, which is a template-friendly proxy of permissions. In the {{ perms }} object, single-attribute lookup is a proxy to User.has_module_perms. This example would display True if the logged-in user had any permissions in the foo app:
{{ perms.foo }}
Two-level-attribute lookup is a proxy to User.has_perm. This example would display True if the logged-in user had the permission foo.can_vote:
{{ perms.foo.can_vote }}
17.7 Groups
Groups are a generic way of categorizing users so you can apply permissions, or some other label, to those users. A user can belong to any number of groups. A user in a group automatically has the permissions granted to that group. For example, if the group Site editors has the permission can_edit_home_page, any user in that group will have that permission. Beyond permissions, groups are a convenient way to categorize users to give them some label, or extended functionality. For example, you could create a group Special users, and you could write code that could, say, give them access to a members-only portion of your site, or send them members-only e-mail messages.
17.7. Groups
267
17.8 Messages
Deprecated since version 1.2: This functionality will be removed in Django 1.4. You should use the messages framework for all new projects and begin to update your existing code immediately. The message system is a lightweight way to queue messages for given users. A message is associated with a User. Theres no concept of expiration or timestamps. Messages are used by the Django admin after successful actions. For example, "The poll Foo was created successfully." is a message. The API is simple: create(message) To create a new message, use user_obj.message_set.create(message=message_text). To retrieve/delete messages, use user_obj.get_and_delete_messages(), which returns a list of Message objects in the users queue (if any) and deletes the messages from the queue. In this example view, the system saves a message for the user after creating a playlist:
def create_playlist(request, songs): # Create the playlist with the given songs. # ... request.user.message_set.create(message="Your playlist was added successfully.") return render_to_response("playlists/create.html", context_instance=RequestContext(request))
When you use RequestContext, the currently logged-in user and his/her messages are made available in the template context as the template variable {{ messages }}. Heres an example of template code that displays messages:
{% if messages %} <ul> {% for message in messages %} <li>{{ message }}</li> {% endfor %} </ul> {% endif %}
Changed in version 1.2: The messages template variable uses a backwards compatible method in the messages framework to retrieve messages from both the user Message model and from the new framework. Unlike in previous revisions, the messages will not be erased unless they are actually displayed. Finally, note that this messages framework only works with users in the user database. To send messages to anonymous users, use the messages framework.
See the authentication backend reference for information on the authentication backends included with Django.
Thats the basic authentication scheme that checks the Django users database. The order of AUTHENTICATION_BACKENDS matters, so if the same username and password is valid in multiple backends, Django will stop processing at the rst positive match. Note: Once a user has authenticated, Django stores which backend was used to authenticate the user in the users session, and re-uses the same backend for subsequent authentication attempts for that user. This effectively means that authentication sources are cached, so if you change AUTHENTICATION_BACKENDS, youll need to clear out session data if you need to force users to re-authenticate using different methods. A simple way to do that is simply to execute Session.objects.all().delete().
The get_user method takes a user_id which could be a username, database ID or whatever and returns a User object. The authenticate method takes credentials as keyword arguments. Most of the time, itll just look like this:
class MyBackend: def authenticate(self, username=None, password=None): # Check the username/password and return a User.
Either way, authenticate should check the credentials it gets, and it should return a User object that matches those credentials, if the credentials are valid. If theyre not valid, it should return None. The Django admin system is tightly coupled to the Django User object described at the beginning of this document. For now, the best way to deal with this is to create a Django User object for each user that exists for your backend (e.g., in your LDAP directory, your external SQL database, etc.) You can either write a script to do this in advance, or your authenticate method can do it the rst time a user logs in.
269
Heres an example backend that authenticates against a username and password variable dened in your settings.py le and creates a Django User object the rst time a user authenticates:
from django.conf import settings from django.contrib.auth.models import User, check_password class SettingsBackend: """ Authenticate against the settings ADMIN_LOGIN and ADMIN_PASSWORD. Use the login name, and a hash of the password. For example: ADMIN_LOGIN = admin ADMIN_PASSWORD = sha1$4e987$afbcf42e21bd417fb71db8c66b321e9fc33051de """ def authenticate(self, username=None, password=None): login_valid = (settings.ADMIN_LOGIN == username) pwd_valid = check_password(password, settings.ADMIN_PASSWORD) if login_valid and pwd_valid: try: user = User.objects.get(username=username) except User.DoesNotExist: # Create a new user. Note that we can set password # to anything, because it wont be checked; the password # from settings.py will. user = User(username=username, password=get from settings.py) user.is_staff = True user.is_superuser = True user.save() return user return None def get_user(self, user_id): try: return User.objects.get(pk=user_id) except User.DoesNotExist: return None
270
This gives full permissions to the user granted access in the above example. Notice that the backend auth functions all take the user object as an argument, and they also accept the same arguments given to the associated django.contrib.auth.models.User functions. A full authorization implementation can be found in django/contrib/auth/backends.py, which is the default backend and queries the auth_permission table most of the time. Authorization for anonymous users Changed in version 1.2: Please, see the release notes An anonymous user is one that is not authenticated i.e. they have provided no valid authentication details. However, that does not necessarily mean they are not authorized to do anything. At the most basic level, most Web sites authorize anonymous users to browse most of the site, and many allow anonymous posting of comments etc. Djangos permission framework does not have a place to store permissions for anonymous users. However, it has a foundation that allows custom authentication backends to specify authorization for anonymous users. This is especially useful for the authors of re-usable apps, who can delegate all questions of authorization to the auth backend, rather than needing settings, for example, to control anonymous access. To enable this in your own backend, you must set the class attribute supports_anonymous_user to True. (This precaution is to maintain compatibility with backends that assume that all user objects are actual instances of the django.contrib.auth.models.User class). With this in place, django.contrib.auth.models.AnonymousUser will delegate all the relevant permission methods to the authentication backends. A nonexistent supports_anonymous_user attribute will raise a hidden PendingDeprecationWarning if used in Django 1.2. In Django 1.3, this warning will be upgraded to a DeprecationWarning, which will be displayed loudly. Additionally supports_anonymous_user will be set to False. Django 1.4 will assume that every backend supports anonymous users being passed to the authorization methods.
271
272
CHAPTER
EIGHTEEN
Django comes with a robust cache system that lets you save dynamic pages so they dont have to be calculated for each request. For convenience, Django offers different levels of cache granularity: You can cache the output of specic views, you can cache only the pieces that are difcult to produce, or you can cache your entire site. Django also works well with upstream caches, such as Squid (http://www.squid-cache.org/) and browser-based caches. These are the types of caches that you dont directly control but to which you can provide hints (via HTTP headers) about which parts of your site should be cached, and how.
273
18.1.1 Memcached
By far the fastest, most efcient type of cache available to Django, Memcached is an entirely memory-based cache framework originally developed to handle high loads at LiveJournal.com and subsequently open-sourced by Danga Interactive. Its used by sites such as Facebook and Wikipedia to reduce database access and dramatically increase site performance. Memcached is available for free at http://danga.com/memcached/ . It runs as a daemon and is allotted a specied amount of RAM. All it does is provide a fast interface for adding, retrieving and deleting arbitrary data in the cache. All data is stored directly in memory, so theres no overhead of database or lesystem usage. After installing Memcached itself, youll need to install python-memcached, which provides Python bindings to Memcached. This is available at ftp://ftp.tummy.com/pub/python-memcached/ Changed in version 1.2: In Django 1.0 and 1.1, you could also use cmemcache as a binding. However, support for this library was deprecated in 1.2 due to a lack of maintenance on the cmemcache library itself. Support for cmemcache will be removed completely in Django 1.4. To use Memcached with Django, set CACHE_BACKEND to memcached://ip:port/, where ip is the IP address of the Memcached daemon and port is the port on which Memcached is running. In this example, Memcached is running on localhost (127.0.0.1) port 11211:
CACHE_BACKEND = memcached://127.0.0.1:11211/
One excellent feature of Memcached is its ability to share cache over multiple servers. This means you can run Memcached daemons on multiple machines, and the program will treat the group of machines as a single cache, without the need to duplicate cache values on each machine. To take advantage of this feature, include all server addresses in CACHE_BACKEND, separated by semicolons. In this example, the cache is shared over Memcached instances running on IP address 172.19.26.240 and 172.19.26.242, both on port 11211:
CACHE_BACKEND = memcached://172.19.26.240:11211;172.19.26.242:11211/
In the following example, the cache is shared over Memcached instances running on the IP addresses 172.19.26.240 (port 11211), 172.19.26.242 (port 11212), and 172.19.26.244 (port 11213):
CACHE_BACKEND = memcached://172.19.26.240:11211;172.19.26.242:11212;172.19.26.244:11213/
A nal point about Memcached is that memory-based caching has one disadvantage: Because the cached data is stored in memory, the data will be lost if your server crashes. Clearly, memory isnt intended for permanent data storage, so dont rely on memory-based caching as your only data storage. Without a doubt, none of the Django caching backends should be used for permanent storage theyre all intended to be solutions for caching, not storage but we point this out here because memory-based caching is particularly temporary.
...where [cache_table_name] is the name of the database table to create. (This name can be whatever you want, as long as its a valid table name thats not already being used in your database.) This command creates a single table in your database that is in the proper format that Djangos database-cache system expects. Once youve created that database table, set your CACHE_BACKEND setting to "db://tablename", where tablename is the name of the database table. In this example, the cache tables name is my_cache_table:
274
CACHE_BACKEND = db://my_cache_table
The database caching backend uses the same database as specied in your settings le. You cant use a different database backend for your cache table. Database caching works best if youve got a fast, well-indexed database server.
Note that there are three forward slashes toward the beginning of that example. The rst two are for file://, and the third is the rst character of the directory path, /var/tmp/django_cache. If youre on Windows, put the drive letter after the file://, like this:
file://c:/foo/bar
The directory path should be absolute that is, it should start at the root of your lesystem. It doesnt matter whether you put a slash at the end of the setting. Make sure the directory pointed-to by this setting exists and is readable and writable by the system user under which your Web server runs. Continuing the above example, if your server runs as the user apache, make sure the directory /var/tmp/django_cache exists and is readable and writable by the user apache. Each cache value will be stored as a separate le whose contents are the cache data saved in a serialized (pickled) format, using Pythons pickle module. Each les name is the cache key, escaped for safe lesystem use.
Note that each process will have its own private cache instance, which means no cross-process caching is possible. This obviously also means the local memory cache isnt particularly memory-efcient, so its probably not a good choice for production environments. Its nice for development.
275
If youre building your own backend, you can use the standard cache backends as reference implementations. Youll nd the code in the django/core/cache/backends/ directory of the Django source. Note: Without a really compelling reason, such as a host that doesnt support them, you should stick to the cache backends included with Django. Theyve been well-tested and are easy to use.
Invalid arguments are silently ignored, as are invalid values of known arguments.
276
django.middleware.cache.FetchFromCacheMiddleware, )
Note: No, thats not a typo: the update middleware must be rst in the list, and the fetch middleware must be last. The details are a bit obscure, but see Order of MIDDLEWARE_CLASSES below if youd like the full story. Then, add the following required settings to your Django settings le: CACHE_MIDDLEWARE_SECONDS The number of seconds each page should be cached. CACHE_MIDDLEWARE_KEY_PREFIX If the cache is shared across multiple sites using the same Django installation, set this to the name of the site, or some other string that is unique to this Django instance, to prevent key collisions. Use an empty string if you dont care. The cache middleware caches every page that doesnt have GET or POST parameters. Optionally, if the CACHE_MIDDLEWARE_ANONYMOUS_ONLY setting is True, only anonymous requests (i.e., not those made by a logged-in user) will be cached. This is a simple and effective way of disabling caching for any user-specic pages (include Djangos admin interface). Note that if you use CACHE_MIDDLEWARE_ANONYMOUS_ONLY, you should make sure youve activated AuthenticationMiddleware. Additionally, the cache middleware automatically sets a few headers in each HttpResponse: Sets the Last-Modified header to the current date/time when a fresh (uncached) version of the page is requested. Sets the Expires header to the current date/time plus the dened CACHE_MIDDLEWARE_SECONDS. Sets the Cache-Control header to give a max age for the page again, CACHE_MIDDLEWARE_SECONDS setting. from the
See Middleware for more on middleware. New in version 1.0: Please, see the release notes If a view sets its own cache expiry time (i.e. it has a max-age section in its Cache-Control header) then the page will be cached until the expiry time, rather than CACHE_MIDDLEWARE_SECONDS. Using the decorators in django.views.decorators.cache you can easily set a views expiry time (using the cache_control decorator) or disable caching for a view (using the never_cache decorator). See the using other headers section for more on these decorators. New in version 1.2: Please, see the release notes If USE_I18N is set to True then the generated cache key will include the name of the active language. This allows you to easily cache multilingual sites without having to create the cache key yourself. See Deployment of translations for more on how Django discovers the active language.
cache_page takes a single argument: the cache timeout, in seconds. In the above example, the result of the my_view() view will be cached for 15 minutes. (Note that weve written it as 60 * 15 for the purpose of readability. 60 * 15 will be evaluated to 900 that is, 15 minutes multiplied by 60 seconds per minute.)
277
The per-view cache, like the per-site cache, is keyed off of the URL. If multiple URLs point at the same view, each URL will be cached separately. Continuing the my_view example, if your URLconf looks like this:
urlpatterns = (, (r^foo/(\d{1,2})/$, my_view), )
then requests to /foo/1/ and /foo/23/ will be cached separately, as you may expect. But once a particular URL (e.g., /foo/23/) has been requested, subsequent requests to that URL will use the cache. cache_page can also take an optional keyword argument, key_prefix, which works in the same way as the CACHE_MIDDLEWARE_KEY_PREFIX setting for the middleware. It can be used like this:
@cache_page(60 * 15, key_prefix="site1") def my_view(request): ...
If you take this approach, dont forget to import cache_page within your URLconf.
278
Sometimes you might want to cache multiple copies of a fragment depending on some dynamic data that appears inside the fragment. For example, you might want a separate cached copy of the sidebar used in the previous example for every user of your site. Do this by passing additional arguments to the {% cache %} template tag to uniquely identify the cache fragment:
{% load cache %} {% cache 500 sidebar request.user.username %} .. sidebar for logged in user .. {% endcache %}
Its perfectly ne to specify more than one argument to identify the fragment. Simply pass as many arguments to {% cache %} as you need. If USE_I18N is set to True the per-site middleware cache will respect the active language. For the cache template tag you could use one of the translation-specic variables available in templates to archieve the same result:
{% load i18n %} {% load cache %} {% get_current_language as LANGUAGE_CODE %} {% cache 600 welcome LANGUAGE_CODE %} {% trans "Welcome to example.com" %} {% endcache %}
The cache timeout can be a template variable, as long as the template variable resolves to an integer value. For example, if the template variable my_timeout is set to the value 600, then the following two examples are equivalent:
{% cache 600 sidebar %} ... {% endcache %} {% cache my_timeout sidebar %} ... {% endcache %}
This feature is useful in avoiding repetition in templates. You can set the timeout in a variable, in one place, and just reuse that value.
279
The timeout argument is optional and defaults to the timeout argument in the CACHE_BACKEND setting (explained above). Its the number of seconds the value should be stored in the cache. If the object doesnt exist in the cache, cache.get() returns None:
# Wait 30 seconds for my_key to expire... >>> cache.get(my_key) None
We advise against storing the literal value None in the cache, because you wont be able to distinguish between your stored None value and a cache miss signied by a return value of None. cache.get() can take a default argument. This species which value to return if the object doesnt exist in the cache:
>>> cache.get(my_key, has expired) has expired
New in version 1.0: Please, see the release notes To add a key only if it doesnt already exist, use the add() method. It takes the same parameters as set(), but it will not attempt to update the cache if the key specied is already present:
>>> cache.set(add_key, Initial value) >>> cache.add(add_key, New value) >>> cache.get(add_key) Initial value
If you need to know whether add() stored a value in the cache, you can check the return value. It will return True if the value was stored, False otherwise. Theres also a get_many() interface that only hits the cache once. get_many() returns a dictionary with all the keys you asked for that actually exist in the cache (and havent expired):
>>> cache.set(a, 1) >>> cache.set(b, 2) >>> cache.set(c, 3) >>> cache.get_many([a, b, c]) {a: 1, b: 2, c: 3}
New in version 1.2: Please, see the release notes To set multiple values more efciently, use set_many() to pass a dictionary of key-value pairs:
>>> cache.set_many({a: 1, b: 2, c: 3}) >>> cache.get_many([a, b, c]) {a: 1, b: 2, c: 3}
280
Like cache.set(), set_many() takes an optional timeout parameter. You can delete keys explicitly with delete(). This is an easy way of clearing the cache for a particular object:
>>> cache.delete(a)
New in version 1.2: Please, see the release notes If you want to clear a bunch of keys at once, delete_many() can take a list of keys to be cleared:
>>> cache.delete_many([a, b, c])
New in version 1.2: Please, see the release notes Finally, if you want to delete all the keys in the cache, use cache.clear(). Be careful with this; clear() will remove everything from the cache, not just the keys set by your application.
>>> cache.clear()
New in version 1.1: Please, see the release notes You can also increment or decrement a key that already exists using the incr() or decr() methods, respectively. By default, the existing cache value will incremented or decremented by 1. Other increment/decrement values can be specied by providing an argument to the increment/decrement call. A ValueError will be raised if you attempt to increment or decrement a nonexistent cache key.:
>>> >>> 2 >>> 12 >>> 11 >>> 6 cache.set(num, 1) cache.incr(num) cache.incr(num, 10) cache.decr(num) cache.decr(num, 5)
Note: incr()/decr() methods are not guaranteed to be atomic. On those backends that support atomic increment/decrement (most notably, the memcached backend), increment and decrement operations will be atomic. However, if the backend doesnt natively provide an increment/decrement operation, it will be implemented using a two-step retrieve/update.
281
Your Web browser caches pages, too. If a Web page sends out the appropriate headers, your browser will use the local cached copy for subsequent requests to that page, without even contacting the Web page again to see whether it has changed. Upstream caching is a nice efciency boost, but theres a danger to it: Many Web pages contents differ based on authentication and a host of other variables, and cache systems that blindly save pages based purely on URLs could expose incorrect or sensitive data to subsequent visitors to those pages. For example, say you operate a Web e-mail system, and the contents of the inbox page obviously depend on which user is logged in. If an ISP blindly cached your site, then the rst user who logged in through that ISP would have his user-specic inbox page cached for subsequent visitors to the site. Thats not cool. Fortunately, HTTP provides a solution to this problem. A number of HTTP headers exist to instruct upstream caches to differ their cache contents depending on designated variables, and to tell caching mechanisms not to cache particular pages. Well look at some of these headers in the sections that follow.
In this case, a caching mechanism (such as Djangos own cache middleware) will cache a separate version of the page for each unique user-agent. The advantage to using the vary_on_headers decorator rather than manually setting the Vary header (using something like response[Vary] = user-agent) is that the decorator adds to the Vary header (which may already exist), rather than setting it from scratch and potentially overriding anything that was already in there. You can pass multiple headers to vary_on_headers():
@vary_on_headers(User-Agent, Cookie) def my_view(request): # ...
This tells upstream caches to vary on both, which means each combination of user-agent and cookie will get its own cache value. For example, a request with the user-agent Mozilla and the cookie value foo=bar will be considered different from a request with the user-agent Mozilla and the cookie value foo=ham. Because varying on cookie is so common, theres a vary_on_cookie decorator. These two views are equivalent:
282
The headers you pass to vary_on_headers are not case sensitive; "User-Agent" is the same thing as "user-agent". You can also use a helper function, django.utils.cache.patch_vary_headers, directly. This function sets, or adds to, the Vary header. For example:
from django.utils.cache import patch_vary_headers def my_view(request): # ... response = render_to_response(template_name, context) patch_vary_headers(response, [Cookie]) return response
patch_vary_headers takes an HttpResponse instance as its rst argument and a list/tuple of case-insensitive header names as its second argument. For more on Vary headers, see the ofcial Vary spec.
This decorator takes care of sending out the appropriate HTTP header behind the scenes. There are a few other ways to control cache parameters. For example, HTTP allows applications to do the following: Dene the maximum time a page should be cached. Specify whether a cache should always check for newer versions, only delivering the cached content when there are no changes. (Some caches might deliver cached content even if the server page changed, simply because the cache copy isnt yet expired.)
283
In Django, use the cache_control view decorator to specify these cache parameters. In this example, cache_control tells caches to revalidate the cache on every access and to store cached versions for, at most, 3,600 seconds:
from django.views.decorators.cache import cache_control @cache_control(must_revalidate=True, max_age=3600) def my_view(request): # ...
Any valid Cache-Control HTTP directive is valid in cache_control(). Heres a full list: public=True private=True no_cache=True no_transform=True must_revalidate=True proxy_revalidate=True max_age=num_seconds s_maxage=num_seconds For explanation of Cache-Control HTTP directives, see the Cache-Control spec. (Note that the caching middleware already sets the cache headers max-age with the value of the CACHE_MIDDLEWARE_SETTINGS setting. If you use a custom max_age in a cache_control decorator, the decorator will take precedence, and the header values will be merged correctly.) If you want to use headers to disable caching altogether, django.views.decorators.cache.never_cache is a view decorator that adds headers to ensure the response wont be cached by browsers or other caches. Example:
from django.views.decorators.cache import never_cache @never_cache def myview(request): # ...
UpdateCacheMiddleware runs during the response phase, where middleware is run in reverse order, so an item at the top of the list runs last during the response phase. Thus, you need to make sure that UpdateCacheMiddleware appears before any other middleware that might add something to the Vary header. The following middleware modules do so: SessionMiddleware adds Cookie GZipMiddleware adds Accept-Encoding LocaleMiddleware adds Accept-Language FetchFromCacheMiddleware, on the other hand, runs during the request phase, where middleware is applied rst-to-last, so an item at the top of the list runs rst during the request phase. The FetchFromCacheMiddleware also needs to run after other middleware updates the Vary header, so FetchFromCacheMiddleware must be after any item that does so.
285
286
CHAPTER
NINETEEN
The two functions, to compute the ETag and the last modied time, will be passed the incoming request object and the same parameters, in the same order, as the view function they are helping to wrap. The function passed last_modified_func should return a standard datetime value specifying the last time the resource was modied, or None if the resource doesnt exist. The function passed to the etag decorator should return a string representing the Etag for the resource, or None if it doesnt exist. Using this feature usefully is probably best explained with an example. Suppose you have this pair of models, representing a simple blog system:
287
import datetime from django.db import models class Blog(models.Model): ... class Entry(models.Model): blog = models.ForeignKey(Blog) published = models.DateTimeField(default=datetime.datetime.now) ...
If the front page, displaying the latest blog entries, only changes when you add a new blog entry, you can compute the last modied time very quickly. You need the latest published date for every entry associated with that blog. One way to do this would be:
def latest_entry(request, blog_id): return Entry.objects.filter(blog=blog_id).latest("published").published
You can then use this function to provide early detection of an unchanged page for your front page view:
from django.views.decorators.http import condition @condition(last_modified_func=latest_entry) def front_page(request, blog_id): ...
We could write the earlier example, which only uses a last-modied function, using one of these decorators:
@last_modified(latest_entry) def front_page(request, blog_id): ...
...or:
def front_page(request, blog_id): ... front_page = last_modified(latest_entry)(front_page)
288
The rst decorator doesnt know anything about the second and might answer that the response is not modied even if the second decorators would determine otherwise. The condition decorator uses both callback functions simultaneously to work out the right action to take.
4. Server checks to see if the resource has changed, by computing the ETag the same way it does for a GET request (using the same function). If the resource has changed, it will return a 412 status code code, meaning precondition failed. 5. Client sends a GET request to /foo/, after receiving a 412 response, to retrieve an updated version of the content before updating it. The important thing this example shows is that the same functions can be used to compute the ETag and last modication values in all situations. In fact, you should use the same functions, so that the same values are returned every time.
289
You should choose the most appropriate tool for your particular problem here. If you have a way to compute ETags and modication times quickly and if some view takes a while to generate the content, you should consider using the condition decorator described in this document. If everything already runs fairly quickly, stick to using the middleware and the amount of network trafc sent back to the clients will still be reduced if the view hasnt changed.
290
CHAPTER
TWENTY
SENDING E-MAIL
Although Python makes sending e-mail relatively easy via the smtplib library, Django provides a couple of light wrappers over it. These wrappers are provided to make sending e-mail extra quick, to make it easy to test e-mail sending during development, and to provide support for platforms that cant use SMTP. The code lives in the django.core.mail module.
Mail is sent using the SMTP host and port specied in the EMAIL_HOST and EMAIL_PORT settings. The EMAIL_HOST_USER and EMAIL_HOST_PASSWORD settings, if set, are used to authenticate to the SMTP server, and the EMAIL_USE_TLS setting controls whether a secure connection is used. Note: The character set of e-mail sent with django.core.mail will be set to the value of your DEFAULT_CHARSET setting.
20.2 send_mail()
The simplest way to send e-mail is using the function django.core.mail.send_mail(). Heres its denition: send_mail(subject, message, from_email, recipient_list, auth_password=None, connection=None) fail_silently=False, auth_user=None,
The subject, message, from_email and recipient_list parameters are required. subject: A string. message: A string. from_email: A string. recipient_list: A list of strings, each an e-mail address. Each member of recipient_list will see the other recipients in the To: eld of the e-mail message. fail_silently: A boolean. If its False, send_mail will raise an smtplib.SMTPException. See the smtplib docs for a list of possible exceptions, all of which are subclasses of SMTPException. 291
auth_user: The optional username to use to authenticate to the SMTP server. If this isnt provided, Django will use the value of the EMAIL_HOST_USER setting. auth_password: The optional password to use to authenticate to the SMTP server. If this isnt provided, Django will use the value of the EMAIL_HOST_PASSWORD setting. connection: The optional e-mail backend to use to send the mail. If unspecied, an instance of the default backend will be used. See the documentation on E-mail backends for more details.
20.3 send_mass_mail()
django.core.mail.send_mass_mail() is intended to handle mass e-mailing. Heres the denition: send_mass_mail(datatuple, fail_silently=False, auth_user=None, auth_password=None, connection=None) datatuple is a tuple in which each element is in this format:
(subject, message, from_email, recipient_list)
fail_silently, auth_user and auth_password have the same functions as in send_mail(). Each separate element of datatuple results in a separate e-mail message. As in send_mail(), recipients in the same recipient_list will all see the other addresses in the e-mail messages To: eld. For example, the following code would send two different messages to two different sets of recipients; however, only one connection to the mail server would be opened:
message1 = (Subject here, Here is the message, [email protected], [[email protected], other@ex message2 = (Another Subject, Here is another message, [email protected], [[email protected]]) send_mass_mail((message1, message2), fail_silently=False)
20.4 mail_admins()
django.core.mail.mail_admins() is a shortcut for sending an e-mail to the site admins, as dened in the ADMINS setting. Heres the denition: mail_admins(subject, message, fail_silently=False, connection=None) mail_admins() prexes the subject with the value of the EMAIL_SUBJECT_PREFIX setting, which is "[Django] " by default. The From: header of the e-mail will be the value of the SERVER_EMAIL setting. This method exists for convenience and readability.
292
20.6 Examples
This sends a single e-mail to [email protected] and [email protected], with them both appearing in the To::
send_mail(Subject, Message., [email protected], [[email protected], [email protected]])
This sends a message to [email protected] and [email protected], with them both receiving a separate e-mail:
datatuple = ( (Subject, Message., [email protected], [[email protected]]), (Subject, Message., [email protected], [[email protected]]), ) send_mass_mail(datatuple)
293
# to get proper validation errors. return HttpResponse(Make sure all fields are entered and valid.)
294
send(fail_silently=False) sends the message. If a connection was specied when the e-mail was constructed, that connection will be used. Otherwise, an instance of the default backend will be instantiated and used. If the keyword argument fail_silently is True, exceptions raised while sending the message will be quashed. message() constructs a django.core.mail.SafeMIMEText object (a subclass of Pythons email.MIMEText.MIMEText class) or a django.core.mail.SafeMIMEMultipart object holding the message to be sent. If you ever need to extend the EmailMessage class, youll probably want to override this method to put the content you want into the MIME object. recipients() returns a list of all the recipients of the message, whether theyre recorded in the to or bcc attributes. This is another method you might need to override when subclassing, because the SMTP server needs to be told the full list of recipients when the message is sent. If you add another way to specify recipients in your class, they need to be returned from this method as well. attach() creates a new le attachment and adds it to the message. There are two ways to call attach(): You can pass it a single argument that is an email.MIMEBase.MIMEBase instance. This will be inserted directly into the resulting message. Alternatively, you can pass attach() three arguments: filename, content and mimetype. filename is the name of the le attachment as it will appear in the e-mail, content is the data that will be contained inside the attachment and mimetype is the optional MIME type for the attachment. If you omit mimetype, the MIME content type will be guessed from the lename of the attachment. For example:
message.attach(design.png, img_data, image/png)
attach_file() creates a new attachment using a le from your lesystem. Call it with the path of the le to attach and, optionally, the MIME type to use for the attachment. If the MIME type is omitted, it will be guessed from the lename. The simplest use would be:
message.attach_file(/images/weather_map.png)
Sending alternative content types It can be useful to include multiple versions of the content in an e-mail; the classic example is to send both text and HTML versions of a message. With Djangos e-mail library, you can do this using the EmailMultiAlternatives class. This subclass of EmailMessage has an attach_alternative() method for including extra versions of the message body in the e-mail. All the other methods (including the class initialization) are inherited directly from EmailMessage. To send a text and HTML combination, you could write:
from django.core.mail import EmailMultiAlternatives subject, from_email, to = hello, [email protected], [email protected] text_content = This is an important message. html_content = <p>This is an <strong>important</strong> message.</p> msg = EmailMultiAlternatives(subject, text_content, from_email, [to]) msg.attach_alternative(html_content, "text/html") msg.send()
By default, the MIME type of the body parameter in an EmailMessage is "text/plain". It is good practice to leave this alone, because it guarantees that any recipient will be able to read the e-mail, regardless of their mail client. However, if you are condent that your recipients can handle an alternative content type, you can use the
295
content_subtype attribute on the EmailMessage class to change the main content type. The major type will always be "text", but you can change the subtype. For example:
msg = EmailMessage(subject, html_content, from_email, [to]) msg.content_subtype = "html" # Main content is now text/html msg.send()
SMTPConnection objects Prior to version 1.2, Django provided a SMTPConnection class. This class provided a way to directly control the use of SMTP to send e-mail. This class has been deprecated in favor of the generic e-mail backend API.
296
For backwards compatibility SMTPConnection is still available in django.core.mail as an alias for the SMTP backend. New code should use get_connection() instead. Console backend Instead of sending out real e-mails the console backend just writes the e-mails that would be send to the standard output. By default, the console backend writes to stdout. You can use a different stream-like object by providing the stream keyword argument when constructing the connection. To specify this backend, put the following in your settings:
EMAIL_BACKEND = django.core.mail.backends.console.EmailBackend
This backend is not intended for use in production it is provided as a convenience that can be used during development. File backend The le backend writes e-mails to a le. A new le is created for each new session that is opened on this backend. The directory to which the les are written is either taken from the EMAIL_FILE_PATH setting or from the file_path keyword when creating a connection with get_connection(). To specify this backend, put the following in your settings:
EMAIL_BACKEND = django.core.mail.backends.filebased.EmailBackend EMAIL_FILE_PATH = /tmp/app-messages # change this to a proper location
This backend is not intended for use in production it is provided as a convenience that can be used during development. In-memory backend The locmem backend stores messages in a special attribute of the django.core.mail module. The outbox attribute is created when the rst message is send. Its a list with an EmailMessage instance for each message that would be send. To specify this backend, put the following in your settings:
EMAIL_BACKEND = django.core.mail.backends.locmem.EmailBackend
This backend is not intended for use in production it is provided as a convenience that can be used during development and testing. Dummy backend As the name suggests the dummy backend does nothing with your messages. To specify this backend, put the following in your settings:
EMAIL_BACKEND = django.core.mail.backends.dummy.EmailBackend
This backend is not intended for use in production it is provided as a convenience that can be used during development.
297
In this example, the call to send_messages() opens a connection on the backend, sends the list of messages, and then closes the connection again. The second approach is to use the open() and close() methods on the e-mail backend to manually control the connection. send_messages() will not manually open or close the connection if it is already open, so if you manually open the connection, you can control when it is closed. For example:
from django.core import mail connection = mail.get_connection() # Manually open the connection connection.open() # Construct an e-mail message that uses the connection email1 = mail.EmailMessage(Hello, Body goes here, [email protected], [[email protected]], connection=connection) email1.send() # Send the e-mail # Construct two more messages email2 = mail.EmailMessage(Hello, Body goes here, [email protected], [[email protected]]) email3 = mail.EmailMessage(Hello, Body goes here, [email protected], [[email protected]]) # Send the two e-mails in a single call -
298
connection.send_messages([email2, email3]) # The connection was already open so send_messages() doesnt close it. # We need to manually close the connection. connection.close()
This command will start a simple SMTP server listening on port 1025 of localhost. This server simply prints to standard output all e-mail headers and the e-mail body. You then only need to set the EMAIL_HOST and EMAIL_PORT accordingly, and you are set. For a more detailed discussion of testing and processing of e-mails locally, see the Python documentation on the SMTP Server.
20.11 SMTPConnection
class SMTPConnection() Deprecated since version 1.2. The SMTPConnection class has been deprecated in favor of the generic e-mail backend API. For backwards compatibility SMTPConnection is still available in django.core.mail as an alias for the SMTP backend. New code should use get_connection() instead.
299
300
CHAPTER
TWENTYONE
21.1.1 Internationalization
Overview The goal of internationalization is to allow a single Web application to offer its content and functionality in multiple languages and locales. For text translations, you, the Django developer, can accomplish this goal by adding a minimal amount of hooks to your Python and templates. These hooks are called translation strings. They tell Django: This text should be translated into the end users language, if a translation for this text is available in that language. Its your responsibility to mark translatable strings; the system can only translate strings it knows about. Django takes care of using these hooks to translate Web apps, on the y, according to users language preferences.
301
Standard translation
Specify a translation string by using the function ugettext(). Its convention to import this as a shorter alias, _, to save typing. Note: Pythons standard library gettext module installs _() into the global namespace, as an alias for gettext(). In Django, we have chosen not to follow this practice, for a couple of reasons: 1. For international character set (Unicode) support, ugettext() is more useful than gettext(). Sometimes, you should be using ugettext_lazy() as the default translation method for a particular le. Without _() in the global namespace, the developer has to think about which is the most appropriate translation function. 2. The underscore character (_) is used to represent the previous result in Pythons interactive shell and doctest tests. Installing a global _() function causes interference. Explicitly importing ugettext() as _() avoids this problem. In this example, the text "Welcome to my site." is marked as a translation string:
from django.utils.translation import ugettext as _ def my_view(request): output = _("Welcome to my site.") return HttpResponse(output)
Obviously, you could code this without using the alias. This example is identical to the previous one:
from django.utils.translation import ugettext def my_view(request): output = ugettext("Welcome to my site.") return HttpResponse(output)
Translation works on computed values. This example is identical to the previous two:
def my_view(request): words = [Welcome, to, my, site.] output = _( .join(words)) return HttpResponse(output)
(The caveat with using variables or computed values, as in the previous two examples, is that Djangos translationstring-detecting utility, django-admin.py makemessages, wont be able to nd these strings. More on makemessages later.) The strings you pass to _() or ugettext() can take placeholders, specied with Pythons standard named-string interpolation syntax. Example:
302
def my_view(request, m, d): output = _(Today is %(month)s, %(day)s.) % {month: m, day: d} return HttpResponse(output)
This technique lets language-specic translations reorder the placeholder text. For example, an English translation may be "Today is November, 26.", while a Spanish translation may be "Hoy es 26 de Noviembre." with the placeholders (the month and the day) with their positions swapped. For this reason, you should use named-string interpolation (e.g., %(day)s) instead of positional interpolation (e.g., %s or %d) whenever you have more than a single parameter. If you used positional interpolation, translations wouldnt be able to reorder placeholder text.
Pluralization
Use the function django.utils.translation.ungettext() to specify pluralized messages. ungettext takes three arguments: the singular translation string, the plural translation string and the number of objects. This function is useful when you need your Django application to be localizable to languages where the number and complexity of plural forms is greater than the two forms used in English (object for the singular and objects for all the cases where count is different from zero, irrespective of its value.) For example:
from django.utils.translation import ungettext def hello_world(request, count): page = ungettext(there is %(count)d object, there are %(count)d objects, count) % { count: count, } return HttpResponse(page)
In this example the number of objects is passed to the translation languages as the count variable. Lets see a slightly more complex usage example:
from django.utils.translation import ungettext count = Report.objects.count() if count == 1: name = Report._meta.verbose_name else: name = Report._meta.verbose_name_plural text = ungettext( There is %(count)d %(name)s available.,
21.1. Overview
303
There are %(count)d %(name)s available., count ) % { count: count, name: name }
Here we reuse localizable, hopefully already translated literals (contained in the verbose_name and verbose_name_plural model Meta options) for other parts of the sentence so all of it is consistently based on the cardinality of the elements at play. Note: When using this technique, make sure you use a single name for every extrapolated variable included in the literal. In the example above note how we used the name Python variable in both translation strings. This example would fail:
from django.utils.translation import ungettext from myapp.models import Report count = Report.objects.count() d = { count: count, name: Report._meta.verbose_name plural_name: Report._meta.verbose_name_plural } text = ungettext( There is %(count)d %(name)s available., There are %(count)d %(plural_name)s available., count ) % d
You would get a a format specification for argument name, as in msgstr[0], doesnt exist in msgid error when running django-admin.py compilemessages or a KeyError Python exception at runtime.
Lazy translation
Use the function django.utils.translation.ugettext_lazy() to translate strings lazily when the value is accessed rather than when the ugettext_lazy() function is called. For example, to translate a models help_text, do the following:
from django.utils.translation import ugettext_lazy class MyThing(models.Model): name = models.CharField(help_text=ugettext_lazy(This is the help text))
In this example, ugettext_lazy() stores a lazy reference to the string not the actual translation. The translation itself will be done when the string is used in a string context, such as template rendering on the Django admin site. The result of a ugettext_lazy() call can be used wherever you would use a unicode string (an object with type unicode) in Python. If you try to use it where a bytestring (a str object) is expected, things will not work as expected, since a ugettext_lazy() object doesnt know how to convert itself to a bytestring. You cant use a unicode string inside a bytestring, either, so this is consistent with normal Python behavior. For example:
304
# This is fine: putting a unicode proxy into a unicode string. u"Hello %s" % ugettext_lazy("people") # This will not work, since you cannot insert a unicode object # into a bytestring (nor can you insert our unicode proxy there) "Hello %s" % ugettext_lazy("people")
If you ever see output that looks like "hello <django.utils.functional...>", you have tried to insert the result of ugettext_lazy() into a bytestring. Thats a bug in your code. If you dont like the verbose name ugettext_lazy, you can just alias it as _ (underscore), like so:
from django.utils.translation import ugettext_lazy as _ class MyThing(models.Model): name = models.CharField(help_text=_(This is the help text))
Always use lazy translations in Django models. Field names and table names should be marked for translation (otherwise, they wont be translated in the admin interface). This means writing explicit verbose_name and verbose_name_plural options in the Meta class, though, rather than relying on Djangos default determination of verbose_name and verbose_name_plural by looking at the models class name:
from django.utils.translation import ugettext_lazy as _ class MyThing(models.Model): name = models.CharField(_(name), help_text=_(This is the help text)) class Meta: verbose_name = _(my thing) verbose_name_plural = _(mythings)
In this case, the lazy translations in result will only be converted to strings when result itself is used in a string (usually at template rendering time).
21.1. Overview
305
The allow_lazy() decorator Django offers many utility functions (particularly in django.utils) that take a string as their rst argument and do something to that string. These functions are used by template lters as well as directly in other code. If you write your own similar functions and deal with translations, youll face the problem of what to do when the rst argument is a lazy translation object. You dont want to convert it to a string immediately, because you might be using this function outside of a view (and hence the current threads locale setting will not be correct). For cases like this, use the django.utils.functional.allow_lazy() decorator. It modies the function so that if its called with a lazy translation as the rst argument, the function evaluation is delayed until it needs to be converted to a string. For example:
from django.utils.functional import allow_lazy def fancy_utility_function(s, ...): # Do some conversion on string s ... fancy_utility_function = allow_lazy(fancy_utility_function, unicode)
The allow_lazy() decorator takes, in addition to the function to decorate, a number of extra arguments (*args) specifying the type(s) that the original function can return. Usually, its enough to include unicode here and ensure that your function returns only Unicode strings. Using this decorator means you can write your function and assume that the input is a proper string, then add support for lazy translation objects at the end. Specifying translation strings: In template code Translations in Django templates uses two template tags and a slightly different syntax than in Python code. To give your template access to these tags, put {% load i18n %} toward the top of your template.
If the noop option is present, variable lookup still takes place but the translation is skipped. This is useful when stubbing out content that will require translation in the future:
<title>{% trans "myvar" noop %}</title>
Internally, inline translations use an ugettext call. In case a template var (myvar above) is passed to the tag, the tag will rst resolve such variable to a string at run-time and then look up that string in the message catalogs. Its not possible to mix a template variable inside a string within {% trans %}. If your translations require strings with variables (placeholders), use {% blocktrans %} instead.
306
To translate a template expression say, accessing object attributes or using template lters you need to bind the expression to a local variable for use within the translation block. Examples:
{% blocktrans with article.price as amount %} That will cost $ {{ amount }}. {% endblocktrans %} {% blocktrans with value|filter as myvar %} This will have {{ myvar }} inside. {% endblocktrans %}
If you need to bind more than one expression inside a blocktrans tag, separate the pieces with and:
{% blocktrans with book|title as book_t and author|title as author_t %} This is {{ book_t }} by {{ author_t }} {% endblocktrans %}
This tag is also in charge of handling another functionality: Pluralization. To make use of it you should: Designate and bind a counter value by using count, such value will be the one used to select the right plural form. Specify both the singular and plural forms separating them with the {% plural %} tag, which appears within {% blocktrans %} and {% endblocktrans %}. An example:
{% blocktrans count list|length as counter %} There is only one {{ name }} object. {% plural %} There are {{ counter }} {{ name }} objects. {% endblocktrans %}
When you both use the pluralization feature and bind values to local variables in addition to the counter value, have in mind that the blocktrans construct is internally converted to an ungettext call. This means the same notes regarding ungettext variables apply.
Other tags
Each RequestContext has access to three translation-specic variables:
21.1. Overview
307
LANGUAGES is a list of tuples in which the rst element is the language code and the second is the language name (translated into the currently active locale). LANGUAGE_CODE is the current users preferred language, as a string. Example: en-us. (See How Django discovers language preference.) LANGUAGE_BIDI is the current locales direction. If True, its a right-to-left language, e.g.: Hebrew, Arabic. If False its a left-to-right language, e.g.: English, French, German etc. If you dont use the RequestContext extension, you can get those values with three tags:
{% get_current_language as LANGUAGE_CODE %} {% get_available_languages as LANGUAGES %} {% get_current_language_bidi as LANGUAGE_BIDI %}
These tags also require a {% load i18n %}. Translation hooks are also available within any template block tag that accepts constant strings. In those cases, just use _() syntax to specify a translation string:
{% some_special_tag _("Page not found") value|yesno:_("yes,no") %}
In this case, both the tag and the lter will see the already-translated string, so they dont need to be aware of translations. Note: In this example, the translation infrastructure will be passed the string "yes,no", not the individual strings "yes" and "no". The translated string will need to contain the comma so that the lter parsing code knows how to split up the arguments. For example, a German translator might translate the string "yes,no" as "ja,nein" (keeping the comma intact). Specifying translation strings: In JavaScript code Adding translations to JavaScript poses some problems: JavaScript code doesnt have access to a gettext implementation. JavaScript code doesnt have access to .po or .mo les; they need to be delivered by the server. The translation catalogs for JavaScript should be kept as small as possible. Django provides an integrated solution for these problems: It passes the translations into JavaScript, so you can call gettext, etc., from within JavaScript.
308
Each string in packages should be in Python dotted-package syntax (the same format as the strings in INSTALLED_APPS) and should refer to a package that contains a locale directory. If you specify multiple packages, all those catalogs are merged into one catalog. This is useful if you have JavaScript that uses strings from different applications. By default, the view uses the djangojs gettext domain. This can be changed by altering the domain argument. You can make the view dynamic by putting the packages into the URL pattern:
urlpatterns = patterns(, (r^jsi18n/(?P<packages>\S+?)/$, django.views.i18n.javascript_catalog), )
With this, you specify the packages as a list of package names delimited by + signs in the URL. This is especially useful if your pages use code from different apps and this changes often and you dont want to pull in one big catalog le. As a security measure, these values can only be either django.conf or any package from the INSTALLED_APPS setting.
This uses reverse URL lookup to nd the URL of the JavaScript catalog view. When the catalog is loaded, your JavaScript code can use the standard gettext interface to access it:
document.write(gettext(this is to be translated));
The interpolation syntax is borrowed from Python, so the interpolate function supports both positional and named interpolation: Positional interpolation: obj contains a JavaScript Array object whose elements values are then sequentially interpolated in their corresponding fmt placeholders in the same order they appear. For example:
fmts = ngettext(There is %s object. Remaining: %s, There are %s objects. Remaining: %s, 11); s = interpolate(fmts, [11, 20]); // s is There are 11 objects. Remaining: 20
21.1. Overview
309
Named interpolation: This mode is selected by passing the optional boolean named parameter as true. obj contains a JavaScript object or associative array. For example:
d = { count: 10 total: 50 }; fmts = ngettext(Total: %(total)s, there is %(count)s object, there are %(count)s of a total of %(total)s objects, d.count); s = interpolate(fmts, d, true);
You shouldnt go over the top with string interpolation, though: this is still JavaScript, so the code has to make repeated regular-expression substitutions. This isnt as fast as string interpolation in Python, so keep it to those cases where you really need it (for example, in conjunction with ngettext to produce proper pluralizations). The set_language redirect view set_language(request) As a convenience, Django comes with a view, django.views.i18n.set_language(), that sets a users language preference and redirects back to the previous page. Activate this view by adding the following line to your URLconf:
(r^i18n/, include(django.conf.urls.i18n)),
(Note that this example makes the view available at /i18n/setlang/.) The view expects to be called via the POST method, with a language parameter set in request. If session support is enabled, the view saves the language choice in the users session. Otherwise, it saves the language choice in a cookie that is by default named django_language. (The name can be changed through the LANGUAGE_COOKIE_NAME setting.) After setting the language choice, Django redirects the user, following this algorithm: Django looks for a next parameter in the POST data. If that doesnt exist, or is empty, Django tries the URL in the Referrer header. If thats empty say, if a users browser suppresses that header then the user will be redirected to / (the site root) as a fallback. Heres example HTML template code:
<form action="/i18n/setlang/" method="post"> {% csrf_token %} <input name="next" type="hidden" value="/next/page/" /> <select name="language"> {% for lang in LANGUAGES %} <option value="{{ lang.0 }}">{{ lang.1 }}</option> {% endfor %} </select> <input type="submit" value="Go" /> </form>
310
21.1.2 Localization
This document covers two localization-related topics: Creating language les and locale aware date, time and numbers input/output in forms See Also: The Using internationalization in your own projects document included with the Django HOW-TO documents collection. How to create language les Once the string literals of an application have been tagged for later translation, the translation themselves need to be written (or obtained). Heres how that works. Locale restrictions Django does not support localizing your application into a locale for which Django itself has not been translated. In this case, it will ignore your translation les. If you were to try this and Django supported it, you would inevitably see a mixture of translated strings (from your application) and English strings (from Django itself). If you want to support a locale for your application that is not already part of Django, youll need to make at least a minimal translation of the Django core. A good starting point is to copy the Django English .po le and to translate at least some translation strings.
Message les
The rst step is to create a message le for a new language. A message le is a plain-text le, representing a single language, that contains all available translation strings and how they should be represented in the given language. Message les have a .po le extension. Django comes with a tool, django-admin.py makemessages, that automates the creation and upkeep of these les. A note to Django veterans The old tool bin/make-messages.py has been moved to the command django-admin.py makemessages to provide consistency throughout Django. Gettext utilities The makemessages command (and compilemessages discussed later) use commands from the GNU gettext toolset: xgettext, msgfmt, msgmerge and msguniq. Changed in version 1.2: Please, see the release notes The minimum version of the gettext utilities supported is 0.15. To create or update a message le, run this command:
django-admin.py makemessages -l de
...where de is the language code for the message le you want to create. The language code, in this case, is in locale format. For example, its pt_BR for Brazilian Portuguese and de_AT for Austrian German. The script should be run from one of two places: The root directory of your Django project. The root directory of your Django app.
21.1. Overview
311
The script runs over your project source tree or your application source tree and pulls out all strings marked for translation. It creates (or updates) a message le in the directory locale/LANG/LC_MESSAGES. In the de example, the le will be locale/de/LC_MESSAGES/django.po. By default django-admin.py makemessages examines every le that has the .html le extension. In case you want to override that default, use the --extension or -e option to specify the le extensions to examine:
django-admin.py makemessages -l de -e txt
Separate multiple extensions with commas and/or use -e or --extension multiple times:
django-admin.py makemessages -l de -e html,txt -e xml
When creating message les from JavaScript source code you need to use the special djangojs domain, not -e js. No gettext? If you dont have the gettext utilities installed, django-admin.py makemessages will create empty les. If thats the case, either install the gettext utilities or just copy the English message le (locale/en/LC_MESSAGES/django.po) if available and use it as a starting point; its just an empty translation le. Working on Windows? If youre using Windows and need to install the GNU gettext utilities so django-admin makemessages works see gettext on Windows for more information. The format of .po les is straightforward. Each .po le contains a small bit of metadata, such as the translation maintainers contact information, but the bulk of the le is a list of messages simple mappings between translation strings and the actual translated text for the particular language. For example, if your Django app contained a translation string for the text "Welcome to my site.", like so:
_("Welcome to my site.")
...then django-admin.py makemessages will have created a .po le containing the following snippet a message:
#: path/to/python/module.py:23 msgid "Welcome to my site." msgstr ""
A quick explanation: msgid is the translation string, which appears in the source. Dont change it. msgstr is where you put the language-specic translation. It starts out empty, so its your responsibility to change it. Make sure you keep the quotes around your translation. As a convenience, each message includes, in the form of a comment line prexed with # and located above the msgid line, the lename and line number from which the translation string was gleaned. Long messages are a special case. There, the rst string directly after the msgstr (or msgid) is an empty string. Then the content itself will be written over the next few lines as one string per line. Those strings are directly concatenated. Dont forget trailing spaces within the strings; otherwise, theyll be tacked together without whitespace! Mind your charset When creating a PO le with your favorite text editor, rst edit the charset line (search for "CHARSET") and set it to the charset youll be using to edit the content. Due to the way the gettext tools work internally and because we want to allow non-ASCII source strings in Djangos core and your applications, you must use UTF-8 as the encoding for
312
your PO le. This means that everybody will be using the same encoding, which is important when Django processes the PO les. To reexamine all source code and templates for new translation strings and update all message les for all languages, run this:
django-admin.py makemessages -a
Thats it. Your translations are ready for use. A note to Django veterans The old tool bin/compile-messages.py has been moved to the command django-admin.py compilemessages to provide consistency throughout Django. Working on Windows? If youre using Windows and need to install the GNU gettext utilities so django-admin compilemessages works see gettext on Windows for more information. Creating message les from JavaScript source code You create and update the message les the same way as the other Django message les with the django-admin.py makemessages tool. The only difference is you need to provide a -d djangojs parameter, like this:
django-admin.py makemessages -d djangojs -l de
This would create or update the message le for JavaScript for German. After updating message les, just run django-admin.py compilemessages the same way as you do with normal Django message les. gettext on Windows This is only needed for people who either want to extract message IDs or compile message les (.po). Translation work itself just involves editing existing les of this type, but if you want to create your own message les, or want to test or compile a changed message le, you will need the gettext utilities: Download the following zip les from the GNOME servers http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/ or from one of its mirrors gettext-runtime-X.zip gettext-tools-X.zip X is the version number, we are requiring 0.15 or higher.
21.1. Overview
313
Extract the contents of the bin\ directories in both les to the same folder on your system (i.e. C:\Program Files\gettext-utils) Update the system PATH: Control Panel > System > Advanced > Environment Variables. In the System variables list, click Path, click Edit. Add ;C:\Program Files\gettext-utils\bin at the end of the Variable value eld. You may also use gettext binaries you have obtained elsewhere, so long as the xgettext --version command works properly. Do not attempt to use Django translation utilities with a gettext package if the command xgettext --version entered at a Windows command prompt causes a popup window saying xgettext.exe has generated errors and will be closed by Windows. Format localization New in version 1.2: Please, see the release notes Djangos formatting system is disabled by default. To enable it, its necessary to set USE_L10N = True in your settings le. Note: The default settings.py le created by django-admin.py startproject includes USE_L10N = True for convenience. When using Djangos formatting system, dates and numbers on templates will be displayed using the format specied for the current locale. Two users accessing the same content, but in different language, will see date and number elds formatted in different ways, depending on the format for their current locale. Django will also use localized formats when parsing data in forms. That means Django uses different formats for different locales when guessing the format used by the user when inputting data on forms. Note: Django uses different formats for displaying data to those it uses for parsing data. Most notably, the formats for parsing dates cant use the %a (abbreviated weekday name), %A (full weekday name), %b (abbreviated month name), %B (full month name), or %p (AM/PM). To enable a form eld to localize input and output data simply use its localize argument:
class CashRegisterForm(forms.Form): product = forms.CharField() revenue = forms.DecimalField(max_digits=4, decimal_places=2, localize=True)
314
__init__.py formats.py
to use a space as a thousand separator, instead of the default for English, a comma.
21.1. Overview
315
(For more on middleware, see the middleware documentation.) LocaleMiddleware tries to determine the users language preference by following this algorithm: First, it looks for a django_language key in the current users session. Failing that, it looks for a cookie. Changed in version 1.0: Please, see the release notes In Django version 0.96 and before, the cookies name is hard-coded to django_language. In Django 1,0, The cookie name is set by the LANGUAGE_COOKIE_NAME setting. (The default name is django_language.) Failing that, it looks at the Accept-Language HTTP header. This header is sent by your browser and tells the server which language(s) you prefer, in order by priority. Django tries each language in the header until it nds one with available translations. Failing that, it uses the global LANGUAGE_CODE setting. Notes: In each of these places, the language preference is expected to be in the standard language format, as a string. For example, Brazilian Portuguese is pt-br. If a base language is available but the sublanguage specied is not, Django uses the base language. For example, if a user species de-at (Austrian German) but Django only has de available, Django uses de. Only languages listed in the LANGUAGES setting can be selected. If you want to restrict the language selection to a subset of provided languages (because your application doesnt provide all those languages), set LANGUAGES to a list of languages. For example:
LANGUAGES = ( (de, _(German)), (en, _(English)), )
This example restricts languages that are available for automatic selection to German and English (and any sublanguage, like de-ch or en-us). If you dene a custom LANGUAGES setting, as explained in the previous bullet, its OK to mark the languages as translation strings but use a dummy ugettext() function, not the one in django.utils.translation. You should never import django.utils.translation from within your settings le, because that module in itself depends on the settings, and that would cause a circular import. The solution is to use a dummy ugettext() function. Heres a sample settings le:
ugettext = lambda s: s LANGUAGES = ( (de, ugettext(German)), (en, ugettext(English)), )
With this arrangement, django-admin.py makemessages will still nd and mark these strings for translation, but the translation wont happen at runtime so youll have to remember to wrap the languages in the real ugettext() in any code that uses LANGUAGES at runtime. 316 Chapter 21. Internationalization and localization
The LocaleMiddleware can only select languages for which there is a Django-provided base translation. If you want to provide translations for your application that arent already in the set of translations in Djangos source tree, youll want to provide at least a basic one as described in the Locale restrictions note. Once LocaleMiddleware determines the users preference, it makes this preference available as request.LANGUAGE_CODE for each HttpRequest. Feel free to read this value in your view code. Heres a simple example:
def hello_world(request, count): if request.LANGUAGE_CODE == de-at: return HttpResponse("You prefer to read Austrian German.") else: return HttpResponse("You prefer to read another language.")
Note that, with static (middleware-less) translation, the language is in settings.LANGUAGE_CODE, while with dynamic (middleware) translation, its in request.LANGUAGE_CODE.
21.2 Glossary
First lets dene some terms that will help us to handle a common language: locale name A locale name, either a language specication of the form ll or a combined language and country specication of the form ll_CC. Examples: it, de_AT, es, pt_BR. Note the underscore in some of them and the case of the part located to its right. language code Represents the name of a language. Browsers send the names of the languages they accept in the Accept-Language HTTP header using this format. Examples: it, de-at, es, pt-br. Note the - separator. message le A message le is a plain-text le, representing a single language, that contains all available translation strings and how they should be represented in the given language. Message les have a .po le extension. translation string A literal that can be translated.
21.2. Glossary
317
318
CHAPTER
TWENTYTWO
PAGINATION
Changed in version 1.0: Pagination facilities have been almost fully reworked. Django provides a few classes that help you manage paginated data that is, data thats split across several pages, with Previous/Next links. These classes live in django/core/paginator.py.
22.1 Example
Give Paginator a list of objects, plus the number of items youd like to have on each page, and it gives you methods for accessing the items for each page:
>>> from django.core.paginator import Paginator >>> objects = [john, paul, george, ringo] >>> p = Paginator(objects, 2) >>> 4 >>> 2 >>> [1, p.count p.num_pages p.page_range 2]
>>> page1 = p.page(1) >>> page1 <Page 1 of 2> >>> page1.object_list [john, paul] >>> page2 = p.page(2) >>> page2.object_list [george, ringo] >>> page2.has_next() False >>> page2.has_previous() True >>> page2.has_other_pages() True >>> page2.next_page_number() 3 >>> page2.previous_page_number() 1 >>> page2.start_index() # The 1-based index of the first item on this page 3
319
>>> page2.end_index() # The 1-based index of the last item on this page 4 >>> p.page(0) Traceback (most ... EmptyPage: That >>> p.page(3) Traceback (most ... EmptyPage: That
recent call last): page number is less than 1 recent call last): page contains no results
Note: Note that you can give Paginator a list/tuple, a Django QuerySet, or any other object with a count() or __len__() method. When determining the number of objects contained in the passed object, Paginator will rst try calling count(), then fallback to using len() if the passed object has no count() method. This allows objects such as Djangos QuerySet to use a more efcient count() method when available.
In the template list.html, youll want to include navigation between pages along with any interesting information from the objects themselves:
{% for contact in contacts.object_list %} {# Each "contact" is a Contact model object. #} {{ contact.full_name|upper }}<br /> ... {% endfor %} <div class="pagination">
320
<span class="step-links"> {% if contacts.has_previous %} <a href="?page={{ contacts.previous_page_number }}">previous</a> {% endif %} <span class="current"> Page {{ contacts.number }} of {{ contacts.paginator.num_pages }}. </span> {% if contacts.has_next %} <a href="?page={{ contacts.next_page_number }}">next</a> {% endif %} </span> </div>
22.3.3 Methods
page(number) Returns a Page object with the given 1-based index. Raises InvalidPage if the given page number doesnt exist.
22.3.4 Attributes
count The total number of objects, across all pages.
321
Note: When determining the number of objects contained in object_list, Paginator will rst try calling object_list.count(). If object_list has no count() method, then Paginator will fallback to using object_list.__len__(). This allows objects, such as Djangos QuerySet, to use a more efcient count() method when available. num_pages The total number of pages. page_range A 1-based range of page numbers, e.g., [1, 2, 3, 4].
22.5.1 Methods
has_next() Returns True if theres a next page. has_previous() Returns True if theres a previous page. has_other_pages() Returns True if theres a next or previous page. next_page_number() Returns the next page number. Note that this is dumb and will return the next page number regardless of whether a subsequent page exists. previous_page_number() Returns the previous page number. Note that this is dumb and will return the previous page number regardless of whether a previous page exists. start_index() Returns the 1-based index of the rst object on the page, relative to all of the objects in the paginators list. For example, when paginating a list of 5 objects with 2 objects per page, the second pages start_index() would return 3.
322
end_index() Returns the 1-based index of the last object on the page, relative to all of the objects in the paginators list. For example, when paginating a list of 5 objects with 2 objects per page, the second pages end_index() would return 4.
22.5.2 Attributes
object_list The list of objects on this page. number The 1-based page number for this page. paginator The associated Paginator object.
323
324
CHAPTER
TWENTYTHREE
The arguments to the serialize function are the format to serialize the data to (see Serialization formats) and a QuerySet to serialize. (Actually, the second argument can be any iterator that yields Django objects, but itll almost always be a QuerySet). You can also use a serializer object directly:
XMLSerializer = serializers.get_serializer("xml") xml_serializer = XMLSerializer() xml_serializer.serialize(queryset) data = xml_serializer.getvalue()
This is useful if you want to serialize data directly to a le-like object (which includes an HttpResponse):
out = open("file.xml", "w") xml_serializer.serialize(SomeModel.objects.all(), stream=out)
325
In this example, only the name and size attributes of each model will be serialized. Note: Depending on your model, you may nd that it is not possible to deserialize a model that only serializes a subset of its elds. If a serialized object doesnt specify all the elds that are required by a model, the deserializer will not be able to save deserialized instances.
the elds on the serialized output will only contain the serves_hot_dogs attribute. The name attribute of the base class will be ignored. In order to fully serialize your Restaurant instances, you will need to serialize the Place models as well:
all_objects = list(Restaurant.objects.all()) + list(Place.objects.all()) data = serializers.serialize(xml, all_objects)
As you can see, the deserialize function takes the same format argument as serialize, a string or stream of data, and returns an iterator. However, here it gets slightly complicated. The objects returned by the deserialize iterator arent simple Django objects. Instead, they are special DeserializedObject instances that wrap a created but unsaved object and any associated relationship data. Calling DeserializedObject.save() saves the object to the database. This ensures that deserializing is a non-destructive operation even if the data in your serialized representation doesnt match whats currently in the database. Usually, working with these DeserializedObject instances looks something like:
326
In other words, the usual use is to examine the deserialized objects to make sure that they are appropriate for saving before doing so. Of course, if you trust your data source you could just save the object and move on. The Django object itself can be inspected as deserialized_object.object.
The Django source code includes the simplejson module. However, if youre using Python 2.6 (which includes a builtin version of the module), Django will use the builtin json module automatically. If you have a system installed version that includes the C-based speedup extension, or your system version is more recent than the version shipped with Django (currently, 2.0.7), the system version will be used instead of the version included with Django. Be aware that if youre serializing using that module directly, not all Django output can be passed unmodied to simplejson. In particular, lazy translation objects need a special encoder written for them. Something like this will work:
from django.utils.functional import Promise from django.utils.encoding import force_unicode class LazyEncoder(simplejson.JSONEncoder): def default(self, obj): if isinstance(obj, Promise): return force_unicode(obj) return super(LazyEncoder, self).default(obj)
327
Ordinarily, serialized data for Book would use an integer to refer to the author. For example, in JSON, a Book might be serialized as:
... { "pk": 1, "model": "store.book", "fields": { "name": "Mostly Harmless", "author": 42 } } ...
This isnt a particularly natural way to refer to an author. It requires that you know the primary key value for the author; it also requires that this primary key value is stable and predictable. However, if we add natural key handling to Person, the xture becomes much more humane. To add natural key handling, you dene a default Manager for Person with a get_by_natural_key() method. In the case of a Person, a good natural key might be the pair of rst and last name:
328
from django.db import models class PersonManager(models.Manager): def get_by_natural_key(self, first_name, last_name): return self.get(first_name=first_name, last_name=last_name) class Person(models.Model): objects = PersonManager() first_name = models.CharField(max_length=100) last_name = models.CharField(max_length=100) birthdate = models.DateField() class Meta: unique_together = ((first_name, last_name),)
Now books can use that natural key to refer to Person objects:
... { "pk": 1, "model": "store.book", "fields": { "name": "Mostly Harmless", "author": ["Douglas", "Adams"] } } ...
When you try to load this serialized data, Django will use the get_by_natural_key() method to resolve ["Douglas", "Adams"] into the primary key of an actual Person object. Note: Whatever elds you use for a natural key must be able to uniquely identify an object. This will usually mean that your model will have a uniqueness clause (either unique=True on a single eld, or unique_together over multiple elds) for the eld or elds in your natural key. However, uniqueness doesnt need to be enforced at the database level. If you are certain that a set of elds will be effectively unique, you can still use those elds as a natural key.
329
That method should always return a natural key tuple in this example, (first name, last name). Then, when you call serializers.serialize(), you provide a use_natural_keys=True argument:
>>> serializers.serialize([book1, book2], format=json, indent=2, use_natural_keys=True)
When use_natural_keys=True is specied, Django will use the natural_key() method to serialize any reference to objects of the type that denes the method. If you are using dumpdata to generate serialized data, you use the natural command line ag to generate natural keys. Note: You dont need to dene both natural_key() and get_by_natural_key(). If you dont want Django to output natural keys during serialization, but you want to retain the ability to load natural keys, then you can opt to not implement the natural_key() method. Conversely, if (for some strange reason) you want Django to output natural keys during serialization, but not be able to load those key values, just dont dene the get_by_natural_key() method.
The natural key for a Permission is a combination of the codename for the Permission, and the ContentType to which the Permission applies. This means that ContentType must be serialized before Permission. To dene this dependency, we add one extra line:
class Permission(models.Model): # ... def natural_key(self): return (self.codename,) + self.content_type.natural_key() natural_key.dependencies = [contenttypes.contenttype]
330
This denition ensures that ContentType models are serialized before Permission models. In turn, any object referencing Permission will be serialized after both ContentType and Permission.
331
332
CHAPTER
TWENTYFOUR
DJANGO SETTINGS
A Django settings le contains all the conguration of your Django installation. This document explains how settings work and which settings are available.
Because a settings le is a Python module, the following apply: It doesnt allow for Python syntax errors. It can assign settings dynamically using normal Python syntax. For example:
MY_SETTING = [str(i) for i in range(30)]
333
334
Note that django.conf.settings isnt a module its an object. So importing individual settings is not possible:
from django.conf.settings import DEBUG # This wont work.
Also note that your code should not import from either global_settings or your own settings le. django.conf.settings abstracts the concepts of default settings and site-specic settings; it presents a single interface. It also decouples the code that uses settings from the location of your settings.
24.6 Security
Because a settings le contains sensitive information, such as the database password, you should make every attempt to limit access to it. For example, change its le permissions so that only you and your Web servers user can read it. This is especially important in a shared-hosting environment.
335
Pass configure() as many keyword arguments as youd like, with each keyword argument representing a setting and its value. Each argument name should be all uppercase, with the same name as the settings described above. If a particular setting is not passed to configure() and is needed at some later point, Django will use the default setting value. Conguring Django in this fashion is mostly necessary and, indeed, recommended when youre using a piece of the framework inside a larger application. Consequently, when congured via settings.configure(), Django will not make any modications to the process environment variables (see the documentation of TIME_ZONE for why this would normally occur). Its assumed that youre already in full control of your environment in these cases.
Normally, you will not need to override the defaults in this fashion. The Django defaults are sufciently tame that you can safely use them. Be aware that if you do pass in a new default module, it entirely replaces the Django defaults, so you must specify a value for every possible setting that might be used in that code you are importing. Check in django.conf.settings.global_settings for the full list.
336
337
338
CHAPTER
TWENTYFIVE
SIGNALS
Django includes a signal dispatcher which helps allow decoupled applications get notied when actions occur elsewhere in the framework. In a nutshell, signals allow certain senders to notify a set of receivers that some action has taken place. Theyre especially useful when many pieces of code may be interested in the same events. Django provides a set of built-in signals that let user code get notied by Django itself of certain actions. These include some useful notications: django.db.models.signals.pre_save & django.db.models.signals.post_save Sent before or after a models save() method is called. django.db.models.signals.pre_delete & django.db.models.signals.post_delete Sent before or after a models delete() method is called. django.db.models.signals.m2m_changed Sent when a ManyToManyField on a model is changed. django.core.signals.request_started & django.core.signals.request_finished Sent when Django starts or nishes an HTTP request. See the built-in signal documentation for a complete list, and a complete explanation of each signal. You can also dene and send your own custom signals; see below.
Notice that the function takes a sender argument, along with wildcard keyword arguments (**kwargs); all signal handlers must take these arguments.
339
Well look at senders a bit later, but right now look at the **kwargs argument. All signals send keyword arguments, and may change those keyword arguments at any time. In the case of request_finished, its documented as sending no arguments, which means we might be tempted to write our signal handling as my_callback(sender). This would be wrong in fact, Django will throw an error if you do so. Thats because at any point arguments could get added to the signal and your receiver must be able to handle those new arguments.
Now, our my_callback function will be called each time a request nishes. Where should this code live? You can put signal handling and registration code anywhere you like. However, youll need to make sure that the module its in gets imported early on so that the signal handling gets registered before any signals need to be sent. This makes your apps models.py a good place to put registration of signal handlers.
The my_handler function will only be called when an instance of MyModel is saved. Different signals use different objects as their senders; youll need to consult the built-in signal documentation for details of each particular signal.
340
This declares a pizza_done signal that will provide receivers with toppings and size arguments. Remember that youre allowed to change this list of arguments at any time, so getting the API right on the rst try isnt necessary.
341
342
Part III
How-to guides
343
Here youll nd short answers to How do I....? types of questions. These how-to guides dont cover topics in depth youll nd that material in the Using Django and the API Reference. However, these guides will help you quickly accomplish common tasks.
345
346
CHAPTER
TWENTYSIX
Using the authentication handler with Apache 2.2 If youre using Apache 2.2, youll need to take a couple extra steps. Youll need to ensure that mod_auth_basic and mod_authz_user are loaded. These might be compiled statically into Apache, or you might need to use LoadModule to load them dynamically (as shown in the example at the bottom of this note). Youll also need to insert conguration directives that prevent Apache from trying to use other authentication modules, as well as specifying the AuthUserFile directive and pointing it to /dev/null. Depending on which other authentication modules you have loaded, you might need one or more of the following directives:
347
AuthBasicAuthoritative Off AuthDefaultAuthoritative Off AuthzLDAPAuthoritative Off AuthzDBMAuthoritative Off AuthzDefaultAuthoritative Off AuthzGroupFileAuthoritative Off AuthzOwnerAuthoritative Off AuthzUserAuthoritative Off
A complete conguration, with differences between Apache 2.0 and Apache 2.2 marked in bold, would look something like:
LoadModule auth_basic_module modules/mod_auth_basic.so LoadModule authz_user_module modules/mod_authz_user.so ... <Location /example/> AuthType Basic AuthName "example.com" AuthUserFile /dev/null AuthBasicAuthoritative Off Require valid-user SetEnv DJANGO_SETTINGS_MODULE mysite.settings PythonAuthenHandler django.contrib.auth.handlers.modpython </Location>
By default, the authentication handler will limit access to the /example/ location to users marked as staff members. You can use a set of PythonOption directives to modify this behavior: PythonOption Explanation DjangoRequireStaffStatus If set to on only staff users (i.e. those with the is_staff ag set) will be allowed. Defaults to on. DjangoRequireSuperuserStatus If set to on only superusers (i.e. those with the is_superuser ag set) will be allowed. Defaults to off. DjangoPermissionName The name of a permission to require for access. See custom permissions for more information. By default no specic permission will be required. Note that sometimes SetEnv doesnt play well in this mod_python conguration, for reasons unknown. If youre having problems getting mod_python to recognize your DJANGO_SETTINGS_MODULE, you can set it using PythonOption instead of SetEnv. Therefore, these two Apache directives are equivalent:
SetEnv DJANGO_SETTINGS_MODULE mysite.settings PythonOption DJANGO_SETTINGS_MODULE mysite.settings
348
CHAPTER
TWENTYSEVEN
27.1 Conguration
First, you must add the django.contrib.auth.middleware.RemoteUserMiddleware to the MIDDLEWARE_CLASSES setting after the django.contrib.auth.middleware.AuthenticationMiddleware:
MIDDLEWARE_CLASSES = ( ... django.contrib.auth.middleware.AuthenticationMiddleware, django.contrib.auth.middleware.RemoteUserMiddleware, ... )
Next, you must replace the ModelBackend with RemoteUserBackend in the AUTHENTICATION_BACKENDS setting:
AUTHENTICATION_BACKENDS = ( django.contrib.auth.backends.RemoteUserBackend, )
With this setup, RemoteUserMiddleware will detect the username in request.META[REMOTE_USER] and will authenticate and auto-login that user using the RemoteUserBackend. Note: Since the RemoteUserBackend inherits from ModelBackend, you will still have all of the same permissions checking that is implemented in ModelBackend. If your authentication mechanism uses a custom HTTP header and not REMOTE_USER, you can subclass RemoteUserMiddleware and set the header attribute to the desired request.META key. For example:
349
27.2 RemoteUserBackend
class RemoteUserBackend() If you need more control, you can create your own authentication backend that inherits from RemoteUserBackend and overrides certain parts:
27.2.1 Attributes
create_unknown_user True or False. Determines whether or not a User object is created if not already in the database. Defaults to True.
27.2.2 Methods
clean_username(username) Performs any cleaning on the username (e.g. stripping LDAP DN information) prior to using it to get or create a User object. Returns the cleaned username. configure_user(user) Congures a newly created user. This method is called immediately after a new user is created, and can be used to perform custom setup actions, such as setting the users groups based on attributes in an LDAP directory. Returns the user object.
350
CHAPTER
TWENTYEIGHT
In this example, the closepoll command will be made available to any project that includes the polls application in INSTALLED_APPS. The closepoll.py module has only one requirement it must dene a class Command that extends BaseCommand or one of its subclasses. Standalone scripts Custom management commands are especially useful for running standalone scripts or for scripts that are periodically executed from the UNIX crontab or from Windows scheduled tasks control panel. To implement the command, edit polls/management/commands/closepoll.py to look like this:
from django.core.management.base import BaseCommand, CommandError from example.polls.models import Poll class Command(BaseCommand): args = <poll_id poll_id ...> help = Closes the specified poll for voting def handle(self, *args, **options): for poll_id in args: try:
351
poll = Poll.objects.get(pk=int(poll_id)) except Poll.DoesNotExist: raise CommandError(Poll "%s" does not exist % poll_id) poll.opened = False poll.save() print Successfully closed poll "%s" % poll_id
The new custom command can be called using python manage.py closepoll <poll_id>. The handle() method takes zero or more poll_ids and sets poll.opened to False for each one. If the user referenced any nonexistant polls, a CommandError is raised. The poll.opened attribute does not exist in the tutorial and was added to polls.models.Poll for this example. The same closepoll could be easily modied to delete a given poll instead of closing it by accepting additional command line options. These custom options must be added to option_list like this:
from optparse import make_option class Command(BaseCommand): option_list = BaseCommand.option_list + ( make_option(--delete, action=store_true, dest=delete, default=False, help=Delete poll instead of closing it), ) # ...
In addition to being able to add custom command line options, all management commands can accept some default options such as --verbosity and --traceback.
28.1.1 Attributes
All attributes can be set in your derived class and can be used in BaseCommands subclasses. args A string listing the arguments accepted by the command, suitable for use in help messages; e.g., a command which takes a list of application names might set this to <appname appname ...>. can_import_settings A boolean indicating whether the command needs to be able to import Django settings; if True, execute() will verify that this is possible before proceeding. Default value is True.
352
help A short description of the command, which will be printed in the help message when the user runs the command python manage.py help <command>. option_list This is the list of optparse options which will be fed into the commands OptionParser for parsing arguments. output_transaction A boolean indicating whether the command outputs SQL statements; if True, the output will automatically be wrapped with BEGIN; and COMMIT;. Default value is False. requires_model_validation A boolean; if True, validation of installed models will be performed prior to executing the command. Default value is True. To validate an individual applications models rather than all applications models, call validate() from handle().
28.1.2 Methods
BaseCommand has a few methods that can be overridden but only the handle() method must be implemented. Implementing a constructor in a subclass If you implement __init__ in your subclass of BaseCommand, you must call BaseCommands __init__.
class Command(BaseCommand): def __init__(self, *args, **kwargs): super(Command, self).__init__(*args, **kwargs) # ...
get_version() Return the Django version, which should be correct for all built-in Django commands. User-supplied commands can override this method to return their own version. execute(*args, **options) Try to execute this command, performing model validation if needed (as controlled by the attribute requires_model_validation). If the command raises a CommandError, intercept it and print it sensibly to stderr. handle(*args, **options) The actual logic of the command. Subclasses must implement this method.
353
A management command which takes one or more arbitrary arguments (labels) on the command line, and does something with each of them. Rather than implementing handle(), subclasses must implement handle_label(), which will be called once for each label. handle_label(label, **options) Perform the commands actions for label, which will be the string as given on the command line. class NoArgsCommand() A command which takes no arguments on the command line. Rather than implementing handle(), subclasses must implement handle_noargs(); handle() itself is overridden to ensure no arguments are passed to the command. handle_noargs(**options) Perform this commands actions
354
CHAPTER
TWENTYNINE
29.1 Introduction
The model reference documentation explains how to use Djangos standard eld classes CharField, DateField, etc. For many purposes, those classes are all youll need. Sometimes, though, the Django version wont meet your precise requirements, or youll want to use a eld that is entirely different from those shipped with Django. Djangos built-in eld types dont cover every possible database column type only the common types, such as VARCHAR and INTEGER. For more obscure column types, such as geographic polygons or even user-created types such as PostgreSQL custom types, you can dene your own Django Field subclasses. Alternatively, you may have a complex Python object that can somehow be serialized to t into a standard database column type. This is another case where a Field subclass will help you use your object with your models.
This is just an ordinary Python class, with nothing Django-specic about it. Wed like to be able to do things like this in our models (we assume the hand attribute on the model is an instance of Hand):
355
example = MyModel.objects.get(pk=1) print example.hand.north new_hand = Hand(north, east, south, west) example.hand = new_hand example.save()
We assign to and retrieve from the hand attribute in our model just like any other Python class. The trick is to tell Django how to handle saving and loading such an object. In order to use the Hand class in our models, we do not have to change this class at all. This is ideal, because it means you can easily write model support for existing classes where you cannot change the source code. Note: You might only be wanting to take advantage of custom database column types and deal with the data as standard Python types in your models; strings, or oats, for example. This case is similar to our Hand example and well note any differences as we go along.
356
it will become clearer in the examples below. Just remember that you will often end up creating two classes when you want a custom eld: The rst class is the Python object that your users will manipulate. They will assign it to the model attribute, they will read from it for displaying purposes, things like that. This is the Hand class in our example. The second class is the Field subclass. This is the class that knows how to convert your rst class back and forth between its permanent storage form and the Python form.
Our HandField accepts most of the standard eld options (see the list below), but we ensure it has a xed length, since it only needs to hold 52 card values plus their suits; 104 characters in total. Note: Many of Djangos model elds accept options that they dont do anything with. For example, you can pass both editable and auto_now to a django.db.models.DateField and it will simply ignore the editable parameter (auto_now being set implies editable=False). No error is raised in this case. This behavior simplies the eld classes, because they dont need to check for options that arent necessary. They just pass all the options to the parent class and then dont use them later on. Its up to you whether you want your elds to be more strict about the options they select, or to use the simpler, more permissive behavior of the current elds. The __init__() method takes the following parameters: verbose_name name primary_key max_length unique blank null db_index
357
rel: Used for related elds (like ForeignKey). For advanced use only. default editable serialize: If False, the eld will not be serialized when the model is passed to Djangos serializers. Defaults to True. unique_for_date unique_for_month unique_for_year choices help_text db_column db_tablespace: Currently only used with the Oracle backend and only for index creation. You can usually ignore this option. auto_created: True if the eld was automatically created, as for the OneToOneField used by model inheritance. For advanced use only. All of the options without an explanation in the above list have the same meaning they do for normal Django elds. See the eld documentation for examples and details.
This ensures that the to_python() method, documented below, will always be called when the attribute is initialized.
358
ModelForms and custom elds If you use SubfieldBase, to_python() will be called every time an instance of the eld is assigned a value. This means that whenever a value may be assigned to the eld, you need to ensure that it will be of the correct datatype, or that you handle any exceptions. This is especially important if you use ModelForms. When saving a ModelForm, Django will use form values to instantiate model instances. However, if the cleaned form data cant be used as valid input to the eld, the normal form validation process will break. Therefore, you must ensure that the form eld used to represent your custom eld performs whatever input validation and data cleaning is necessary to convert user-provided form input into a to_python()-compatible model eld value. This may require writing a custom form eld, and/or implementing the formfield() method on your eld to return a form eld class whose to_python() returns the correct datatype.
Once you have MytypeField, you can use it in any model, just like any other Field type:
class Person(models.Model): name = models.CharField(max_length=80) gender = models.CharField(max_length=1) something_else = MytypeField()
359
If you aim to build a database-agnostic application, you should account for differences in database column types. For example, the date/time column type in PostgreSQL is called timestamp, while the same column in MySQL is called datetime. The simplest way to handle this in a db_type() method is to check the connection.settings_dict[ENGINE] attribute. For example:
class MyDateField(models.Field): def db_type(self, connection): if connection.settings_dict[ENGINE] == django.db.backends.mysql: return datetime else: return timestamp
The db_type() method is only called by Django when the framework constructs the CREATE TABLE statements for your application that is, when you rst create your tables. Its not called at any other time, so it can afford to execute slightly complex code, such as the connection.settings_dict check in the above example. Some database column types accept parameters, such as CHAR(25), where the parameter 25 represents the maximum column length. In cases like these, its more exible if the parameter is specied in the model rather than being hard-coded in the db_type() method. For example, it wouldnt make much sense to have a CharMaxlength25Field, shown here:
# This is a silly example of hard-coded parameters. class CharMaxlength25Field(models.Field): def db_type(self, connection): return char(25) # In the model: class MyModel(models.Model): # ... my_field = CharMaxlength25Field()
The better way of doing this would be to make the parameter speciable at run time i.e., when the class is instantiated. To do that, just implement django.db.models.Field.__init__(), like so:
# This is a much more flexible example. class BetterCharField(models.Field): def __init__(self, max_length, *args, **kwargs): self.max_length = max_length super(BetterCharField, self).__init__(*args, **kwargs) def db_type(self, connection): return char(%s) % self.max_length # In the model: class MyModel(models.Model): # ... my_field = BetterCharField(25)
Finally, if your column requires truly complex SQL setup, return None from db_type(). This will cause Djangos SQL creation code to skip over this eld. You are then responsible for creating the column in the right table in some other way, of course, but this gives you a way to tell Django to get out of the way. Converting database values to Python objects to_python(self, value) 360 Chapter 29. Writing custom model elds
Converts a value as returned by your database (or a serializer) to a Python object. The default implementation simply returns value, for the common case in which the database backend already returns data in the correct format (as a Python string, for example). If your custom Field class deals with data structures that are more complex than strings, dates, integers or oats, then youll need to override this method. As a general rule, the method should deal gracefully with any of the following arguments: An instance of the correct type (e.g., Hand in our ongoing example). A string (e.g., from a deserializer). Whatever the database returns for the column type youre using. In our HandField class, were storing the data as a VARCHAR eld in the database, so we need to be able to process strings and Hand instances in to_python():
import re class HandField(models.Field): # ... def to_python(self, value): if isinstance(value, Hand): return value # The string case. p1 = re.compile(.{26}) p2 = re.compile(..) args = [p2.findall(x) for x in p1.findall(value)] return Hand(*args)
Notice that we always return a Hand instance from this method. Thats the Python object type we want to store in the models attribute. Remember: If your custom eld needs the to_python() method to be called when it is created, you should be using The SubeldBase metaclass mentioned earlier. Otherwise to_python() wont be called automatically. Converting Python objects to query values get_prep_value(self, value) New in version 1.2: This method was factored out of get_db_prep_value() This is the reverse of to_python() when working with the database backends (as opposed to serialization). The value parameter is the current value of the models attribute (a eld has no reference to its containing model, so it cannot retrieve the value itself), and the method should return data in a format that has been prepared for use as a parameter in a query. This conversion should not include any database-specic conversions. If database-specic conversions are required, they should be made in the call to get_db_prep_value(). For example:
class HandField(models.Field): # ... def get_prep_value(self, value): return .join([.join(l) for l in (value.north, value.east, value.south, value.west)])
361
Converting query values to database values get_db_prep_value(self, value, connection, prepared=False) New in version 1.2: The connection and prepared arguments were added to support multiple databases. Some data types (for example, dates) need to be in a specic format before they can be used by a database backend. get_db_prep_value() is the method where those conversions should be made. The specic connection that will be used for the query is passed as the connection parameter. This allows you to use backend-specic conversion logic if it is required. The prepared argument describes whether or not the value has already been passed through get_prep_value() conversions. When prepared is False, the default implementation of get_db_prep_value() will call get_prep_value() to do initial data conversions before performing any database-specic processing. get_db_prep_save(self, value, connection) New in version 1.2: The connection argument was added to support multiple databases. Same as the above, but called when the Field value must be saved to the database. As the default implementation just calls get_db_prep_value, you shouldnt need to implement this method unless your custom eld needs a special conversion when being saved that is not the same as the conversion used for normal query parameters (which is implemented by get_db_prep_value). Preprocessing values before saving pre_save(self, model_instance, add) This method is called just prior to get_db_prep_save() and should return the value of the appropriate attribute from model_instance for this eld. The attribute name is in self.attname (this is set up by Field). If the model is being saved to the database for the rst time, the add parameter will be True, otherwise it will be False. You only need to override this method if you want to preprocess the value somehow, just before saving. For example, Djangos DateTimeField uses this method to set the attribute correctly in the case of auto_now or auto_now_add. If you do override this method, you must return the value of the attribute at the end. You should also update the models attribute if you make any changes to the value so that code holding references to the model will always see the correct value. Preparing values for use in database lookups As with value conversions, preparing a value for database lookups is a two phase process. get_prep_lookup(self, lookup_type, value) New in version 1.2: This method was factored out of get_db_prep_lookup() get_prep_lookup() performs the rst phase of lookup preparation, performing generic data validity checks Prepares the value for passing to the database when used in a lookup (a WHERE constraint in SQL). The lookup_type will be one of the valid Django lter lookups: exact, iexact, contains, icontains, gt, gte, lt, lte, in, startswith, istartswith, endswith, iendswith, range, year, month, day, isnull, search, regex, and iregex. Your method must be prepared to handle all of these lookup_type values and should raise either a ValueError if the value is of the wrong sort (a list when you were expecting an object, for example) or a TypeError if your eld does not support that type of lookup. For many elds, you can get by with handling the lookup types that need special handling for your eld and pass the rest to the get_db_prep_lookup() method of the parent class.
362
If you needed to implement get_db_prep_save(), you will usually need to implement get_prep_lookup(). If you dont, get_prep_value will be called by the default implementation, to manage exact, gt, gte, lt, lte, in and range lookups. You may also want to implement this method to limit the lookup types that could be used with your custom eld type. Note that, for range and in lookups, get_prep_lookup will receive a list of objects (presumably of the right type) and will need to convert them to a list of things of the right type for passing to the database. Most of the time, you can reuse get_prep_value(), or at least factor out some common pieces. For example, the following code implements get_prep_lookup to limit the accepted lookup types to exact and in:
class HandField(models.Field): # ... def get_prep_lookup(self, lookup_type, value): # We only handle exact and in. All others are errors. if lookup_type == exact: return self.get_prep_value(value) elif lookup_type == in: return [self.get_prep_value(v) for v in value] else: raise TypeError(Lookup type %r not supported. % lookup_type)
get_db_prep_lookup(self, lookup_type, value, connection, prepared=False) New in version 1.2: The connection and prepared arguments were added to support multiple databases. Performs any database-specic data conversions required by a lookup. As with get_db_prep_value(), the specic connection that will be used for the query is passed as the connection parameter. The prepared argument describes whether the value has already been prepared with get_prep_lookup(). Specifying the form eld for a model eld formfield(self, form_class=forms.CharField, **kwargs) Returns the default form eld to use when this eld is displayed in a model. This method is called by the ModelForm helper. All of the kwargs dictionary is passed directly to the form elds Field__init__() method. Normally, all you need to do is set up a good default for the form_class argument and then delegate further handling to the parent class. This might require you to write a custom form eld (and even a form widget). See the forms documentation for information about this, and take a look at the code in django.contrib.localflavor for some examples of custom widgets. Continuing our ongoing example, we can write the formfield() method as:
class HandField(models.Field): # ... def formfield(self, **kwargs): # This is a fairly standard way to set up some defaults # while letting the caller override them. defaults = {form_class: MyFormField} defaults.update(kwargs) return super(HandField, self).formfield(**defaults)
363
This assumes weve imported a MyFormField eld class (which has its own default widget). This document doesnt cover the details of writing custom form elds. Emulating built-in eld types get_internal_type(self ) Returns a string giving the name of the Field subclass we are emulating at the database level. This is used to determine the type of database column for simple cases. If you have created a db_type() method, you dont need to worry about get_internal_type() it wont be used much. Sometimes, though, your database storage is similar in type to some other eld, so you can use that other elds logic to create the right column. For example:
class HandField(models.Field): # ... def get_internal_type(self): return CharField
No matter which database backend we are using, this will mean that syncdb and other SQL commands create the right column type for storing a string. If get_internal_type() returns a string that is not known to Django for the database backend you are using that is, it doesnt appear in django.db.backends.<db_name>.creation.DATA_TYPES the string will still be used by the serializer, but the default db_type() method will return None. See the documentation of db_type() for reasons why this might be useful. Putting a descriptive string in as the type of the eld for the serializer is a useful idea if youre ever going to be using the serializer output in some other place, outside of Django. Converting eld data for serialization value_to_string(self, obj) This method is used by the serializers to convert the eld into a string for output. Calling Field._get_val_from_obj(obj)() is the best way to get the value to serialize. For example, since our HandField uses strings for its data storage anyway, we can reuse some existing conversion code:
class HandField(models.Field): # ... def value_to_string(self, obj): value = self._get_val_from_obj(obj) return self.get_db_prep_value(value)
364
2. Put a __str__() or __unicode__() method on the class youre wrapping up as a eld. There are a lot of places where the default behavior of the eld code is to call force_unicode() on the value. (In our examples in this document, value would be a Hand instance, not a HandField). So if your __unicode__() method automatically converts to the string form of your Python object, you can save yourself a lot of work.
365
366
CHAPTER
THIRTY
The app that contains the custom tags must be in INSTALLED_APPS in order for the {% load %} tag to work. This is a security feature: It allows you to host Python code for many template libraries on a single host machine without enabling access to all of them for every Django installation.
367
Theres no limit on how many modules you put in the templatetags package. Just keep in mind that a {% load %} statement will load tags/lters for the given Python module name, not the name of the app. To be a valid tag library, the module must contain a module-level variable named register that is a template.Library instance, in which all the tags and lters are registered. So, near the top of your module, put the following:
from django import template register = template.Library()
Behind the scenes For a ton of examples, read the source code for Djangos default lters and tags. Theyre in django/template/defaultfilters.py and django/template/defaulttags.py, respectively.
Most lters dont take arguments. In this case, just leave the argument out of your function. Example:
def lower(value): # Only one argument. "Converts a string into all lowercase" return value.lower()
Template lters that expect strings If youre writing a template lter that only expects a string as the rst argument, you should use the decorator stringfilter. This will convert an object to its string value before being passed to your function:
from django.template.defaultfilters import stringfilter @stringfilter def lower(value): return value.lower()
368
This way, youll be able to pass, say, an integer to this lter, and it wont cause an AttributeError (because integers dont have lower() methods). Registering custom lters Once youve written your lter denition, you need to register it with your Library instance, to make it available to Djangos template language:
register.filter(cut, cut) register.filter(lower, lower)
The Library.filter() method takes two arguments: 1. The name of the lter a string. 2. The compilation function a Python function (not the name of the function as a string). You can use register.filter() as a decorator instead:
@register.filter(name=cut) @stringfilter def cut(value, arg): return value.replace(arg, ) @register.filter @stringfilter def lower(value): return value.lower()
If you leave off the name argument, as in the second example above, Django will use the functions name as the lter name. Filters and auto-escaping New in version 1.0: Please, see the release notes When writing a custom lter, give some thought to how the lter will interact with Djangos auto-escaping behavior. Note that three types of strings can be passed around inside the template code: Raw strings are the native Python str or unicode types. On output, theyre escaped if auto-escaping is in effect and presented unchanged, otherwise. Safe strings are strings that have been marked safe from further escaping at output time. Any necessary escaping has already been done. Theyre commonly used for output that contains raw HTML that is intended to be interpreted as-is on the client side. Internally, these strings are of type SafeString or SafeUnicode. They share a common base class of SafeData, so you can test for them using code like:
if isinstance(value, SafeData): # Do something with the "safe" string.
Strings marked as needing escaping are always escaped on output, regardless of whether they are in an autoescape block or not. These strings are only escaped once, however, even if auto-escaping applies. Internally, these strings are of type EscapeString or EscapeUnicode. Generally you dont have to worry about these; they exist for the implementation of the escape lter. Template lter code falls into one of two situations: 30.1. Introduction 369
1. Your lter does not introduce any HTML-unsafe characters (<, >, , " or &) into the result that were not already present. In this case, you can let Django take care of all the auto-escaping handling for you. All you need to do is put the is_safe attribute on your lter function and set it to True, like so:
@register.filter def myfilter(value): return value myfilter.is_safe = True
This attribute tells Django that if a safe string is passed into your lter, the result will still be safe and if a non-safe string is passed in, Django will automatically escape it, if necessary. You can think of this as meaning this lter is safe it doesnt introduce any possibility of unsafe HTML. The reason is_safe is necessary is because there are plenty of normal string operations that will turn a SafeData object back into a normal str or unicode object and, rather than try to catch them all, which would be very difcult, Django repairs the damage after the lter has completed. For example, suppose you have a lter that adds the string xx to the end of any input. Since this introduces no dangerous HTML characters to the result (aside from any that were already present), you should mark your lter with is_safe:
@register.filter def add_xx(value): return %sxx % value add_xx.is_safe = True
When this lter is used in a template where auto-escaping is enabled, Django will escape the output whenever the input is not already marked as safe. By default, is_safe defaults to False, and you can omit it from any lters where it isnt required. Be careful when deciding if your lter really does leave safe strings as safe. If youre removing characters, you might inadvertently leave unbalanced HTML tags or entities in the result. For example, removing a > from the input might turn <a> into <a, which would need to be escaped on output to avoid causing problems. Similarly, removing a semicolon (;) can turn & into &, which is no longer a valid entity and thus needs further escaping. Most cases wont be nearly this tricky, but keep an eye out for any problems like that when reviewing your code. Marking a lter is_safe will coerce the lters return value to a string. If your lter should return a boolean or other non-string value, marking it is_safe will probably have unintended consequences (such as converting a boolean False to the string False). 2. Alternatively, your lter code can manually take care of any necessary escaping. This is necessary when youre introducing new HTML markup into the result. You want to mark the output as safe from further escaping so that your HTML markup isnt escaped further, so youll need to handle the input yourself. To mark the output as a safe string, use django.utils.safestring.mark_safe(). Be careful, though. You need to do more than just mark the output as safe. You need to ensure it really is safe, and what you do depends on whether auto-escaping is in effect. The idea is to write lters than can operate in templates where auto-escaping is either on or off in order to make things easier for your template authors. In order for your lter to know the current auto-escaping state, set the needs_autoescape attribute to True on your function. (If you dont specify this attribute, it defaults to False). This attribute tells Django that your lter function wants to be passed an extra keyword argument, called autoescape, that is True if autoescaping is in effect and False otherwise. For example, lets write a lter that emphasizes the rst character of a string:
370
from django.utils.html import conditional_escape from django.utils.safestring import mark_safe def initial_letter_filter(text, autoescape=None): first, other = text[0], text[1:] if autoescape: esc = conditional_escape else: esc = lambda x: x result = <strong>%s</strong>%s % (esc(first), esc(other)) return mark_safe(result) initial_letter_filter.needs_autoescape = True
The needs_autoescape attribute on the lter function and the autoescape keyword argument mean that our function will know whether automatic escaping is in effect when the lter is called. We use autoescape to decide whether the input data needs to be passed through django.utils.html.conditional_escape or not. (In the latter case, we just use the identity function as the escape function.) The conditional_escape() function is like escape() except it only escapes input that is not a SafeData instance. If a SafeData instance is passed to conditional_escape(), the data is returned unchanged. Finally, in the above example, we remember to mark the result as safe so that our HTML is inserted directly into the template without further escaping. Theres no need to worry about the is_safe attribute in this case (although including it wouldnt hurt anything). Whenever you manually handle the auto-escaping issues and return a safe string, the is_safe attribute wont change anything either way.
30.1. Introduction
371
The parser for this function should grab the parameter and create a Node object:
from django import template def do_current_time(parser, token): try: # split_contents() knows not to split quoted strings. tag_name, format_string = token.split_contents() except ValueError: raise template.TemplateSyntaxError, "%r tag requires a single argument" % token.contents.spli if not (format_string[0] == format_string[-1] and format_string[0] in (", "")): raise template.TemplateSyntaxError, "%r tags argument should be in quotes" % tag_name return CurrentTimeNode(format_string[1:-1])
Notes: parser is the template parser object. We dont need it in this example. token.contents is a string of the raw contents of the tag. In our example, its current_time "%Y-%m-%d %I:%M %p". The token.split_contents() method separates the arguments on spaces while keeping quoted strings together. The more straightforward token.contents.split() wouldnt be as robust, as it would naively split on all spaces, including those within quoted strings. Its a good idea to always use token.split_contents(). This function is responsible for raising django.template.TemplateSyntaxError, with helpful messages, for any syntax error. The TemplateSyntaxError exceptions use the tag_name variable. Dont hard-code the tags name in your error messages, because that couples the tags name to your function. token.contents.split()[0] will always be the name of your tag even when the tag has no arguments. The function returns a CurrentTimeNode with everything the node needs to know about this tag. In this case, it just passes the argument "%Y-%m-%d %I:%M %p". The leading and trailing quotes from the template tag are removed in format_string[1:-1]. The parsing is very low-level. The Django developers have experimented with writing small frameworks on top of this parsing system, using techniques such as EBNF grammars, but those experiments made the template engine too slow. Its low-level because thats fastest. Writing the renderer The second step in writing custom tags is to dene a Node subclass that has a render() method. Continuing the above example, we need to dene CurrentTimeNode:
from django import template import datetime class CurrentTimeNode(template.Node): def __init__(self, format_string): self.format_string = format_string def render(self, context): return datetime.datetime.now().strftime(self.format_string)
Notes:
372
__init__() gets the format_string from do_current_time(). tions/parameters/arguments to a Node via its __init__(). The render() method is where the work actually happens.
render() should never raise TemplateSyntaxError or any other exception. It should fail silently, just as template lters should. Ultimately, this decoupling of compilation and rendering results in an efcient template system, because a template can render multiple contexts without having to be parsed multiple times. Auto-escaping considerations New in version 1.0: Please, see the release notes The output from template tags is not automatically run through the auto-escaping lters. However, there are still a couple of things you should keep in mind when writing a template tag. If the render() function of your template stores the result in a context variable (rather than returning the result in a string), it should take care to call mark_safe() if appropriate. When the variable is ultimately rendered, it will be affected by the auto-escape setting in effect at the time, so content that should be safe from further escaping needs to be marked as such. Also, if your template tag creates a new context for performing some sub-rendering, set the auto-escape attribute to the current contexts value. The __init__ method for the Context class takes a parameter called autoescape that you can use for this purpose. For example:
def render(self, context): # ... new_context = Context({var: obj}, autoescape=context.autoescape) # ... Do something with new_context ...
This is not a very common situation, but its useful if youre rendering a template yourself. For example:
def render(self, context): t = template.loader.get_template(small_fragment.html) return t.render(Context({var: obj}, autoescape=context.autoescape))
If we had neglected to pass in the current context.autoescape value to our new Context in this example, the results would have always been automatically escaped, which may not be the desired behavior if the template tag is used inside a {% autoescape off %} block. Thread-safety considerations New in version 1.2: Please, see the release notes Once a node is parsed, its render method may be called any number of times. Since Django is sometimes run in multi-threaded environments, a single node may be simultaneously rendering with different contexts in response to two separate requests. Therefore, its important to make sure your template tags are thread safe. To make sure your template tags are thread safe, you should never store state information on the node itself. For example, Django provides a builtin cycle template tag that cycles among a list of given strings each time its rendered:
{% for o in some_list %} <tr class="{% cycle row1 row2 %}> ... </tr> {% endfor %}
A naive implementation of CycleNode might look something like this: 30.1. Introduction 373
class CycleNode(Node): def __init__(self, cyclevars): self.cycle_iter = itertools.cycle(cyclevars) def render(self, context): return self.cycle_iter.next()
But, suppose we have two templates rendering the template snippet from above at the same time: 1. Thread 1 performs its rst loop iteration, CycleNode.render() returns row1 2. Thread 2 performs its rst loop iteration, CycleNode.render() returns row2 3. Thread 1 performs its second loop iteration, CycleNode.render() returns row1 4. Thread 2 performs its second loop iteration, CycleNode.render() returns row2 The CycleNode is iterating, but its iterating globally. As far as Thread 1 and Thread 2 are concerned, its always returning the same value. This is obviously not what we want! To address this problem, Django provides a render_context thats associated with the context of the template that is currently being rendered. The render_context behaves like a Python dictionary, and should be used to store Node state between invocations of the render method. Lets refactor our CycleNode implementation to use the render_context:
class CycleNode(Node): def __init__(self, cyclevars): self.cyclevars = cyclevars def render(self, context): if self not in context.render_context: context.render_context[self] = itertools.cycle(self.cyclevars) cycle_iter = context.render_context[self] return cycle_iter.next()
Note that its perfectly safe to store global information that will not change throughout the life of the Node as an attribute. In the case of CycleNode, the cyclevars argument doesnt change after the Node is instantiated, so we dont need to put it in the render_context. But state information that is specic to the template that is currently being rendered, like the current iteration of the CycleNode, should be stored in the render_context. Note: Notice how we used self to scope the CycleNode specic information within the render_context. There may be multiple CycleNodes in a given template, so we need to be careful not to clobber another nodes state information. The easiest way to do this is to always use self as the key into render_context. If youre keeping track of several state variables, make render_context[self] a dictionary. Registering the tag Finally, register the tag with your modules Library instance, as explained in Writing custom template lters above. Example:
register.tag(current_time, do_current_time)
The tag() method takes two arguments: 1. The name of the template tag a string. If this is left out, the name of the compilation function will be used. 2. The compilation function a Python function (not the name of the function as a string). As with lter registration, it is also possible to use this as a decorator:
374
@register.tag(name="current_time") def do_current_time(parser, token): # ... @register.tag def shout(parser, token): # ...
If you leave off the name argument, as in the second example above, Django will use the functions name as the tag name. Passing template variables to the tag Although you can pass any number of arguments to a template tag using token.split_contents(), the arguments are all unpacked as string literals. A little more work is required in order to pass dynamic content (a template variable) to a template tag as an argument. While the previous examples have formatted the current time into a string and returned the string, suppose you wanted to pass in a DateTimeField from an object and have the template tag format that date-time:
<p>This post was last updated at {% format_time blog_entry.date_updated "%Y-%m-%d %I:%M %p" %}.</p>
Initially, token.split_contents() will return three values: 1. The tag name format_time. 2. The string blog_entry.date_updated (without the surrounding quotes). 3. The formatting string %Y-%m-%d %I:%M %p. The return value from split_contents() will include the leading and trailing quotes for string literals like this. Now your tag should begin to look like this:
from django import template def do_format_time(parser, token): try: # split_contents() knows not to split quoted strings. tag_name, date_to_be_formatted, format_string = token.split_contents() except ValueError: raise template.TemplateSyntaxError, "%r tag requires exactly two arguments" % token.contents. if not (format_string[0] == format_string[-1] and format_string[0] in (", "")): raise template.TemplateSyntaxError, "%r tags argument should be in quotes" % tag_name return FormatTimeNode(date_to_be_formatted, format_string[1:-1])
Changed in version 1.0: Variable resolution has changed in the 1.0 release of Django. template.resolve_variable() has been deprecated in favor of a new template.Variable class. You also have to change the renderer to retrieve the actual contents of the date_updated property of the blog_entry object. This can be accomplished by using the Variable() class in django.template. To use the Variable class, simply instantiate it with the name of the variable to be resolved, and then call variable.resolve(context). So, for example:
class FormatTimeNode(template.Node): def __init__(self, date_to_be_formatted, format_string): self.date_to_be_formatted = template.Variable(date_to_be_formatted) self.format_string = format_string
30.1. Introduction
375
def render(self, context): try: actual_date = self.date_to_be_formatted.resolve(context) return actual_date.strftime(self.format_string) except template.VariableDoesNotExist: return
Variable resolution will throw a VariableDoesNotExist exception if it cannot resolve the string passed to it in the current context of the page. Shortcut for simple tags Many template tags take a number of arguments strings or a template variables and return a string after doing some processing based solely on the input argument and some external information. For example, the current_time tag we wrote above is of this variety: we give it a format string, it returns the time as a string. To ease the creation of the types of tags, Django provides a helper function, simple_tag. This function, which is a method of django.template.Library, takes a function that accepts any number of arguments, wraps it in a render function and the other necessary bits mentioned above and registers it with the template system. Our earlier current_time function could thus be written like this:
def current_time(format_string): return datetime.datetime.now().strftime(format_string) register.simple_tag(current_time)
A couple of things to note about the simple_tag helper function: Checking for the required number of arguments, etc., has already been done by the time our function is called, so we dont need to do that. The quotes around the argument (if any) have already been stripped away, so we just receive a plain string. If the argument was a template variable, our function is passed the current value of the variable, not the variable itself. When your template tag does not need access to the current context, writing a function to work with the input values and using the simple_tag helper is the easiest way to create a new tag. Inclusion tags Another common type of template tag is the type that displays some data by rendering another template. For example, Djangos admin interface uses custom template tags to display the buttons along the bottom of the add/change form pages. Those buttons always look the same, but the link targets change depending on the object being edited so theyre a perfect case for using a small template that is lled with details from the current object. (In the admins case, this is the submit_row tag.) These sorts of tags are called inclusion tags.
376
Writing inclusion tags is probably best demonstrated by example. Lets write a tag that outputs a list of choices for a given Poll object, such as was created in the tutorials. Well use the tag like this:
{% show_results poll %}
First, dene the function that takes the argument and produces a dictionary of data for the result. The important point here is we only need to return a dictionary, not anything more complex. This will be used as a template context for the template fragment. Example:
def show_results(poll): choices = poll.choice_set.all() return {choices: choices}
Next, create the template used to render the tags output. This template is a xed feature of the tag: the tag writer species it, not the template designer. Following our example, the template is very simple:
<ul> {% for choice in choices %} <li> {{ choice }} </li> {% endfor %} </ul>
Now, create and register the inclusion tag by calling the inclusion_tag() method on a Library object. Following our example, if the above template is in a le called results.html in a directory thats searched by the template loader, wed register the tag like this:
# Here, register is a django.template.Library instance, as before register.inclusion_tag(results.html)(show_results)
...when rst creating the function. Sometimes, your inclusion tags might require a large number of arguments, making it a pain for template authors to pass in all the arguments and remember their order. To solve this, Django provides a takes_context option for inclusion tags. If you specify takes_context in creating a template tag, the tag will have no required arguments, and the underlying Python function will have one argument the template context as of when the tag was called. For example, say youre writing an inclusion tag that will always be used in a context that contains home_link and home_title variables that point back to the main page. Heres what the Python function would look like:
# The first argument *must* be called "context" here. def jump_link(context): return { link: context[home_link],
30.1. Introduction
377
title: context[home_title], } # Register the custom tag as an inclusion tag with takes_context=True. register.inclusion_tag(link.html, takes_context=True)(jump_link)
(Note that the rst parameter to the function must be called context.) In that register.inclusion_tag() line, we specied takes_context=True and the name of the template. Heres what the template link.html might look like:
Jump directly to <a href="{{ link }}">{{ title }}</a>.
Then, any time you want to use that custom tag, load its library and call it without any arguments, like so:
{% jump_link %}
Note that when youre using takes_context=True, theres no need to pass arguments to the template tag. It automatically gets access to the context. The takes_context parameter defaults to False. When its set to True, the tag is passed the context object, as in this example. Thats the only difference between this case and the previous inclusion_tag example. Setting a variable in the context The above example simply output a value. Generally, its more exible if your template tags set template variables instead of outputting values. That way, template authors can reuse the values that your template tags create. To set a variable in the context, just use dictionary assignment on the context object in the render() method. Heres an updated version of CurrentTimeNode that sets a template variable current_time instead of outputting it:
class CurrentTimeNode2(template.Node): def __init__(self, format_string): self.format_string = format_string def render(self, context): context[current_time] = datetime.datetime.now().strftime(self.format_string) return
Note that render() returns the empty string. render() should always return string output. If all the template tag does is set a variable, render() should return the empty string. Heres how youd use this new version of the tag:
{% current_time "%Y-%M-%d %I:%M %p" %}<p>The time is {{ current_time }}.</p>
But, theres a problem with CurrentTimeNode2: The variable name current_time is hard-coded. This means youll need to make sure your template doesnt use {{ current_time }} anywhere else, because the {% current_time %} will blindly overwrite that variables value. A cleaner solution is to make the template tag specify the name of the output variable, like so:
{% current_time "%Y-%M-%d %I:%M %p" as my_current_time %} <p>The current time is {{ my_current_time }}.</p>
To do that, youll need to refactor both the compilation function and Node class, like so:
378
class CurrentTimeNode3(template.Node): def __init__(self, format_string, var_name): self.format_string = format_string self.var_name = var_name def render(self, context): context[self.var_name] = datetime.datetime.now().strftime(self.format_string) return import re def do_current_time(parser, token): # This version uses a regular expression to parse tag contents. try: # Splitting by None == splitting by spaces. tag_name, arg = token.contents.split(None, 1) except ValueError: raise template.TemplateSyntaxError, "%r tag requires arguments" % token.contents.split()[0] m = re.search(r(.*?) as (\w+), arg) if not m: raise template.TemplateSyntaxError, "%r tag had invalid arguments" % tag_name format_string, var_name = m.groups() if not (format_string[0] == format_string[-1] and format_string[0] in (", "")): raise template.TemplateSyntaxError, "%r tags argument should be in quotes" % tag_name return CurrentTimeNode3(format_string[1:-1], var_name)
The difference here is that do_current_time() grabs the format string and the variable name, passing both to CurrentTimeNode3. Parsing until another block tag Template tags can work in tandem. For instance, the standard {% comment %} tag hides everything until {% endcomment %}. To create a template tag such as this, use parser.parse() in your compilation function. Heres how the standard {% comment %} tag is implemented:
def do_comment(parser, token): nodelist = parser.parse((endcomment,)) parser.delete_first_token() return CommentNode() class CommentNode(template.Node): def render(self, context): return
parser.parse() takes a tuple of names of block tags to parse until. It returns an instance of django.template.NodeList, which is a list of all Node objects that the parser encountered before it encountered any of the tags named in the tuple. In "nodelist = parser.parse((endcomment,))" in the above example, nodelist is a list of all nodes between the {% comment %} and {% endcomment %}, not counting {% comment %} and {% endcomment %} themselves. After parser.parse() is called, the parser hasnt yet consumed the {% endcomment %} tag, so the code needs to explicitly call parser.delete_first_token(). CommentNode.render() simply returns an empty string. endcomment %} is ignored. Anything between {% comment %} and {%
30.1. Introduction
379
Parsing until another block tag, and saving contents In the previous example, do_comment() discarded everything between {% comment %} and {% endcomment %}. Instead of doing that, its possible to do something with the code between block tags. For example, heres a custom template tag, {% upper %}, that capitalizes everything between itself and {% endupper %}. Usage:
{% upper %}This will appear in uppercase, {{ your_name }}.{% endupper %}
As in the previous example, well use parser.parse(). But this time, we pass the resulting nodelist to the Node:
def do_upper(parser, token): nodelist = parser.parse((endupper,)) parser.delete_first_token() return UpperNode(nodelist) class UpperNode(template.Node): def __init__(self, nodelist): self.nodelist = nodelist def render(self, context): output = self.nodelist.render(context) return output.upper()
The only new concept here is the self.nodelist.render(context) in UpperNode.render(). For more examples of complex rendering, see the source code for {% if %}, {% for %}, {% ifequal %} and {% ifchanged %}. They live in django/template/defaulttags.py.
380
CHAPTER
THIRTYONE
2. Django must be able to instantiate your storage system without any arguments. This means that any settings should be taken from django.conf.settings:
from django.conf import settings from django.core.files.storage import Storage class MyStorage(Storage): def __init__(self, option=None): if not option: option = settings.CUSTOM_STORAGE_OPTIONS ...
3. Your storage class must implement the _open() and _save() methods, along with any other methods appropriate to your storage class. See below for more on these methods. In addition, if your class provides local le storage, it must override the path() method. Your custom storage system may override any of the storage methods explained in File storage API , but you must implement the following methods: Storage.delete() Storage.exists() Storage.listdir() Storage.size() Storage.url() Youll also usually want to use hooks specically designed for custom storage objects. These are:
381
31.2.1 get_valid_name(name)
Returns a lename suitable for use with the underlying storage system. The name argument passed to this method is the original lename sent to the server, after having any path information removed. Override this to customize how non-standard characters are converted to safe lenames. The code provided on Storage retains only alpha-numeric characters, periods and underscores from the original lename, removing everything else.
31.2.2 get_available_name(name)
Returns a lename that is available in the storage mechanism, possibly taking the provided lename into account. The name argument passed to this method will have already cleaned to a lename valid for the storage system, according to the get_valid_name() method described above. The code provided on Storage simply appends "_1", "_2", etc. to the lename until it nds one thats available in the destination directory.
382
CHAPTER
THIRTYTWO
DEPLOYING DJANGO
Djangos chock-full of shortcuts to make web developers lives easier, but all those tools are of no use if you cant easily deploy your sites. Since Djangos inception, ease of deployment has been a major goal. Theres a number of good ways to easily deploy Django:
The rst bit above is the url you want to be serving your application at (/ indicates the root url), and the second is the location of a WSGI le see below on your system, usually inside of your project. This tells Apache to serve any request below the given URL using the WSGI application dened by that le. Next well need to actually create this WSGI application, so create the le mentioned in the second part of WSGIScriptAlias and add:
import os import sys os.environ[DJANGO_SETTINGS_MODULE] = mysite.settings import django.core.handlers.wsgi application = django.core.handlers.wsgi.WSGIHandler()
383
just above the nal import line to place your project on the path. Remember to replace mysite.settings with your correct settings le, and /usr/local/django with your own projects location.
More details on conguring a mod_wsgi site to serve static les can be found in the mod_wsgi documentation on hosting static les.
32.1.3 Details
For more details, see the mod_wsgi documentation on Django integration, which explains the above in more detail, and walks through all the various options youve got when deploying under mod_wsgi.
384
...and replace mysite.settings with the Python import path to your Django projects settings le. This tells Apache: Use mod_python for any URL at or under /mysite/, using the Django mod_python handler. It passes the value of DJANGO_SETTINGS_MODULE so mod_python knows which settings to use. New in version 1.0: The PythonOption django.root ... is new in this version. Because mod_python does not know we are serving this site from underneath the /mysite/ prex, this value needs to be passed through to the mod_python handler in Django, via the PythonOption django.root ... line. The value set on that line (the last item) should match the string given in the <Location ...> directive. The effect of this is that Django will automatically strip the /mysite string from the front of any URLs before matching them against your URLconf patterns. If you later move your site to live under /mysite2, you will not have to change anything except the django.root option in the cong le. When using django.root you should make sure that whats left, after the prex has been removed, begins with a slash. Your URLconf patterns that are expecting an initial slash will then work correctly. In the above example, since we want to send things like /mysite/admin/ to /admin/, we need to remove the string /mysite from the beginning, so that is the django.root value. It would be an error to use /mysite/ (with a trailing slash) in this case. Note that were using the <Location> directive, not the <Directory> directive. The latter is used for pointing at places on your lesystem, whereas <Location> points at places in the URL structure of a Web site. <Directory> would be meaningless here.
385
Also, if your Django project is not on the default PYTHONPATH for your computer, youll have to tell mod_python where your project can be found:
<Location "/mysite/"> SetHandler python-program PythonHandler django.core.handlers.modpython SetEnv DJANGO_SETTINGS_MODULE mysite.settings PythonOption django.root /mysite PythonDebug On PythonPath "[/path/to/project] + sys.path" </Location>
The value you use for PythonPath should include the parent directories of all the modules you are going to import in your application. It should also include the parent directory of the DJANGO_SETTINGS_MODULE location. This is exactly the same situation as setting the Python path for interactive usage. Whenever you try to import something, Python will run through all the directories in sys.path in turn, from rst to last, and try to import from each directory until one succeeds. Make sure that your Python source les permissions are set such that the Apache user (usually named apache or httpd on most systems) will have read access to the les. An example might make this clearer. Suppose you have some applications under /usr/local/django-apps/ (for example, /usr/local/django-apps/weblog/ and so forth), your settings le is at /var/www/mysite/settings.py and you have specied DJANGO_SETTINGS_MODULE as in the above example. In this case, you would need to write your PythonPath directive as:
PythonPath "[/usr/local/django-apps/, /var/www] + sys.path"
With this path, import weblog and import mysite.settings will both work. If you had import blogroll in your code somewhere and blogroll lived under the weblog/ directory, you would also need to add /usr/local/django-apps/weblog/ to your PythonPath. Remember: the parent directories of anything you import directly must be on the Python path. Note: If youre using Windows, we still recommended that you use forward slashes in the pathnames, even though Windows normally uses the backslash character as its native separator. Apache knows how to convert from the forward slash format to the native format, so this approach is portable and easier to read. (It avoids tricky problems with having to double-escape backslashes.) This is valid even on a Windows system:
PythonPath "[c:/path/to/project] + sys.path"
You can also add directives such as PythonAutoReload Off for performance. See the mod_python documentation for a full list of options. Note that you should set PythonDebug Off on a production server. If you leave PythonDebug On, your users would see ugly (and revealing) Python tracebacks if something goes wrong within mod_python. Restart Apache, and any request to /mysite/ or below will be served by Django. Note that Djangos URLconfs wont trim the /mysite/ they get passed the full URL. When deploying Django sites on mod_python, youll need to restart Apache each time you make changes to your Python code.
386
If you need to put two Django installations within the same VirtualHost (or in different VirtualHost blocks that share the same server name), youll need to take a special precaution to ensure mod_pythons cache doesnt mess things up. Use the PythonInterpreter directive to give different <Location> directives separate interpreters:
<VirtualHost *> ServerName www.example.com # ... <Location "/something"> SetEnv DJANGO_SETTINGS_MODULE mysite.settings PythonInterpreter mysite </Location> <Location "/otherthing"> SetEnv DJANGO_SETTINGS_MODULE mysite.other_settings PythonInterpreter othersite </Location> </VirtualHost>
The values of PythonInterpreter dont really matter, as long as theyre different between the two Location blocks.
387
Just change Location to the root URL of your media les. You can also use <LocationMatch> to match a regular expression. This example sets up Django at the site root but explicitly disables Django for the media subdirectory and any URL that ends with .jpg, .gif or .png:
<Location "/"> SetHandler python-program PythonHandler django.core.handlers.modpython SetEnv DJANGO_SETTINGS_MODULE mysite.settings </Location> <Location "/media"> SetHandler None </Location> <LocationMatch "\.(jpg|gif|png)$"> SetHandler None </LocationMatch>
388
Here, /some/directory is a directory that the Apache webserver process can write to. It will be used as the location for any unpacking of code the eggs need to do. Then you have to tell mod_python to import this le before doing anything else. This is done using the PythonImport directive to mod_python. You need to ensure that you have specied the PythonInterpreter directive to mod_python as described above (you need to do this even if you arent serving multiple installations in this case). Then add the PythonImport line in the main server conguration (i.e., outside the Location or VirtualHost sections). For example:
PythonInterpreter my_django PythonImport /path/to/my/project/file.py my_django
Note that you can use an absolute path here (or a normal dotted import path), as described in the mod_python manual. We use an absolute path in the above example because if any Python path modications are required to access your project, they will not have been done at the time the PythonImport line is processed.
389
Consult the documentation for your operating system for the appropriate syntax and location to put these conguration items; /etc/apache2/envvars is a common location on Unix platforms. Once you have added these statements to your environment, restart Apache.
32.3.1 Prerequisite: up
Before you can start using FastCGI with Django, youll need to install up, a Python library for dealing with FastCGI. Version 0.5 or newer should work ne.
390
If you specify help as the only option after runfcgi, itll display a list of all the available options. Youll need to specify either a socket, a protocol or both host and port. Then, when you set up your Web server, youll just need to point it at the host/port or socket you specied when starting the FastCGI server. See the examples, below. Protocols Django supports all the protocols that up does, namely fastcgi, SCGI and AJP1.3 (the Apache JServ Protocol, version 1.3). Select your preferred protocol by using the protocol=<protocol_name> option with ./manage.py runfcgi where <protocol_name> may be one of: fcgi (the default), scgi or ajp. For example:
./manage.py runfcgi protocol=scgi
391
Stopping the FastCGI daemon If you have the process running in the foreground, its easy enough to stop it: Simply hitting Ctrl-C will stop and quit the FastCGI server. However, when youre dealing with background processes, youll need to resort to the Unix kill command. If you specify the pidfile option to runfcgi, you can kill the running FastCGI daemon like this:
kill cat $PIDFILE
...where $PIDFILE is the pidfile you specied. To easily restart your FastCGI daemon on Unix, try this small shell script:
#!/bin/bash # Replace these three settings. PROJDIR="/home/user/myproject" PIDFILE="$PROJDIR/mysite.pid" SOCKET="$PROJDIR/mysite.sock" cd $PROJDIR if [ -f $PIDFILE ]; then kill cat -- $PIDFILE rm -f -- $PIDFILE fi exec /usr/bin/env - \ PYTHONPATH="../python:.." \ ./manage.py runfcgi socket=$SOCKET pidfile=$PIDFILE
392
In either case, the le /home/user/public_html/mysite.fcgi doesnt actually have to exist. Its just a URL used by the Web server internally a hook for signifying which requests at a URL should be handled by FastCGI. (More on this in the next section.) Using mod_rewrite to point URLs at FastCGI The second step is telling Apache to use FastCGI for URLs that match a certain pattern. To do this, use the mod_rewrite module and rewrite URLs to mysite.fcgi (or whatever you specied in the FastCGIExternalServer directive, as explained in the previous section). In this example, we tell Apache to use FastCGI to handle any request that doesnt represent a le on the lesystem and doesnt start with /media/. This is probably the most common case, if youre using Djangos admin site:
<VirtualHost 12.34.56.78> ServerName example.com DocumentRoot /home/user/public_html Alias /media /home/user/python/django/contrib/admin/media RewriteEngine On RewriteRule ^/(media.*)$ /$1 [QSA,L,PT] RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^/(.*)$ /mysite.fcgi/$1 [QSA,L] </VirtualHost>
Django will automatically use the pre-rewrite version of the URL when constructing URLs with the {% url %} template tag (and similar methods).
393
Running multiple Django sites on one lighttpd lighttpd lets you use conditional conguration to allow conguration to be customized per host. To specify multiple FastCGI sites, just add a conditional block around your FastCGI cong for each site:
# If the hostname is www.example1.com... $HTTP["host"] == "www.example1.com" { server.document-root = "/foo/site1" fastcgi.server = ( ... ) ... } # If the hostname is www.example2.com... $HTTP["host"] == "www.example2.com" { server.document-root = "/foo/site2" fastcgi.server = ( ... ) ... }
You can also run multiple Django installations on the same site simply by specifying multiple entries in the fastcgi.server directive. Add one FastCGI host for each.
394
Then, create a small script that tells Apache how to spawn your FastCGI program. Create a le mysite.fcgi and place it in your Web directory, and be sure to make it executable:
#!/usr/bin/python import sys, os # Add a custom Python path. sys.path.insert(0, "/home/user/python") # Switch to the directory of your project. (Optional.) # os.chdir("/home/user/myproject") # Set the DJANGO_SETTINGS_MODULE environment variable. os.environ[DJANGO_SETTINGS_MODULE] = "myproject.settings" from django.core.servers.fastcgi import runfastcgi runfastcgi(method="threaded", daemonize="false")
Restarting the spawned server If you change any Python code on your site, youll need to tell FastCGI the code has changed. But theres no need to restart Apache in this case. Rather, just reupload mysite.fcgi, or edit the le, so that the timestamp on the le will change. When Apache sees the le has been updated, it will restart your Django application for you. If you have access to a command shell on a Unix system, you can accomplish this easily by using the touch command:
touch mysite.fcgi
395
If youre new to deploying Django and/or Python, wed recommend you try mod_wsgi rst. In most cases itll be the easiest, fastest, and most stable deployment choice. See Also: Chapter 12 of The Django Book discusses deployment and especially scaling in more detail.
396
CHAPTER
THIRTYTHREE
397
You can tell Django to stop reporting particular 404s by tweaking the IGNORABLE_404_ENDS and IGNORABLE_404_STARTS settings. Both should be a tuple of strings. For example:
IGNORABLE_404_ENDS = (.php, .cgi) IGNORABLE_404_STARTS = (/phpmyadmin/,)
In this example, a 404 to any URL ending with .php or .cgi will not be reported. Neither will any URL starting with /phpmyadmin/. The best way to disable this behavior is to set SEND_BROKEN_LINK_EMAILS to False. See Also: You can also set up custom error reporting by writing a custom piece of exception middleware. If you do write custom error handling, its a good idea to emulate Djangos built-in error handling and only report/log errors if DEBUG is False.
398
CHAPTER
THIRTYFOUR
399
- model: myapp.person pk: 1 fields: first_name: John last_name: Lennon - model: myapp.person pk: 2 fields: first_name: Paul last_name: McCartney
Youll store this data in a fixtures directory inside your app. Loading data is easy: just call manage.py loaddata fixturename, where xturename is the name of the xture le youve created. Every time you run loaddata the data will be read from the xture and re-loaded into the database. Note that this means that if you change one of the rows created by a xture and then run loaddata again youll wipe out any changes youve made.
Each SQL le, if given, is expected to contain valid SQL statements which will insert the desired data (e.g., properlyformatted INSERT statements separated by semicolons). The SQL les are read by the sqlcustom, sqlreset, sqlall and reset commands in manage.py. Refer to the manage.py documentation for more information. Note that if you have multiple SQL data les, theres no guarantee of the order in which theyre executed. The only thing you can assume is that, by the time your custom data les are executed, all the database tables already will have been created.
400
401
402
CHAPTER
THIRTYFIVE
403
Finally, you should give some thought to the structure of your translation les. If your applications need to be delivered to other users and will be used in other projects, you might want to use app-specic translations. But using appspecic translations and project translations could produce weird problems with makemessages: It will traverse all directories below the current path and so might put message IDs into the project message le that are already in application message les. The easiest way out is to store applications that are not part of the project (and so carry their own translations) outside the project tree. That way, django-admin.py makemessages on the project level will only translate strings that are connected to your explicit project and not strings that are distributed independently.
Calling this function with the value de will give you "Willkommen", regardless of LANGUAGE_CODE and language set by middleware. Functions of particular interest are django.utils.translation.get_language() which returns the language used in the current thread, django.utils.translation.activate() which activates a translation catalog for the current thread, and django.utils.translation.check_for_language() which checks if the given language is supported by Django.
404
CHAPTER
THIRTYSIX
405
406
CHAPTER
THIRTYSEVEN
This feature is meant as a shortcut, not as denitive model generation. See the documentation of inspectdb for more information.
407
Once youve cleaned up your models, name the le models.py and put it in the Python package that holds your app. Then add the app to your INSTALLED_APPS setting.
408
CHAPTER
THIRTYEIGHT
The code and comments should be self-explanatory, but a few things deserve a mention: The response gets a special MIME type, text/csv. This tells browsers that the document is a CSV le, rather than an HTML le. If you leave this off, browsers will probably interpret the output as HTML, which will result in ugly, scary gobbledygook in the browser window. The response gets an additional Content-Disposition header, which contains the name of the CSV le. This lename is arbitrary; call it whatever you want. Itll be used by browsers in the Save as... dialogue, etc. Hooking into the CSV-generation API is easy: Just pass response as the rst argument to csv.writer. The csv.writer function expects a le-like object, and HttpResponse objects t the bill. For each row in your CSV le, call writer.writerow, passing it an iterable object such as a list or tuple. The CSV module takes care of quoting for you, so you dont have to worry about escaping strings with quotes or commas in them. Just pass writerow() your raw strings, and itll do the right thing.
409
The only difference between this example and the previous example is that this one uses template loading instead of the CSV module. The rest of the code such as the mimetype=text/csv is the same. Then, create the template my_template_name.txt, with this template code:
{% for row in data %}"{{ row.0|addslashes }}", "{{ row.1|addslashes }}", "{{ row.2|addslashes }}", "{ {% endfor %}
This template is quite basic. It just iterates over the given data and displays a line of CSV for each row. It uses the addslashes template lter to ensure there arent any problems with quotes.
410
CHAPTER
THIRTYNINE
411
# See the ReportLab documentation for the full list of functionality. p.drawString(100, 100, "Hello world.") # Close the PDF object cleanly, and were done. p.showPage() p.save() return response
The code and comments should be self-explanatory, but a few things deserve a mention: The response gets a special MIME type, application/pdf. This tells browsers that the document is a PDF le, rather than an HTML le. If you leave this off, browsers will probably interpret the output as HTML, which would result in ugly, scary gobbledygook in the browser window. The response gets an additional Content-Disposition header, which contains the name of the PDF le. This lename is arbitrary: Call it whatever you want. Itll be used by browsers in the Save as... dialogue, etc. The Content-Disposition header starts with attachment; in this example. This forces Web browsers to pop-up a dialog box prompting/conrming how to handle the document even if a default is set on the machine. If you leave off attachment;, browsers will handle the PDF using whatever program/plugin theyve been congured to use for PDFs. Heres what that code would look like:
response[Content-Disposition] = filename=somefilename.pdf
Hooking into the ReportLab API is easy: Just pass response as the rst argument to canvas.Canvas. The Canvas class expects a le-like object, and HttpResponse objects t the bill. Note that all subsequent PDF-generation methods are called on the PDF object (in this case, p) not on response. Finally, its important to call showPage() and save() on the PDF le.
412
# Close the PDF object cleanly. p.showPage() p.save() # Get the value of the StringIO buffer and write it to the response. pdf = buffer.getvalue() buffer.close() response.write(pdf) return response
413
414
CHAPTER
FORTY
40.2 How to do it
Heres the formal denition of the serve() view: def serve(request, path, document_root, show_indexes=False)() To use it, just put this in your URLconf :
(r^site_media/(?P<path>.*)$, django.views.static.serve, {document_root: /path/to/media}),
...where site_media is the URL where your media will be rooted, and /path/to/media is the lesystem root for your media. This will call the serve() view, passing in the path from the URLconf and the (required) document_root parameter. Given the above URLconf: The le /path/to/media/foo.jpg will be made available at the URL /site_media/foo.jpg. The le /path/to/media/css/mystyles.css /site_media/css/mystyles.css. will be made available at the URL
415
The le /path/bar.jpg will not be accessible, because it doesnt fall under the document root. Of course, its not compulsory to use a xed string for the document_root value. You might wish to make that an entry in your settings le and use the setting value there. That will allow you and other developers working on the code to easily change the value as required. For example, if we have a line in settings.py that says:
STATIC_DOC_ROOT = /path/to/media
Be careful not to use the same path as your ADMIN_MEDIA_PREFIX (which defaults to /media/) as this will overwrite your URLconf entry.
You can customize the index view by creating a template called static/directory_index.html. That template gets two objects in its context: directory the directory name (a string) file_list a list of le names (as strings) in the directory Heres the default static/directory_index.html template:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Language" content="en-us" /> <meta name="robots" content="NONE,NOARCHIVE" /> <title>Index of {{ directory }}</title> </head> <body> <h1>Index of {{ directory }}</h1> <ul> {% for f in file_list %} <li><a href="{{ f }}">{{ f }}</a></li> {% endfor %} </ul> </body> </html>
416
Changed in version 1.0.3: Prior to Django 1.0.3, there was a bug in the view that provided directory listings. The template that was loaded had to be called static/directory_listing (with no .html extension). For backwards compatibility with earlier versions, Django will still load templates with the older (no extension) name, but it will prefer the directory_index.html version.
This code is straightforward. It imports the settings and checks the value of the DEBUG setting. If it evaluates to True, then site_media will be associated with the django.views.static.serve view. If not, then the view wont be made available. Of course, the catch here is that youll have to remember to set DEBUG=False in your production settings le. But you should be doing that anyway. See Also: The Django community aggregator, where we aggregate content from the global Django community. Many writers in the aggregator write this sort of how-to material.
417
418
Part IV
Django FAQ
419
CHAPTER
FORTYONE
FAQ: GENERAL
41.1 Why does this project exist?
Django grew from a very practical need: World Online, a newspaper Web operation, is responsible for building intensive Web applications on journalism deadlines. In the fast-paced newsroom, World Online often has only a matter of hours to take a complicated Web application from concept to public launch. At the same time, the World Online Web developers have consistently been perfectionists when it comes to following best practices of Web development. In fall 2003, the World Online developers (Adrian Holovaty and Simon Willison) ditched PHP and began using Python to develop its Web sites. As they built intensive, richly interactive sites such as Lawrence.com, they began to extract a generic Web development framework that let them build Web applications more and more quickly. They tweaked this framework constantly, adding improvements over two years. In summer 2005, World Online decided to open-source the resulting software, Django. Django would not be possible without a whole host of open-source projects Apache, Python, and PostgreSQL to name a few and were thrilled to be able to give something back to the open-source community.
41.2 What does Django mean, and how do you pronounce it?
Django is named after Django Reinhardt, a gypsy jazz guitarist from the 1930s to early 1950s. To this day, hes considered one of the best guitarists of all time. Listen to his music. Youll like it. Django is pronounced JANG-oh. Rhymes with FANG-oh. The D is silent. Weve also recorded an audio clip of the pronunciation.
421
41.7 Django appears to be a MVC framework, but you call the Controller the view, and the View the template. How come you dont use the standard names?
Well, the standard names are debatable. In our interpretation of MVC, the view describes the data that gets presented to the user. Its not necessarily how the data looks, but which data is presented. The view describes which data you see, not how you see it. Its a subtle distinction. So, in our case, a view is the Python callback function for a particular URL, because that callback function describes which data is presented. Furthermore, its sensible to separate content from presentation which is where templates come in. In Django, a view describes which data is presented, but a view normally delegates to a template, which describes how the data is presented. Where does the controller t in, then? In Djangos case, its probably the framework itself: the machinery that sends a request to the appropriate view, according to the Django URL conguration. If youre hungry for acronyms, you might say that Django is a MTV framework that is, model, template, and view. That breakdown makes much more sense. At the end of the day, of course, it comes down to getting stuff done. And, regardless of how things are named, Django gets stuff done in a way thats most logical to us.
422
41.9 Why did you write all of Django from scratch, instead of using other Python libraries?
When Django was originally written a couple of years ago, Adrian and Simon spent quite a bit of time exploring the various Python Web frameworks available. In our opinion, none of them were completely up to snuff. Were picky. You might even call us perfectionists. (With deadlines.) Over time, we stumbled across open-source libraries that did things wed already implemented. It was reassuring to see other people solving similar problems in similar ways, but it was too late to integrate outside code: Wed already written, tested and implemented our own framework bits in several production settings and our own code met our needs delightfully. In most cases, however, we found that existing frameworks/tools inevitably had some sort of fundamental, fatal aw that made us squeamish. No tool t our philosophies 100%. Like we said: Were picky. Weve documented our philosophies on the design philosophies page.
423
424
CHAPTER
FORTYTWO
FAQ: INSTALLATION
42.1 How do I get started?
1. Download the code. 2. Install Django (read the installation guide). 3. Walk through the tutorial. 4. Check out the rest of the documentation, and ask questions if you run into trouble.
42.3 Do I lose anything by using Python 2.4 versus newer Python versions, such as Python 2.5 or 2.6?
Not in the core framework. Currently, Django itself ofcially supports any version of Python from 2.4 through 2.6, inclusive. However, newer versions of Python are often faster, have more features, and are better supported. Thirdparty applications for use with Django are, of course, free to set their own version requirements. Over the next year or two Django will begin dropping support for older Python versions as part of a migration which will end with Django running on Python 3 (see below for details). All else being equal, we recommend that you use the latest 2.x release (currently Python 2.6). This will let you take advantage of the numerous improvements and optimizations to the Python language since version 2.4, and will help ease the process of dropping support for older Python versions on the road to Python 3.
425
42.6 Will Django run under shared hosting (like TextDrive or Dreamhost)?
See our Django-friendly Web hosts page.
426
CHAPTER
FORTYTHREE
error
about
importing
427
1. In your settings le, youll need to dene MEDIA_ROOT as the full path to a directory where youd like Django to store uploaded les. (For performance, these les are not stored in the database.) Dene MEDIA_URL as the base public URL of that directory. Make sure that this directory is writable by the Web servers user account. 2. Add the FileField or ImageField to your model, making sure to dene the upload_to option to tell Django to which subdirectory of MEDIA_ROOT it should upload les. 3. All that will be stored in your database is a path to the le (relative to MEDIA_ROOT). Youll most likely want to use the convenience url attribute provided by Django. For example, if your ImageField is called mug_shot, you can get the absolute URL to your image in a template with {{ object.mug_shot.url }}.
428
CHAPTER
FORTYFOUR
429
430
CHAPTER
FORTYFIVE
connection.queries is only available if DEBUG is True. Its a list of dictionaries in order of query execution. Each dictionary has the following:
sql -- The raw SQL statement time -- How long the statement took to execute, in seconds.
connection.queries includes all SQL statements INSERTs, UPDATES, SELECTs, etc. Each time your app hits the database, the query will be recorded. Note that the raw SQL logged in connection.queries may not include parameter quoting. Parameter quoting is performed by the database-specic backend, and not all backends provide a way to retrieve the SQL after quoting. New in version 1.2: Please, see the release notes If you are using multiple databases, you can use the same interface on each member of the connections dictionary:
>>> from django.db import connections >>> connections[my_db_alias].queries
431
This drops any tables associated with appname and recreates them. If you do care about deleting data, youll have to execute the ALTER TABLE statements manually in your database. Thats the way weve always done it, because dealing with data is a very sensitive operation that weve wanted to avoid automating. That said, theres some work being done to add partially automated database-upgrade functionality.
45.5 How do I add database-specic options to my CREATE TABLE statements, such as specifying MyISAM as the table type?
We try to avoid adding special cases in the Django code to accommodate all the database-specic options such as table type, etc. If youd like to use any of these options, create an SQL initial data le that contains ALTER TABLE statements that do what you want to do. The initial data les are executed in your database after the CREATE TABLE statements. For example, if youre using MySQL and want your tables to use the MyISAM table type, create an initial data le and put something like this in it:
ALTER TABLE myapp_mytable ENGINE=MyISAM;
As explained in the SQL initial data le documentation, this SQL le can contain arbitrary SQL, so you can make any sorts of changes you need to make.
432
CHAPTER
FORTYSIX
46.2 I cant log in. When I enter a valid username and password, it brings up the login page again, with a Please enter a correct username and password error.
If youre sure your username and password are correct, make sure your user account has is_active and is_staff set to True. The admin site only allows access to users with those two elds both set to True.
46.3 How can I prevent the cache middleware from caching the admin site?
Set the CACHE_MIDDLEWARE_ANONYMOUS_ONLY setting to True. See the cache documentation for more information.
46.4 How do I automatically set a elds value to the user who last edited the object in the admin?
The ModelAdmin class provides customization hooks that allow you to transform an object as it saved, using details from the request. By extracting the current user from the request, and customizing the
433
ModelAdmin.save_model() hook, you can update an object to reect the user that edited it. See the documentation on ModelAdmin methods for an example.
46.5 How do I limit admin access so that objects can only be edited by the users who created them?
The ModelAdmin class also provides customization hooks that allow you to control the visibility and editability of objects in the admin. Using the same trick of extracting the user from the request, the ModelAdmin.queryset() and ModelAdmin.has_change_permission() can be used to control the visibility and editability of objects in the admin.
46.6 My admin-site CSS and images showed up ne using the development server, but theyre not displaying when using mod_python.
See serving the admin les in the How to use Django with mod_python documentation.
46.9 The dynamically-generated admin site is ugly! How can I change it?
We like it, but if you dont agree, you can modify the admin sites presentation by editing the CSS stylesheet and/or associated image les. The site is built using semantic HTML and plenty of CSS hooks, so any changes youd like to make should be possible by editing the stylesheet. Weve got a guide to the CSS used in the admin to get you started.
434
CHAPTER
FORTYSEVEN
47.2 I submitted a bug x in the ticket system several weeks ago. Why are you ignoring my patch?
Dont worry: Were not ignoring you! Its important to understand there is a difference between a ticket is being ignored and a ticket has not been attended to yet. Djangos ticket system contains hundreds of open tickets, of various degrees of impact on end-user functionality, and Djangos developers have to review and prioritize. On top of that: the people who work on Django are all volunteers. As a result, the amount of time that we have to work on the framework is limited and will vary from week to week depending on our spare time. If were busy, we may not be able to spend as much time on Django as we might want. The best way to make sure tickets do not get hung up on the way to checkin is to make it dead easy, even for someone who may not be intimately familiar with that area of the code, to understand the problem and verify the x: Are there clear instructions on how to reproduce the bug? If this touches a dependency (such as PIL), a contrib module, or a specic database, are those instructions clear enough even for someone not familiar with it? If there are several patches attached to the ticket, is it clear what each one does, which ones can be ignored and which matter? Does the patch include a unit test? If not, is there a very clear explanation why not? A test expresses succinctly what the problem is, and shows that the patch actually xes it. If your patch stands no chance of inclusion in Django, we wont ignore it well just close the ticket. So if your ticket is still open, it doesnt mean were ignoring you; it just means we havent had time to look at it yet.
47.3 When and how might I remind the core team of a patch I care about?
A polite, well-timed message to the mailing list is one way to get attention. To determine the right time, you need to keep an eye on the schedule. If you post your message when the core developers are trying to hit a feature deadline or manage a planning phase, youre not going to get the sort of attention you require. However, if you draw attention to a
435
ticket when the core developers are paying particular attention to bugs just before a bug xing sprint, or in the lead up to a beta release for example youre much more likely to get a productive response. Gentle IRC reminders can also work again, strategically timed if possible. During a bug sprint would be a very good time, for example. Another way to get traction is to pull several related tickets together. When the core developers sit down to x a bug in an area they havent touched for a while, it can take a few minutes to remember all the ne details of how that area of code works. If you collect several minor bug xes together into a similarly themed group, you make an attractive target, as the cost of coming up to speed on an area of code can be spread over multiple tickets. Please refrain from emailing core developers personally, or repeatedly raising the same issue over and over. This sort of behavior will not gain you any additional attention certainly not the attention that you need in order to get your pet bug addressed.
47.4 But Ive reminded you several times and you keep ignoring my patch!
Seriously - were not ignoring you. If your patch stands no chance of inclusion in Django, well close the ticket. For all the other tickets, we need to prioritize our efforts, which means that some tickets will be addressed before others. One of the criteria that is used to prioritize bug xes is the number of people that will likely be affected by a given bug. Bugs that have the potential to affect many people will generally get priority over those that are edge cases. Another reason that bugs might be ignored for while is if the bug is a symptom of a larger problem. While we can spend time writing, testing and applying lots of little patches, sometimes the right solution is to rebuild. If a rebuild or refactor of a particular component has been proposed or is underway, you may nd that bugs affecting that component will not get as much attention. Again, this is just a matter of prioritizing scarce resources. By concentrating on the rebuild, we can close all the little bugs at once, and hopefully prevent other little bugs from appearing in the future. Whatever the reason, please keep in mind that while you may hit a particular bug regularly, it doesnt necessarily follow that every single Django user will hit the same bug. Different users use Django in different ways, stressing different parts of the code under different conditions. When we evaluate the relative priorities, we are generally trying to consider the needs of the entire community, not just the severity for one particular user. This doesnt mean that we think your problem is unimportant just that in the limited time we have available, we will always err on the side of making 10 people happy rather than making 1 person happy.
436
Part V
API Reference
437
CHAPTER
FORTYEIGHT
AUTHENTICATION BACKENDS
This document details the authentication backends that come with Django. For information on how to use them and how to write your own authentication backends, see the Other authentication sources section of the User authentication guide.
439
440
CHAPTER
FORTYNINE
CONTRIB PACKAGES
Django aims to follow Pythons batteries included philosophy. It ships with a variety of extra, optional tools that solve common Web-development problems. This code lives in django/contrib in the Django distribution. This document gives a rundown of the packages in contrib, along with any dependencies those packages have. Note For most of these add-ons specically, the add-ons that include either models or template tags youll need to add the package name (e.g., django.contrib.admin) to your INSTALLED_APPS setting and re-run manage.py syncdb.
49.1.1 Overview
There are six steps in activating the Django admin site: 1. Add django.contrib.admin to your INSTALLED_APPS setting. 2. Admin has two dependencies - django.contrib.auth and django.contrib.contenttypes. If these applications are not in your INSTALLED_APPS list, add them. 3. Determine which of your applications models should be editable in the admin interface. 4. For each of those models, optionally create a ModelAdmin class that encapsulates the customized admin functionality and options for that particular model. 5. Instantiate an AdminSite and tell it about each of your models and ModelAdmin classes. 6. Hook the AdminSite instance into your URLconf.
441
Other topics
Admin actions
New in version 1.1: Please, see the release notes The basic workow of Djangos admin is, in a nutshell, select an object, then change it. This works well for a majority of use cases. However, if you need to make the same change to many objects at once, this workow can be quite tedious. In these cases, Djangos admin lets you write and register actions simple functions that get called with a list of objects selected on the change list page. If you look at any change list in the admin, youll see this feature in action; Django ships with a delete selected objects action available to all models. For example, heres the user module from Djangos built-in django.contrib.auth app:
Warning: The delete selected objects action uses QuerySet.delete() for efciency reasons, which has an important caveat: your models delete() method will not be called. If you wish to override this behavior, simply write a custom action which accomplishes deletion in your preferred manner for example, by calling Model.delete() for each of the selected items. For more background on bulk deletion, see the documentation on object deletion. Read on to nd out how to add your own actions to this list. Writing actions The easiest way to explain actions is by example, so lets dive in. A common use case for admin actions is the bulk updating of a model. Imagine a simple news application with an Article model:
from django.db import models STATUS_CHOICES = ( (d, Draft), (p, Published), (w, Withdrawn), )
442
class Article(models.Model): title = models.CharField(max_length=100) body = models.TextField() status = models.CharField(max_length=1, choices=STATUS_CHOICES) def __unicode__(self): return self.title
A common task we might perform with a model like this is to update an articles status from draft to published. We could easily do this in the admin one article at a time, but if we wanted to bulk-publish a group of articles, itd be tedious. So, lets write an action that lets us change an articles status to published. Writing action functions First, well need to write a function that gets called when the action is trigged from the admin. Action functions are just regular functions that take three arguments: The current ModelAdmin An HttpRequest representing the current request, A QuerySet containing the set of objects selected by the user. Our publish-these-articles function wont need the ModelAdmin or the request object, but we will use the queryset:
def make_published(modeladmin, request, queryset): queryset.update(status=p)
Note: For the best performance, were using the querysets update method. Other types of actions might need to deal with each object individually; in these cases wed just iterate over the queryset:
for obj in queryset: do_something_with(obj)
Thats actually all there is to writing an action! However, well take one more optional-but-useful step and give the action a nice title in the admin. By default, this action would appear in the action list as Make published the function name, with underscores replaced by spaces. Thats ne, but we can provide a better, more human-friendly name by giving the make_published function a short_description attribute:
def make_published(modeladmin, request, queryset): queryset.update(status=p) make_published.short_description = "Mark selected stories as published"
Note: This might look familiar; the admins list_display option uses the same technique to provide humanreadable descriptions for callback functions registered there, too. Adding actions to the ModelAdmin Next, well need to inform our ModelAdmin of the action. This works just like any other conguration option. So, the complete admin.py with the action and its registration would look like:
from django.contrib import admin from myapp.models import Article def make_published(modeladmin, request, queryset): queryset.update(status=p) make_published.short_description = "Mark selected stories as published" class ArticleAdmin(admin.ModelAdmin):
443
That code will give us an admin change list that looks something like this:
Thats really all there is to it! If youre itching to write your own actions, you now know enough to get started. The rest of this document just covers more advanced techniques. Advanced action techniques Theres a couple of extra options and possibilities you can exploit for more advanced options. Actions as ModelAdmin methods The example above shows the make_published action dened as a simple function. Thats perfectly ne, but its not perfect from a code design point of view: since the action is tightly coupled to the Article object, it makes sense to hook the action to the ArticleAdmin object itself. Thats easy enough to do:
class ArticleAdmin(admin.ModelAdmin): ... actions = [make_published] def make_published(self, request, queryset): queryset.update(status=p) make_published.short_description = "Mark selected stories as published"
Notice rst that weve moved make_published into a method and renamed the modeladmin parameter to self, and second that weve now put the string make_published in actions instead of a direct function reference. This tells the ModelAdmin to look up the action as a method. Dening actions as methods gives the action more straightforward, idiomatic access to the ModelAdmin itself, allowing the action to call any of the methods provided by the admin. For example, we can use self to ash a message to the user informing her that the action was successful: 444 Chapter 49. contrib packages
class ArticleAdmin(admin.ModelAdmin): ... def make_published(self, request, queryset): rows_updated = queryset.update(status=p) if rows_updated == 1: message_bit = "1 story was" else: message_bit = "%s stories were" % rows_updated self.message_user(request, "%s successfully marked as published." % message_bit)
This make the action match what the admin itself does after successfully performing an action:
Actions that provide intermediate pages By default, after an action is performed the user is simply redirected back to the original change list page. However, some actions, especially more complex ones, will need to return intermediate pages. For example, the built-in delete action asks for conrmation before deleting the selected objects. To provide an intermediary page, simply return an HttpResponse (or subclass) from your action. For example, you might write a simple export function that uses Djangos serialization functions to dump some selected objects as JSON:
from django.http import HttpResponse from django.core import serializers def export_as_json(modeladmin, request, queryset): response = HttpResponse(mimetype="text/javascript") serializers.serialize("json", queryset, stream=response) return response
Generally, something like the above isnt considered a great idea. Most of the time, the best practice will be to return an HttpResponseRedirect and redirect the user to a view youve written, passing the list of selected objects in the GET query string. This allows you to provide complex interaction logic on the intermediary pages. For example, if you wanted to provide a more complete export function, youd want to let the user choose a format, and possibly a list of elds to include in the export. The best thing to do would be to write a small action that simply redirects to your custom export view: 49.1. The Django admin site 445
from django.contrib import admin from django.contrib.contenttypes.models import ContentType from django.http import HttpResponseRedirect def export_selected_objects(modeladmin, request, queryset): selected = request.POST.getlist(admin.ACTION_CHECKBOX_NAME) ct = ContentType.objects.get_for_model(queryset.model) return HttpResponseRedirect("/export/?ct=%s&ids=%s" % (ct.pk, ",".join(selected)))
As you can see, the action is the simple part; all the complex logic would belong in your export view. This would need to deal with objects of any type, hence the business with the ContentType. Writing this view is left as an exercise to the reader. Making actions available site-wide add_action(action, [name]) Some actions are best if theyre made available to any object in the admin site the export action dened above would be a good candidate. You can make an action globally available using AdminSite.add_action(). For example:
from django.contrib import admin admin.site.add_action(export_selected_objects)
This makes the export_selected_objects action globally available as an action named export_selected_objects. You can explicitly give the action a name good if you later want to programatically remove the action by passing a second argument to AdminSite.add_action():
admin.site.add_action(export_selected_objects, export_selected)
Disabling actions Sometimes you need to disable certain actions especially those registered site-wide for particular objects. Theres a few ways you can disable actions: Disabling a site-wide action disable_action(name) If you need to disable a site-wide action you can call AdminSite.disable_action(). For example, you can use this method to remove the built-in delete selected objects action:
admin.site.disable_action(delete_selected)
Once youve done the above, that action will no longer be available site-wide. If, however, you need to re-enable a globally-disabled action for one particular model, simply list it explicitally in your ModelAdmin.actions list:
# Globally disable delete selected admin.site.disable_action(delete_selected) # This ModelAdmin will not have delete_selected available class SomeModelAdmin(admin.ModelAdmin): actions = [some_other_action] ...
446
Disabling all actions for a particular ModelAdmin If you want no bulk actions available for a given ModelAdmin, simply set ModelAdmin.actions to None:
class MyModelAdmin(admin.ModelAdmin): actions = None
This tells the ModelAdmin to not display or allow any actions, including any site-wide actions. Conditionally enabling or disabling actions get_actions(request) Finally, you can conditionally enable or disable actions on a per-request (and hence per-user basis) by overriding ModelAdmin.get_actions(). This returns a dictionary of actions allowed. The keys are action names, and the values are (function, name, short_description) tuples. Most of the time youll use this method to conditionally remove actions from the list gathered by the superclass. For example, if I only wanted users whose names begin with J to be able to delete objects in bulk, I could do the following:
class MyModelAdmin(admin.ModelAdmin): ... def get_actions(self, request): actions = super(MyModelAdmin, self).get_actions(request) if request.user.username[0].upper() != J: del actions[delete_selected] return actions
See Also: For information about serving the media les (images, JavaScript, and CSS) associated with the admin in production, see Serving media les.
447
Do you need a ModelAdmin object at all? In the preceding example, the ModelAdmin class doesnt dene any custom values (yet). As a result, the default admin interface will be provided. If you are happy with the default admin interface, you dont need to dene a ModelAdmin object at all you can register the model class without providing a ModelAdmin description. The preceding example could be simplied to:
from django.contrib import admin from myproject.myapp.models import Author admin.site.register(Author)
ModelAdmin Options The ModelAdmin is very exible. It has several options for dealing with customizing the interface. All options are dened on the ModelAdmin subclass:
class AuthorAdmin(admin.ModelAdmin): date_hierarchy = pub_date
date_hierarchy Set date_hierarchy to the name of a DateField or DateTimeField in your model, and the change list page will include a date-based drilldown navigation by that eld. Example:
date_hierarchy = pub_date
form By default a ModelForm is dynamically created for your model. It is used to create the form presented on both the add/change pages. You can easily provide your own ModelForm to override any default form behavior on the add/change pages. For an example see the section Adding custom validation to the admin. fieldsets Set fieldsets to control the layout of admin add and change pages. fieldsets is a list of two-tuples, in which each two-tuple represents a <fieldset> on the admin form page. (A <fieldset> is a section of the form.) The two-tuples are in the format (name, field_options), where name is a string representing the title of the eldset and field_options is a dictionary of information about the eldset, including a list of elds to be displayed in it. A full example, taken from the django.contrib.flatpages.FlatPage model:
class FlatPageAdmin(admin.ModelAdmin): fieldsets = ( (None, { fields: (url, title, content, sites) }), (Advanced options, { classes: (collapse,), fields: (enable_comments, registration_required, template_name)
448
}), )
If fieldsets isnt given, Django will default to displaying each eld that isnt an AutoField and has editable=True, in a single eldset, in the same order as the elds are dened in the model. The field_options dictionary can have the following keys: fields A tuple of eld names to display in this eldset. This key is required. Example:
{ fields: (first_name, last_name, address, city, state), }
To display multiple elds on the same line, wrap those elds in their own tuple. In this example, the first_name and last_name elds will display on the same line:
{ fields: ((first_name, last_name), address, city, state), }
New in version 1.2: Please, see the release notes fields can contain values dened in ModelAdmin.readonly_fields to be displayed as read-only. classes A list containing extra CSS classes to apply to the eldset. Example:
449
Two useful classes dened by the default admin site stylesheet are collapse and wide. Fieldsets with the collapse style will be initially collapsed in the admin and replaced with a small click to expand link. Fieldsets with the wide style will be given extra horizontal space. description A string of optional extra text to be displayed at the top of each eldset, under the heading of the eldset. Note that this value is not HTML-escaped when its displayed in the admin interface. This lets you include HTML if you so desire. Alternatively you can use plain text and django.utils.html.escape() to escape any HTML special characters. fields Use this option as an alternative to fieldsets if the layout does not matter and if you want to only show a subset of the available elds in the form. For example, you could dene a simpler version of the admin form for the django.contrib.flatpages.FlatPage model as follows:
class FlatPageAdmin(admin.ModelAdmin): fields = (url, title, content)
In the above example, only the elds url, title and content will be displayed, sequentially, in the form. New in version 1.2: Please, see the release notes fields can contain values dened in ModelAdmin.readonly_fields to be displayed as read-only. Note This fields option should not be confused with the fields dictionary key that is within the fieldsets option, as described in the previous section. exclude This attribute, if given, should be a list of eld names to exclude from the form. For example, lets consider the following model:
class Author(models.Model): name = models.CharField(max_length=100) title = models.CharField(max_length=3) birth_date = models.DateField(blank=True, null=True)
If you want a form for the Author model that includes only the name and title elds, you would specify fields or exclude like this:
class AuthorAdmin(admin.ModelAdmin): fields = (name, title) class AuthorAdmin(admin.ModelAdmin): exclude = (birth_date,)
Since the Author model only has three elds, name, title, and birth_date, the forms resulting from the above declarations will contain exactly the same elds. filter_horizontal
450
Use a nifty unobtrusive JavaScript lter interface instead of the usability-challenged <select multiple> in the admin form. The value is a list of elds that should be displayed as a horizontal lter interface. See filter_vertical to use a vertical interface. filter_vertical Same as filter_horizontal, but is a vertical display of the lter interface. list_display Set list_display to control which elds are displayed on the change list page of the admin. Example:
list_display = (first_name, last_name)
If you dont set list_display, the admin site will display a single column that displays the __unicode__() representation of each object. You have four possible values that can be used in list_display: A eld of the model. For example:
class PersonAdmin(admin.ModelAdmin): list_display = (first_name, last_name)
A callable that accepts one parameter for the model instance. For example:
def upper_case_name(obj): return ("%s %s" % (obj.first_name, obj.last_name)).upper() upper_case_name.short_description = Name class PersonAdmin(admin.ModelAdmin): list_display = (upper_case_name,)
A string representing an attribute on the ModelAdmin. This behaves same as the callable. For example:
class PersonAdmin(admin.ModelAdmin): list_display = (upper_case_name,) def upper_case_name(self, obj): return ("%s %s" % (obj.first_name, obj.last_name)).upper() upper_case_name.short_description = Name
A string representing an attribute on the model. This behaves almost the same as the callable, but self in this context is the model instance. Heres a full model example:
class Person(models.Model): name = models.CharField(max_length=50) birthday = models.DateField() def decade_born_in(self): return self.birthday.strftime(%Y)[:3] + "0s" decade_born_in.short_description = Birth decade class PersonAdmin(admin.ModelAdmin): list_display = (name, decade_born_in)
451
If the eld is a ForeignKey, Django will display the __unicode__() of the related object. ManyToManyField elds arent supported, because that would entail executing a separate SQL statement for each row in the table. If you want to do this nonetheless, give your model a custom method, and add that methods name to list_display. (See below for more on custom methods in list_display.) If the eld is a BooleanField or NullBooleanField, Django will display a pretty on or off icon instead of True or False. If the string given is a method of the model, ModelAdmin or a callable, Django will HTML-escape the output by default. If youd rather not escape the output of the method, give the method an allow_tags attribute whose value is True. Heres a full example model:
class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) color_code = models.CharField(max_length=6)
def colored_name(self): return <span style="color: #%s;">%s %s</span> % (self.color_code, self.first_name, sel colored_name.allow_tags = True class PersonAdmin(admin.ModelAdmin): list_display = (first_name, last_name, colored_name)
If the string given is a method of the model, ModelAdmin or a callable that returns True or False Django will display a pretty on or off icon if you give the method a boolean attribute whose value is True. Heres a full example model:
class Person(models.Model): first_name = models.CharField(max_length=50) birthday = models.DateField() def born_in_fifties(self): return self.birthday.strftime(%Y)[:3] == 195 born_in_fifties.boolean = True class PersonAdmin(admin.ModelAdmin): list_display = (name, born_in_fifties)
The __str__() and __unicode__() methods are just as valid in list_display as any other model method, so its perfectly OK to do this:
list_display = (__unicode__, some_other_field)
Usually, elements of list_display that arent actual database elds cant be used in sorting (because Django does all the sorting at the database level). However, if an element of list_display represents a certain database eld, you can indicate this fact by setting the admin_order_field attribute of the item. For example:
class Person(models.Model): first_name = models.CharField(max_length=50) color_code = models.CharField(max_length=6)
452
def colored_first_name(self): return <span style="color: #%s;">%s</span> % (self.color_code, self.first_name) colored_first_name.allow_tags = True colored_first_name.admin_order_field = first_name class PersonAdmin(admin.ModelAdmin): list_display = (first_name, colored_first_name)
The above will tell Django to order by the first_name eld when trying to sort by colored_first_name in the admin. list_display_links Set list_display_links to control which elds in list_display should be linked to the change page for an object. By default, the change list page will link the rst column the rst eld specied in list_display to the change page for each item. But list_display_links lets you change which columns are linked. Set list_display_links to a list or tuple of eld names (in the same format as list_display) to link. list_display_links can specify one or many eld names. As long as the eld names appear in list_display, Django doesnt care how many (or how few) elds are linked. The only requirement is: If you want to use list_display_links, you must dene list_display. In this example, the first_name and last_name elds will be linked on the change list page:
class PersonAdmin(admin.ModelAdmin): list_display = (first_name, last_name, birthday) list_display_links = (first_name, last_name)
list_editable New in version 1.1: Please, see the release notes Set list_editable to a list of eld names on the model which will allow editing on the change list page. That is, elds listed in list_editable will be displayed as form widgets on the change list page, allowing users to edit and save multiple rows at once. Note: list_editable interacts with a couple of other options in particular ways; you should note the following rules: Any eld in list_editable must also be in list_display. You cant edit a eld thats not displayed! The same eld cant be listed in both list_editable and list_display_links a eld cant be both a form and a link. Youll get a validation error if either of these rules are broken. list_filter Set list_filter to activate lters in the right sidebar of the change list page of the admin. This should be a list of eld names, and each specied eld should be either a BooleanField, CharField, DateField, DateTimeField, IntegerField or ForeignKey. This example, taken from the django.contrib.auth.models.User model, list_display and list_filter work: shows how both
class UserAdmin(admin.ModelAdmin): list_display = (username, email, first_name, last_name, is_staff) list_filter = (is_staff, is_superuser)
The above code results in an admin change list page that looks like this:
453
(This example also has search_fields dened. See below.) list_per_page Set list_per_page to control how many items appear on each paginated admin change list page. By default, this is set to 100. list_select_related Set list_select_related to tell Django to use select_related() in retrieving the list of objects on the admin change list page. This can save you a bunch of database queries. The value should be either True or False. Default is False. Note that Django will use select_related(), regardless of this setting, if one of the list_display elds is a ForeignKey. For more on select_related(), see the select_related() docs. inlines See InlineModelAdmin objects below. ordering Set ordering to specify how objects on the admin change list page should be ordered. This should be a list or tuple in the same format as a models ordering parameter. If this isnt provided, the Django admin will use the models default ordering. Note Django will only honor the rst element in the list/tuple; any others will be ignored. prepopulated_fields Set prepopulated_fields to a dictionary mapping eld names to the elds it should prepopulate from:
class ArticleAdmin(admin.ModelAdmin): prepopulated_fields = {"slug": ("title",)}
When set, the given elds will use a bit of JavaScript to populate from the elds assigned. The main use for this functionality is to automatically generate the value for SlugField elds from one or more other elds. The generated value is produced by concatenating the values of the source elds, and then by transforming that result into a valid slug (e.g. substituting dashes for spaces).
454
prepopulated_fields doesnt accept DateTimeField, ForeignKey, nor ManyToManyField elds. radio_fields By default, Djangos admin uses a select-box interface (<select>) for elds that are ForeignKey or have choices set. If a eld is present in radio_fields, Django will use a radio-button interface instead. Assuming group is a ForeignKey on the Person model:
class PersonAdmin(admin.ModelAdmin): radio_fields = {"group": admin.VERTICAL}
You have the choice of using HORIZONTAL or VERTICAL from the django.contrib.admin module. Dont include a eld in radio_fields unless its a ForeignKey or has choices set. raw_id_fields By default, Djangos admin uses a select-box interface (<select>) for elds that are ForeignKey. Sometimes you dont want to incur the overhead of having to select all the related instances to display in the drop-down. raw_id_fields is a list of elds you would like to change into a Input widget for either a ForeignKey or ManyToManyField:
class ArticleAdmin(admin.ModelAdmin): raw_id_fields = ("newspaper",)
readonly_fields New in version 1.2: Please, see the release notes By default the admin shows all elds as editable. Any elds in this option (which should be a list or tuple) will display its data as-is and non-editable. This option behaves nearly identical to ModelAdmin.list_display. Usage is the same, however, when you specify ModelAdmin.fields or ModelAdmin.fieldsets the read-only elds must be present to be shown (they are ignored otherwise). If readonly_fields is used without dening explicit ordering through ModelAdmin.fields or ModelAdmin.fieldsets they will be added last after all editable elds. save_as Set save_as to enable a save as feature on admin change forms. Normally, objects have three save options: Save, Save and continue editing and Save and add another. If save_as is True, Save and add another will be replaced by a Save as button. Save as means the object will be saved as a new object (with a new ID), rather than the old object. By default, save_as is set to False. save_on_top Set save_on_top to add save buttons across the top of your admin change forms. Normally, the save buttons appear only at the bottom of the forms. If you set save_on_top, the buttons will appear both on the top and the bottom. By default, save_on_top is set to False. search_fields Set search_fields to enable a search box on the admin change list page. This should be set to a list of eld names that will be searched whenever somebody submits a search query in that text box. These elds should be some kind of text eld, such as CharField or TextField. You can also perform a related lookup on a ForeignKey with the lookup API follow notation:
455
search_fields = [foreign_key__related_fieldname]
When somebody does a search in the admin search box, Django splits the search query into words and returns all objects that contain each of the words, case insensitive, where each word must be in at least one of search_fields. For example, if search_fields is set to [first_name, last_name] and a user searches for john lennon, Django will do the equivalent of this SQL WHERE clause:
WHERE (first_name ILIKE %john% OR last_name ILIKE %john%) AND (first_name ILIKE %lennon% OR last_name ILIKE %lennon%)
For faster and/or more restrictive searches, prex the eld name with an operator: ^ Matches the beginning of the eld. For example, if search_fields is set to [^first_name, ^last_name] and a user searches for john lennon, Django will do the equivalent of this SQL WHERE clause:
WHERE (first_name ILIKE john% OR last_name ILIKE john%) AND (first_name ILIKE lennon% OR last_name ILIKE lennon%)
This query is more efcient than the normal %john% query, because the database only needs to check the beginning of a columns data, rather than seeking through the entire columns data. Plus, if the column has an index on it, some databases may be able to use the index for this query, even though its a LIKE query. = Matches exactly, case-insensitive. For example, if search_fields is set to [=first_name, =last_name] and a user searches for john lennon, Django will do the equivalent of this SQL WHERE clause:
WHERE (first_name ILIKE john OR last_name ILIKE john) AND (first_name ILIKE lennon OR last_name ILIKE lennon)
Note that the query input is split by spaces, so, following this example, its currently not possible to search for all records in which first_name is exactly john winston (containing a space). @ Performs a full-text match. This is like the default search method but uses an index. Currently this is only available for MySQL. formfield_overrides New in version 1.1: Please, see the release notes This provides a quick-and-dirty way to override some of the Field options for use in the admin. formfield_overrides is a dictionary mapping a eld class to a dict of arguments to pass to the eld at construction time. Since thats a bit abstract, lets look at a concrete example. The most common use of formfield_overrides is to add a custom widget for a certain type of eld. So, imagine weve written a RichTextEditorWidget that wed like to use for large text elds instead of the default <textarea>. Heres how wed do that:
from django.db import models from django.contrib import admin # Import our custom widget and our model from where theyre defined from myapp.widgets import RichTextEditorWidget from myapp.models import MyModel class MyModelAdmin(admin.ModelAdmin): formfield_overrides = { models.TextField: {widget: RichTextEditorWidget}, }
456
Note that the key in the dictionary is the actual eld class, not a string. The value is another dictionary; these arguments will be passed to __init__(). See The Forms API for details. Warning: If you want to use a custom widget with a relation eld (i.e. ForeignKey or ManyToManyField), make sure you havent included that elds name in raw_id_fields or radio_fields. formfield_overrides wont let you change the widget on relation elds that have raw_id_fields or radio_fields set. Thats because raw_id_fields and radio_fields imply custom widgets of their own. actions New in version 1.1: Please, see the release notes A list of actions to make available on the change list page. See Admin actions for details. actions_on_top actions_on_bottom New in version 1.1: Please, see the release notes Controls where on the page the actions bar appears. By default, the admin changelist displays actions at the top of the page (actions_on_top = True; actions_on_bottom = False). actions_selection_counter New in version 1.2: Please, see the release notes Controls whether a selection counter is display next to the action dropdown. By default, the admin changelist will display it (actions_selection_counter = True).
457
The save_model method is given the HttpRequest, a model instance, a ModelForm instance and a boolean value based on whether it is adding or changing the object. Here you can do any pre- or post-save operations. For example to attach request.user to the object prior to saving:
class ArticleAdmin(admin.ModelAdmin): def save_model(self, request, obj, form, change): obj.user = request.user obj.save()
save_formset(self, request, form, formset, change) The save_formset method is given the HttpRequest, the parent ModelForm instance and a boolean value based on whether it is adding or changing the parent object. For example to attach request.user to each changed formset model instance:
class ArticleAdmin(admin.ModelAdmin): def save_formset(self, request, form, formset, change): instances = formset.save(commit=False) for instance in instances: instance.user = request.user instance.save() formset.save_m2m()
get_readonly_fields(self, request, obj=None) New in version 1.2: Please, see the release notes The get_readonly_fields method is given the HttpRequest and the obj being edited (or None on an add form) and is expected to return a list or tuple of eld names that will be displayed as read-only, as described above in the ModelAdmin.readonly_fields section. get_urls(self ) New in version 1.1: Please, see the release notes The get_urls method on a ModelAdmin returns the URLs to be used for that ModelAdmin in the same way as a URLconf. Therefore you can extend them as documented in URL dispatcher:
class MyModelAdmin(admin.ModelAdmin): def get_urls(self): urls = super(MyModelAdmin, self).get_urls() my_urls = patterns(, (r^my_view/$, self.my_view) ) return my_urls + urls
Note: Notice that the custom patterns are included before the regular admin URLs: the admin URL patterns are very permissive and will match nearly anything, so youll usually want to prepend your custom URLs to the built-in ones. However, the self.my_view function registered above suffers from two problems: It will not perform any permission checks, so it will be accessible to the general public. It will not provide any header details to prevent caching. This means if the page retrieves data from the database, and caching middleware is active, the page could show outdated information. Since this is usually not what you want, Django provides a convenience wrapper to check permissions and mark the view as non-cacheable. This wrapper is AdminSite.admin_view() (i.e. self.admin_site.admin_view inside a ModelAdmin instance); use it like so:
458
class MyModelAdmin(admin.ModelAdmin): def get_urls(self): urls = super(MyModelAdmin, self).get_urls() my_urls = patterns(, (r^my_view/$, self.admin_site.admin_view(self.my_view)) ) return my_urls + urls
This wrapping will protect self.my_view from unauthorized access and will apply the django.views.decorators.cache.never_cache decorator to make sure it is not cached if the cache middleware is active. If the page is cacheable, but you still want the permission check to be performed, you can pass a cacheable=True argument to AdminSite.admin_view():
(r^my_view/$, self.admin_site.admin_view(self.my_view, cacheable=True))
formfield_for_foreignkey(self, db_eld, request, **kwargs) New in version 1.1: Please, see the release notes The formfield_for_foreignkey method on a ModelAdmin allows you to override the default formeld for a foreign key eld. For example, to return a subset of objects for this foreign key eld based on the user:
class MyModelAdmin(admin.ModelAdmin): def formfield_for_foreignkey(self, db_field, request, **kwargs): if db_field.name == "car": kwargs["queryset"] = Car.objects.filter(owner=request.user) return db_field.formfield(**kwargs) return super(MyModelAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
This uses the HttpRequest instance to lter the Car foreign key eld to only the cars owned by the User instance. queryset(self, request) The queryset method on a ModelAdmin returns a QuerySet of all model instances that can be edited by the admin site. One use case for overriding this method is to show objects owned by the logged-in user:
class MyModelAdmin(admin.ModelAdmin): def queryset(self, request): qs = super(MyModelAdmin, self).queryset(request) if request.user.is_superuser: return qs return qs.filter(author=request.user)
Other methods
add_view(self, request, form_url=, extra_context=None) Django view for the model instance addition page. See note below. change_view(self, request, object_id, extra_context=None)
459
Django view for the model instance edition page. See note below. changelist_view(self, request, extra_context=None) Django view for the model instances change list/actions page. See note below. delete_view(self, request, object_id, extra_context=None) Django view for the model instance(s) deletion conrmation page. See note below. history_view(self, request, object_id, extra_context=None) Django view for the page that shows the modication history for a given model instance. Unlike the hook-type ModelAdmin methods detailed in the previous section, these ve methods are in reality designed to be invoked as Django views from the admin application URL dispatching handler to render the pages that deal with model instances CRUD operations. As a result, completely overriding these methods will signicantly change the behavior of the admin application. One common reason for overriding these methods is to augment the context data that is provided to the template that renders the view. In the following example, the change view is overridden so that the rendered template is provided some extra mapping data that would not otherwise be available:
class MyModelAdmin(admin.ModelAdmin): # A template for a very customized change view: change_form_template = admin/myapp/extras/openstreetmap_change_form.html def get_osm_info(self): # ... def change_view(self, request, object_id, extra_context=None): my_context = { osm_data: self.get_osm_info(), } return super(MyModelAdmin, self).change_view(request, object_id, extra_context=my_context)
ModelAdmin media denitions There are times where you would like add a bit of CSS and/or JavaScript to the add/change views. This can be accomplished by using a Media inner class on your ModelAdmin:
class ArticleAdmin(admin.ModelAdmin): class Media: css = { "all": ("my_styles.css",) } js = ("my_code.js",)
Keep in mind that this will be prepended with MEDIA_URL. The same rules apply as regular media denitions on forms. Django admin Javascript makes use of the jQuery library. To avoid conict with user scripts, Djangos jQuery is namespaced as django.jQuery. If you want to use jQuery in your own admin JavaScript without including a second copy, you can use the django.jQuery object on changelist and add/edit views.
460
Adding custom validation to the admin Adding custom validation of data in the admin is quite easy. The automatic admin interface reuses django.forms, and the ModelAdmin class gives you the ability dene your own form:
class ArticleAdmin(admin.ModelAdmin): form = MyArticleAdminForm
MyArticleAdminForm can be dened anywhere as long as you import where needed. Now within your form you can add your own custom validation for any eld:
class MyArticleAdminForm(forms.ModelForm): class Meta: model = Article def clean_name(self): # do something that validates your data return self.cleaned_data["name"]
It is important you use a ModelForm here otherwise things can break. See the forms documentation on custom validation and, more specically, the model form validation notes for more information.
You can edit the books authored by an author on the author page. You add inlines to a model by specifying them in a ModelAdmin.inlines:
class BookInline(admin.TabularInline): model = Book class AuthorAdmin(admin.ModelAdmin): inlines = [ BookInline, ]
Django provides two subclasses of InlineModelAdmin and they are: TabularInline StackedInline The difference between these two is merely the template used to render them.
461
InlineModelAdmin options The InlineModelAdmin class is a subclass of ModelAdmin so it inherits all the same functionality as well as some of its own:
model
The model in which the inline is using. This is required.
fk_name
The name of the foreign key on the model. In most cases this will be dealt with automatically, but fk_name must be specied explicitly if there are more than one foreign key to the same parent model.
formset
This defaults to BaseInlineFormSet. Using your own formset can give you many possibilities of customization. Inlines are built around model formsets.
form
The value for form defaults to ModelForm. This is what is passed through to inlineformset_factory when creating the formset for this inline.
extra
This controls the number of extra forms the formset will display in addition to the initial forms. See the formsets documentation for more information. New in version 1.2: Please, see the release notes For users with JavaScriptenabled browsers, an Add another link is provided to enable any number of additional inlines to be added in addition to those provided as a result of the extra argument. The dynamic link will not appear if the number of currently displayed forms exceeds max_num, or if the user does not have JavaScript enabled.
max_num
This controls the maximum number of forms to show in the inline. This doesnt directly correlate to the number of objects, but can if the value is small enough. See Limiting the number of editable objects for more information.
raw_id_fields
By default, Djangos admin uses a select-box interface (<select>) for elds that are ForeignKey. Sometimes you dont want to incur the overhead of having to select all the related instances to display in the drop-down. raw_id_fields is a list of elds you would like to change into a Input widget for either a ForeignKey or ManyToManyField:
462
template
The template used to render the inline on the page.
verbose_name
An override to the verbose_name found in the models inner Meta class.
verbose_name_plural
An override to the verbose_name_plural found in the models inner Meta class. Working with a model with two or more foreign keys to the same parent model It is sometimes possible to have more than one foreign key to the same model. Take this model for instance:
class Friendship(models.Model): to_person = models.ForeignKey(Person, related_name="friends") from_person = models.ForeignKey(Person, related_name="from_friends")
If you wanted to display an inline on the Person admin add/change pages you need to explicitly dene the foreign key since it is unable to do so automatically:
class FriendshipInline(admin.TabularInline): model = Friendship fk_name = "to_person" class PersonAdmin(admin.ModelAdmin): inlines = [ FriendshipInline, ]
Working with Many-to-Many Models New in version 1.2: Please, see the release notes By default, admin widgets for many-to-many relations will be displayed on whichever model contains the actual reference to the ManyToManyField. Depending on your ModelAdmin denition, each many-to-many eld in your model will be represented by a standard HTML <select multiple>, a horizontal or vertical lter, or a raw_id_admin widget. However, it is also possible to to replace these widgets with inlines. Suppose we have the following models:
463
class Person(models.Model): name = models.CharField(max_length=128) class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField(Person, related_name=groups)
If you want to display many-to-many relations using an inline, you can do so by dening an InlineModelAdmin object for the relationship:
class MembershipInline(admin.TabularInline): model = Group.members.through class PersonAdmin(admin.ModelAdmin): inlines = [ MembershipInline, ] class GroupAdmin(admin.ModelAdmin): inlines = [ MembershipInline, ] exclude = (members,)
There are two features worth noting in this example. Firstly - the MembershipInline class references Group.members.through. The through attribute is a reference to the model that manages the many-to-many relation. This model is automatically created by Django when you dene a many-to-many eld. Secondly, the GroupAdmin must manually exclude the members eld. Django displays an admin widget for a many-to-many eld on the model that denes the relation (in this case, Group). If you want to use an inline model to represent the many-to-many relationship, you must tell Djangos admin to not display this widget - otherwise you will end up with two widgets on your admin page for managing the relation. In all other respects, the InlineModelAdmin is exactly the same as any other. You can customize the appearance using any of the normal InlineModelAdmin properties. Working with Many-to-Many Intermediary Models When you specify an intermediary model using the through argument to a ManyToManyField, the admin will not display a widget by default. This is because each instance of that intermediary model requires more information than could be displayed in a single widget, and the layout required for multiple widgets will vary depending on the intermediate model. However, we still want to be able to edit that information inline. Fortunately, this is easy to do with inline admin models. Suppose we have the following models:
class Person(models.Model): name = models.CharField(max_length=128) class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField(Person, through=Membership) class Membership(models.Model): person = models.ForeignKey(Person)
464
The rst step in displaying this intermediate model in the admin is to dene an inline class for the Membership model:
class MembershipInline(admin.TabularInline): model = Membership extra = 1
This simple example uses the default InlineModelAdmin values for the Membership model, and limits the extra add forms to one. This could be customized using any of the options available to InlineModelAdmin classes. Now create admin views for the Person and Group models:
class PersonAdmin(admin.ModelAdmin): inlines = (MembershipInline,) class GroupAdmin(admin.ModelAdmin): inlines = (MembershipInline,)
Finally, register your Person and Group models with the admin site:
admin.site.register(Person, PersonAdmin) admin.site.register(Group, GroupAdmin)
Now your admin site is set up to edit Membership objects inline from either the Person or the Group detail pages. Using generic relations as an inline It is possible to use an inline with generically related objects. Lets say you have the following models:
class Image(models.Model): image = models.ImageField(upload_to="images") content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() content_object = generic.GenericForeignKey("content_type", "object_id") class Product(models.Model): name = models.CharField(max_length=100)
If you want to allow editing and creating Image instance on the Product add/change views you can simply use GenericInlineModelAdmin provided by django.contrib.contenttypes.generic. In your admin.py for this example app:
from django.contrib import admin from django.contrib.contenttypes import generic from myproject.myapp.models import Image, Product class ImageInline(generic.GenericTabularInline): model = Image class ProductAdmin(admin.ModelAdmin): inlines = [
465
django.contrib.contenttypes.generic provides both GenericStackedInline and behave just like any other inline. more specic information.
466
{% trans "View on site" %}</a> </li> {% endif%} </ul> {% endif %}{% endif %} {% endblock %}
And thats it! If we placed this le in the templates/admin/my_app directory, our link would appear on every models change form. Templates which may be overridden per app or model Not every template in contrib/admin/templates/admin may be overridden per app or per model. The following can: app_index.html change_form.html change_list.html delete_confirmation.html object_history.html For those templates that cannot be overridden in this way, you may still override them for your entire project. Just place the new version in your templates/admin directory. This is particularly useful to create custom 404 and 500 pages. Note: Some of the admin templates, such as change_list_request.html are used to render custom inclusion tags. These may be overridden, but in such cases you are probably better off creating your own version of the tag in question and giving it a different name. That way you can use it selectively. Root and login templates If you wish to change the index, login or logout templates, you are better off creating your own AdminSite instance (see below), and changing the AdminSite.index_template , AdminSite.login_template or AdminSite.logout_template properties.
467
AdminSite attributes Templates can override or extend base admin templates as described in Overriding Admin Templates. index_template Path to a custom template that will be used by the admin site main index view. login_template Path to a custom template that will be used by the admin site login view. logout_template New in version 1.2: Please, see the release notes Path to a custom template that will be used by the admin site logout view. password_change_template New in version 1.2: Please, see the release notes Path to a custom template that will be used by the admin site password change view. password_change_done_template New in version 1.2: Please, see the release notes Path to a custom template that will be used by the admin site password change done view. Hooking AdminSite instances into your URLconf The last step in setting up the Django admin is to hook your AdminSite instance into your URLconf. Do this by pointing a given URL at the AdminSite.urls method. In this example, we register the default AdminSite instance django.contrib.admin.site at the URL /admin/
# urls.py from django.conf.urls.defaults import * from django.contrib import admin admin.autodiscover() urlpatterns = patterns(, (r^admin/, include(admin.site.urls)), )
Above we used admin.autodiscover() to automatically load the INSTALLED_APPS admin.py modules. In this example, we register the AdminSite instance myproject.admin.admin_site at the URL /myadmin/
# urls.py from django.conf.urls.defaults import * from myproject.admin import admin_site urlpatterns = patterns(, (r^myadmin/, include(admin_site.urls)), )
There is really no need to use autodiscover when using your own AdminSite instance since you will likely be importing all the per-app admin.py modules in your myproject.admin module.
468
Multiple admin sites in the same URLconf Its easy to create multiple instances of the admin site on the same Django-powered Web site. Just create multiple instances of AdminSite and root each one at a different URL. Changed in version 1.1: The method for hooking AdminSite instances into urls has changed in Django 1.1. In this example, the URLs /basic-admin/ and /advanced-admin/ feature separate versions of the admin site using the AdminSite instances myproject.admin.basic_site and myproject.admin.advanced_site, respectively:
# urls.py from django.conf.urls.defaults import * from myproject.admin import basic_site, advanced_site urlpatterns = patterns(, (r^basic-admin/, include(basic_site.urls)), (r^advanced-admin/, include(advanced_site.urls)), )
AdminSite instances take a single argument to their constructor, their name, which can be anything you like. This argument becomes the prex to the URL names for the purposes of reversing them. This is only necessary if you are using more than one AdminSite. Adding views to admin sites New in version 1.1: Please, see the release notes Just like ModelAdmin, AdminSite provides a get_urls() method that can be overridden to dene additional views for the site. To add a new view to your admin site, extend the base get_urls() method to include a pattern for your new view. Note: Any view you render that uses the admin templates, or extends the base admin template, should provide the current_app argument to RequestContext or Context when rendering the template. It should be set to either self.name if your view is on an AdminSite or self.admin_site.name if your view is on a ModelAdmin.
app_label
Each ModelAdmin instance provides an additional set of named URLs: Page Changelist Add History Delete Change URL name {{ app_label {{ app_label {{ app_label {{ app_label {{ app_label Parameters }}_{{ }}_{{ }}_{{ }}_{{ }}_{{ model_name model_name model_name model_name model_name }}_changelist }}_add }}_history }}_delete }}_change
469
These named URLs are registered with the application namespace admin, and with an instance namespace corresponding to the name of the Site instance. So - if you wanted to get a reference to the Change view for a particular Choice object (from the polls application) in the default admin, you would call:
>>> from django.core import urlresolvers >>> c = Choice.objects.get(...) >>> change_url = urlresolvers.reverse(admin:polls_choice_change, args=(c.id,))
This will nd the rst registered instance of the admin application (whatever the instance name), and resolve to the view for changing poll.Choice instances in that instance. If you want to nd a URL in a specic admin instance, provide the name of that instance as a current_app hint to the reverse call. For example, if you specically wanted the admin view from the admin instance named custom, you would need to call:
>>> change_url = urlresolvers.reverse(custom:polls_choice_change, args=(c.id,))
49.2 django.contrib.auth
See User authentication in Django.
4. Use the comment template tags below to embed comments in your templates. You might also want to examine Comment settings.
470
Once loaded you can use the template tags below. Specifying which object comments are attached to Djangos comments are all attached to some parent object. This can be any instance of a Django model. Each of the tags below gives you a couple of different ways you can specify which object to attach to: 1. Refer to the object directly the more common method. Most of the time, youll have some object in the templates context you want to attach the comment to; you can simply use that object. For example, in a blog entry page that has a variable named entry, you could use the following to load the number of comments:
{% get_comment_count for entry as comment_count %}.
2. Refer to the object by content-type and object id. Youd use this method if you, for some reason, dont actually have direct access to the object. Following the above example, if you knew the object ID was 14 but didnt have access to the actual object, you could do something like:
{% get_comment_count for blog.entry 14 as comment_count %}
In the above, blog.entry is the app label and (lower-cased) model name of the model class. Displaying comments To display a list of comments, you can use the template tags render_comment_list or get_comment_list.
For example:
{% render_comment_list for event %}
This will render comments using a template named comments/list.html, a default version of which is included with Django.
471
For example:
{% get_comment_list for event as comment_list %} {% for comment in comment_list %} ... {% endfor %}
This returns a list of Comment objects; see the comment model documentation for details. Linking to comments New in version 1.2: Please, see the release notes To provide a permalink to a specic comment, use get_comment_permalink:
{% get_comment_permalink comment_obj [format_string] %}
By default, the named anchor that will be appended to the URL will be the letter c followed by the comment id, for example c82. You may specify a custom format string if you wish to override this behavior:
{% get_comment_permalink comment "#c%(id)s-by-%(user_name)s"%}
The format string is a standard python format string. Valid mapping keys include any attributes of the comment object. Regardless of whether you specify a custom anchor pattern, you must supply a matching named anchor at a suitable place in your template. For example:
{% for comment in comment_list %} <a name="c{{ comment.id }}"></a> <a href="{% get_comment_permalink comment %}"> permalink for comment #{{ forloop.counter }} </a> ... {% endfor %}
Warning: Theres a known bug in Safari/Webkit which causes the named anchor to be forgotten following a redirect. The practical impact for comments is that the Safari/webkit browsers will arrive at the correct page but will not scroll to the named anchor.
For example:
472
Displaying the comment post form To show the form that users will use to post a comment, you can use render_comment_form or get_comment_form
For example:
{% render_comment_form for event %}
This will render comments using a template named comments/form.html, a default version of which is included with Django.
Be sure to read the notes on the comment form, below, for some special considerations youll need to make if youre using this approach.
473
Notes on the comment form The form used by the comment system has a few important anti-spam attributes you should know about: It contains a number of hidden elds that contain timestamps, information about the object the comment should be attached to, and a security hash used to validate this information. If someone tampers with this data something comment spammers will try the comment submission will fail. If youre rendering a custom comment form, youll need to make sure to pass these values through unchanged. The timestamp is used to ensure that reply attacks cant continue very long. Users who wait too long between requesting the form and posting a comment will have their submissions refused. The comment form includes a honeypot eld. Its a trap: if any data is entered in that eld, the comment will be considered spam (spammers often automatically ll in all elds in an attempt to make valid submissions). The default form hides this eld with a piece of CSS and further labels it with a warning eld; if you use the comment form with a custom template you should be sure to do the same. The comments app also depends on the more general Cross Site Request Forgery protection that comes with Django. As described in the documentation, it is best to use CsrfViewMiddleware. However, if you are not using that, you will need to use the csrf_protect decorator on any views that include the comment form, in order for those views to be able to output the CSRF token and cookie.
user A ForeignKey to the User who posted the comment. May be blank if the comment was posted by an unauthenticated user. user_name The name of the user who posted the comment. user_email The email of the user who posteed the comment. user_url The URL entered by the person who posted the comment. comment The actual content of the comment itself. submit_date The date the comment was submitted. ip_address The IP address of the user posting the comment. is_public False if the comment is in moderation (see Generic comment moderation); If True, the comment will be displayed on the site. is_removed True if the comment was removed. Used to keep track of removed comments instead of just deleting them. Comment settings These settings congure the behavior of the comments framework:
COMMENTS_HIDE_REMOVED
If True (default), removed comments will be excluded from comment lists/counts (as taken from template tags). Otherwise, the template author is responsible for some sort of a this comment has been removed by the site staff message.
COMMENT_MAX_LENGTH
The maximum length of the comment eld, in characters. Comments longer than this will be rejected. Defaults to 3000.
COMMENTS_APP
An app which provides customization of the comments framework. Use the same dotted-string notation as in INSTALLED_APPS. Your custom COMMENTS_APP must also be listed in INSTALLED_APPS.
475
Signals sent by the comments app The comment app sends a series of signals to allow for comment moderation and similar activities. See the introduction to signals for information about how to register for and receive these signals.
comment_will_be_posted
comment_will_be_posted Sent just before a comment will be saved, after its been sanity checked and submitted. This can be used to modify the comment (in place) with posting details or other such actions. If any receiver returns False the comment will be discarded and a 403 (not allowed) response will be returned. This signal is sent at more or less the same time (just before, actually) as the Comment objects pre_save signal. Arguments sent with this signal: sender The comment model. comment The comment instance about to be posted. Note that it wont have been saved into the database yet, so it wont have a primary key, and any relations might not work correctly yet. request The HttpRequest that posted the comment.
comment_was_posted
comment_was_posted Sent just after the comment is saved. Arguments sent with this signal: sender The comment model. comment The comment instance that was posted. Note that it will have already been saved, so if you modify it youll need to call save() again. request The HttpRequest that posted the comment.
comment_was_agged
comment_was_flagged Sent after a comment was agged in some way. Check the ag to see if this was a user requesting removal of a comment, a moderator approving/removing a comment, or some other custom user ag. Arguments sent with this signal: sender The comment model. comment The comment instance that was posted. Note that it will have already been saved, so if you modify it youll need to call save() again. flag The CommentFlag thats been attached to the comment. created True if this is a new ag; False if its a duplicate ag. request The HttpRequest that posted the comment.
476
Upgrading from Djangos previous comment system Prior versions of Django included an outdated, undocumented comment system. Users who reverse-engineered this framework will need to upgrade to use the new comment system; this guide explains how. The main changes from the old system are: This new system is documented. It uses modern Django features like forms and modelforms. It has a single Comment model instead of separate FreeComment and Comment models. Comments have email and URL elds. No ratings, photos and karma. This should only effect World Online. The {% comment_form %} tag no longer exists. Instead, theres now two functions: {% get_comment_form %}, which returns a form for posting a new comment, and {% render_comment_form %}, which renders said form using the comments/form.html template. The way comments are include in your URLconf have changed; youll need to replace:
(r^comments/, include(django.contrib.comments.urls.comments)),
with:
(r^comments/, include(django.contrib.comments.urls)),
Upgrading data
The data models for Djangos comment system have changed, as have the table names. Before you transfer your existing data into the new comments system, make sure that you have installed the new comments system as explained in the quick start guide. This will ensure that the new tables have been properly created. To transfer your data into the new comments system, youll need to directly run the following SQL:
BEGIN; INSERT INTO django_comments (content_type_id, object_pk, site_id, user_name, user_email, user_url, comment, submit_date, ip_address, is_public, is_removed) SELECT content_type_id, object_id, site_id, person_name, , , comment, submit_date, ip_address, is_public, not approved FROM comments_freecomment; INSERT INTO django_comments (content_type_id, object_pk, site_id, user_id, user_name, user_email, user_url, comment, submit_date, ip_address, is_public, is_removed) SELECT content_type_id, object_id, site_id, user_id, , , , comment, submit_date, ip_address, is_public, is_removed FROM comments_comment; UPDATE django_comments SET user_name = ( SELECT username FROM auth_user WHERE django_comments.user_id = auth_user.id
477
) WHERE django_comments.user_id is not NULL; UPDATE django_comments SET user_email = ( SELECT email FROM auth_user WHERE django_comments.user_id = auth_user.id ) WHERE django_comments.user_id is not NULL; COMMIT;
Customizing the comments framework If the built-in comment framework doesnt quite t your needs, you can extend the comment apps behavior to add custom data and logic. The comments framework lets you extend the built-in comment model, the built-in comment form, and the various comment views. The COMMENTS_APP setting is where this customization begins. Set COMMENTS_APP to the name of the app youd like to use to provide custom behavior. Youll use the same syntax as youd use for INSTALLED_APPS, and the app given must also be in the INSTALLED_APPS list. For example, if you wanted to use an app named my_comment_app, your settings le would contain:
INSTALLED_APPS = [ ... my_comment_app, ... ] COMMENTS_APP = my_comment_app
The app named in COMMENTS_APP provides its custom behavior by dening some module-level functions in the apps __init__.py. The complete list of these functions can be found below, but rst lets look at a quick example.
478
from django.db import models from django.contrib.comments.models import Comment class CommentWithTitle(Comment): title = models.CharField(max_length=300)
Most custom comment models will subclass the Comment model. However, if you want to substantially remove or change the elds available in the Comment model, but dont want to rewrite the templates, you could try subclassing from BaseCommentAbstractModel. Next, well dene a custom comment form in forms.py. This is a little more tricky: we have to both create a form and override CommentForm.get_comment_model() and CommentForm.get_comment_create_data() to return deal with our custom title eld:
from django import forms from django.contrib.comments.forms import CommentForm from my_comment_app.models import CommentWithTitle class CommentFormWithTitle(CommentForm): title = forms.CharField(max_length=300) def get_comment_model(self): # Use our custom comment model instead of the built-in one. return CommentWithTitle def get_comment_create_data(self): # Use the data of the superclass, and add in the title field data = super(CommentFormWithTitle, self).get_comment_create_data() data[title] = self.cleaned_data[title] return data
Django provides a couple of helper classes to make writing certain types of custom comment forms easier; see django.contrib.comments.forms for more. Finally, well dene a couple of methods in my_custom_app/__init__.py to point Django at these classes weve created:
from my_comments_app.models import CommentWithTitle from my_comments_app.forms import CommentFormWithTitle def get_model(): return CommentWithTitle def get_form(): return CommentFormWithTitle
The above process should take care of most common situations. For more advanced usage, there are additional methods you can dene. Those are explained in the next section.
479
django.contrib.comments.models.BaseCommentAbstractModel, which denes necessary core elds. The default implementation returns django.contrib.comments.models.Comment. get_form() Return the Form class you want to use for creating, validating, and saving your comment model. Your custom comment form should accept an additional rst argument, target_object, which is the object the comment will be attached to. The default implementation returns django.contrib.comments.forms.CommentForm. Note: The default comment form also includes a number of unobtrusive spam-prevention features (see Notes on the comment form). If replacing it with your own form, you may want to look at the source code for the built-in form and consider incorporating similar features. get_form_target() Return the URL for POSTing comments. This will be the <form action> attribute when rendering your comment form. The default implementation returns a reverse-resolved URL pointing to the post_comment() view. Note: If you provide a custom comment model and/or form, but you want to use the default post_comment() view, you will need to be aware that it requires the model and form to have certain additional attributes and methods: see the post_comment() view documentation for details. get_flag_url() Return the URL for the ag this comment view. The default implementation returns a reverse-resolved URL django.contrib.comments.views.moderation.flag() view. get_delete_url() Return the URL for the delete this comment view. The default implementation returns a reverse-resolved URL django.contrib.comments.views.moderation.delete() view. get_approve_url() Return the URL for the approve this comment from moderation view. The default implementation returns a reverse-resolved URL django.contrib.comments.views.moderation.approve() view. Comment form classes The django.contrib.comments.forms module contains a handful of forms youll use when writing custom views dealing with comments, or when writing custom comment apps. class CommentForm() The main comment form representing the standard, built-in way of handling submitted comments. This is the class used by all the views django.contrib.comments to handle submitted comments. If you want to build custom views that are similar to Djangos built-in comment handling views, youll probably want to use this form. pointing to the pointing to the pointing to the
CommentForm is actually composed of a couple of abstract base class forms that you can subclass to reuse pieces of the form handling logic: class CommentSecurityForm() Handles the anti-spoong protection aspects of the comment form handling. This class contains the content_type and object_pk elds pointing to the object the comment is attached to, along with a timestamp and a security_hash of all the form data. Together, the timestamp and the security hash ensure that spammers cant replay form submissions and ood you with comments. class CommentDetailsForm() Handles the details of the comment itself. This class contains the name, email, url, and the comment eld itself, along with the associated validation logic. Generic comment moderation Djangos bundled comments application is extremely useful on its own, but the amount of comment spam circulating on the Web today essentially makes it necessary to have some sort of automatic moderation system in place for any application which makes use of comments. To make this easier to handle in a consistent fashion, django.contrib.comments.moderation provides a generic, extensible comment-moderation system which can be applied to any model or set of models which want to make use of Djangos comment system.
Overview
The entire system is contained within django.contrib.comments.moderation, and uses a two-step process to enable moderation for any given model: 1. A subclass of CommentModerator is dened which species the moderation options the model wants to enable. 2. The model is registered with the moderation system, passing in the model class and the class which species its moderation options. A simple example is the best illustration of this. Suppose we have the following model, which would represent entries in a weblog:
from django.db import models class Entry(models.Model): title = models.CharField(maxlength=250) body = models.TextField() pub_date = models.DateTimeField() enable_comments = models.BooleanField()
Now, suppose that we want the following steps to be applied whenever a new comment is posted on an Entry: 1. If the Entrys enable_comments eld is False, the comment will simply be disallowed (i.e., immediately deleted). 2. If the enable_comments eld is True, the comment will be allowed to save. 3. Once the comment is saved, an email should be sent to site staff notifying them of the new comment. Accomplishing this is fairly straightforward and requires very little code:
481
from django.contrib.comments.moderation import CommentModerator, moderator class EntryModerator(CommentModerator): email_notification = True enable_field = enable_comments moderator.register(Entry, EntryModerator)
The CommentModerator class pre-denes a number of useful moderation options which subclasses can enable or disable as desired, and moderator knows how to work with them to determine whether to allow a comment, whether to moderate a comment which will be allowed to post, and whether to email notications of new comments. Built-in moderation options class CommentModerator() Most common comment-moderation needs can be handled by subclassing CommentModerator and changing the values of pre-dened attributes; the full range of built-in options is as follows. auto_close_field If this is set to the name of a DateField or DateTimeField on the model for which comments are being moderated, new comments for objects of that model will be disallowed (immediately deleted) when a certain number of days have passed after the date specied in that eld. Must be used in conjunction with close_after, which species the number of days past which comments should be disallowed. Default value is None. auto_moderate_field Like auto_close_field, but instead of outright deleting new comments when the requisite number of days have elapsed, it will simply set the is_public eld of new comments to False before saving them. Must be used in conjunction with moderate_after, which species the number of days past which comments should be moderated. Default value is None. close_after If auto_close_field is used, this must specify the number of days past the value of the eld specied by auto_close_field after which new comments for an object should be disallowed. Default value is None. email_notification If True, any new comment on an object of this model which survives moderation (i.e., is not deleted) will generate an email to site staff. Default value is False. enable_field If this is set to the name of a BooleanField on the model for which comments are being moderated, new comments on objects of that model will be disallowed (immediately deleted) whenever the value of that eld is False on the object the comment would be attached to. Default value is None. moderate_after If auto_moderate_field is used, this must specify the number of days past the value of the eld specied by auto_moderate_field after which new comments for an object should be marked nonpublic. Default value is None. Simply subclassing CommentModerator and changing the values of these options will automatically enable the various moderation methods for any models registered using the subclass. Adding custom moderation methods For situations where the built-in options listed above are not sufcient, subclasses of CommentModerator can also override the methods which actually perform the moderation, and apply any logic they desire. CommentModerator denes three methods which determine how moderation will take place;
482
each method will be called by the moderation system and passed two arguments: comment, which is the new comment being posted, content_object, which is the object the comment will be attached to, and request, which is the HttpRequest in which the comment is being submitted: allow(comment, content_object, request) Should return True if the comment should be allowed to post on the content object, and False otherwise (in which case the comment will be immediately deleted). email(comment, content_object, request) If email notication of the new comment should be sent to site staff or moderators, this method is responsible for sending the email. moderate(comment, content_object, request) Should return True if the comment should be moderated (in which case its is_public eld will be set to False before saving), and False otherwise (in which case the is_public eld will not be changed). Registering models for moderation The moderation system, represented by django.contrib.comments.moderation.moderator is an instance of the class Moderator, which allows registration and unregistration of models via two methods: register(model_or_iterable, moderation_class) Takes two arguments: the rst should be either a model class or list of model classes, and the second should be a subclass of CommentModerator, and register the model or models to be moderated using the options dened in the CommentModerator subclass. If any of the models are already registered for moderation, the exception AlreadyModerated will be raised. unregister(model_or_iterable) Takes one argument: a model class or list of model classes, and removes the model or models from the set of models which are being moderated. If any of the models are not currently being moderated, the exception NotModerated will be raised. Customizing the moderation system Most use cases will work easily with simple subclassing of CommentModerator and registration with the provided Moderator instance, but customization of global moderation behavior can be achieved by subclassing Moderator and instead registering models with an instance of the subclass. class Moderator() In addition to the Moderator.register() and Moderator.unregister() methods detailed above, the following methods on Moderator can be overridden to achieve customized behavior: connect() Determines how moderation is set up globally. The base implementation in Moderator does this by attaching listeners to the comment_will_be_posted and comment_was_posted signals from the comment models. pre_save_moderation(sender, comment, request, **kwargs) In the base implementation, applies all pre-save moderation steps (such as determining whether the comment needs to be deleted, or whether it needs to be marked as non-public or generate an email). post_save_moderation(sender, comment, request, **kwargs) In the base implementation, applies all post-save moderation steps (currently this consists entirely of deleting comments which were disallowed). Example of using the in-built comments app Follow the rst three steps of the quick start guide in the documentation.
483
Now suppose, you have an app (blog) with a model (Post) to which you want to attach comments. Let us also suppose that you have a template called blog_detail.html where you want to display the comments list and comment form.
Template
First, we should load the comment template tags in the blog_detail.html so that we can use its functionality. So just like all other custom template tag libraries:
{% load comments %}
Next, let us add the number of comments attached to the particular model instance of Post. For this we assume that a context variable object_pk is present which gives the id of the instance of Post. The usage of the get_comment_count tag is like below:
{% get_comment_count for blog.post object_pk as comment_count %} <p>{{ comment_count }} comments have been posted.</p>
If you have the instance (say entry) of the model (Post) available in the context, then you can refer to it directly:
{% get_comment_count for entry as comment_count %} <p>{{ comment_count }} comments have been posted.</p>
New in version 1.2: Please, see the release notes Next, we can use the render_comment_list tag, to render all comments to the given instance (entry) by using the comments/list.html template. {% render_comment_list for entry %} Django will will look for the list.html under the following directories (for our example):
comments/blog/post/list.html comments/blog/list.html comments/list.html
To get a list of comments, we make use of the get_comment_list tag. This tags usage is very similar to the get_comment_count tag. We need to remember that the get_comment_list returns a list of comments and hence we will have to iterate through them to display them:
{% get_comment_list for blog.post object_pk as comment_list %} {% for comment in comment_list %} <p>Posted by: {{ comment.user_name }} on {{ comment.submit_date }}</p> ... <p>Comment: {{ comment.comment }}</p> ... {% endfor %}
Finally, we display the comment form, enabling users to enter their comments. There are two ways of doing so. The rst is when you want to display the comments template available under your comments/form.html. The other method gives you a chance to customize the form. The rst method makes use of the render_comment_form tag. Its usage too is similar to the other three tags we have discussed above:
{% render_comment_form for entry %}
484
It looks for the form.html under the following directories (for our example):
comments/blog/post/form.html comments/blog/form.html comments/form.html
Since we customize the form in the second method, we make use of another tag called comment_form_target. This tag on rendering gives the URL where the comment form is posted. Without any customization, comment_form_target evaluates to /comments/post/. We use this tag in the forms action attribute. The get_comment_form tag renders a form for a model instance by creating a context variable. One can iterate over the form object to get individual elds. This gives you ne-grain control over the form:
{% for field in form %} {% ifequal field.name "comment" %} <!-- Customize the "comment" field, say, make CSS changes --> ... {% endfor %}
Flagging
If you want your users to be able to ag comments (say for profanity), you can just direct them (by placing a link in your comment list) to /flag/{{ comment.id }}/. Similarly, a user with requisite permissions ("Can moderate comments") can approve and delete comments. This can also be done through the admin as youll see later. You might also want to customize the following templates: flag.html flagged.html approve.html approved.html delete.html deleted.html found under the directory structure we saw for form.html.
485
Feeds
Suppose you want to export a feed of the latest comments, you can use the in-built LatestCommentFeed. Just enable it in your projects urls.py:
from django.conf.urls.defaults import * from django.contrib.comments.feeds import LatestCommentFeed feeds = { latest: LatestCommentFeed, } urlpatterns = patterns(, # ... (r^feeds/(?P<url>.*)/$, django.contrib.syndication.views.feed, {feed_dict: feeds}), # ... )
Now you should have the latest comment feeds being served off /feeds/latest/.
Moderation
Now that we have the comments framework working, we might want to have some moderation setup to administer the comments. The comments framework comes in-built with generic comment moderation. The comment moderation has the following features (all of which or only certain can be enabled): Enable comments for a particular model instance. Close comments after a particular (user-dened) number of days. Email new comments to the site-staff. To enable comment moderation, we subclass the CommentModerator and register it with the moderation features we want. Let us suppose we want to close comments after 7 days of posting and also send out an email to the site staff. In blog/models.py, we register a comment moderator in the following way:
from django.contrib.comments.moderation import CommentModerator, moderator from django.db import models class Post(models.Model): title = models.CharField(max_length = 255) content = models.TextField() posted_date = models.DateTimeField() class PostModerator(CommentModerator): email_notification = True auto_close_field = posted_date # Close the comments after 7 days. close_after = 7 moderator.register(Post, PostModerator)
The generic comment moderation also has the facility to remove comments. These comments can then be moderated by any user who has access to the admin site and the Can moderate comments permission (can be set under the Users page in the admin).
486
The moderator can Flag, Approve or Remove comments using the Action drop-down in the admin under the Comments page. Note: Only a super-user will be able to delete comments from the database. Remove Comments only sets the is_public attribute to False.
49.4.1 Overview
At the heart of the contenttypes application is the ContentType model, which lives at django.contrib.contenttypes.models.ContentType. Instances of ContentType represent and store information about the models installed in your project, and new instances of ContentType are automatically created whenever new models are installed. Instances of ContentType have methods for returning the model classes they represent and for querying objects from those models. ContentType also has a custom manager that adds methods for working with ContentType and for obtaining instances of ContentType for a particular model. Relations between your models and ContentType can also be used to enable generic relationships between an instance of one of your models and instances of any model you have installed.
487
name The human-readable name of the model. This is taken from the verbose_name attribute of the model. Lets look at an example to see how this works. If you already have the contenttypes application installed, and then add the sites application to your INSTALLED_APPS setting and run manage.py syncdb to install it, the model django.contrib.sites.models.Site will be installed into your database. Along with it a new instance of ContentType will be created with the following values: app_label will be set to sites (the last part of the Python path django.contrib.sites). model will be set to site. name will be set to site.
And then use it to query for a particular User, or to get access to the User model class:
>>> user_type.model_class() <class django.contrib.auth.models.User> >>> user_type.get_object_for_this_type(username=Guido) <User: Guido>
Together, get_object_for_this_type() and model_class() enable two extremely important use cases: 1. Using these methods, you can write high-level generic code that performs queries on any installed model instead of importing and using a single specic model class, you can pass an app_label and model into a ContentType lookup at runtime, and then work with the model class or retrieve objects from it. 2. You can relate another model to ContentType as a way of tying instances of it to particular model classes, and use these methods to get access to those model classes. Several of Djangos bundled applications make use of the latter technique. For example, the permissions system in Djangos authentication framework uses a Permission model with a foreign key to ContentType; this lets Permission represent concepts like can add blog entry or can delete news story. The ContentTypeManager class ContentTypeManager() ContentType also has a custom manager, ContentTypeManager, which adds the following methods:
488
clear_cache() Clears an internal cache used by ContentType to keep track of which models for which it has created django.contrib.contenttypes.models.ContentType instances. You probably wont ever need to call this method yourself; Django will call it automatically when its needed. get_for_model(model) Takes either a model class or an instance of a model, and returns the ContentType instance representing that model. The get_for_model() method is especially useful when you know you need to work with a ContentType but dont want to go to the trouble of obtaining the models metadata to perform a manual lookup:
>>> from django.contrib.auth.models import User >>> user_type = ContentType.objects.get_for_model(User) >>> user_type <ContentType: user>
A normal ForeignKey can only point to one other model, which means that if the TaggedItem model used a ForeignKey it would have to choose one and only one model to store tags for. The contenttypes application provides a special eld type django.contrib.contenttypes.generic.GenericForeignKey which works around this and allows the relationship to be with any model. There are three parts to setting up a GenericForeignKey: 1. Give your model a ForeignKey to ContentType. 2. Give your model a eld that can store a primary-key value from the models youll be relating to. (For most models, this means an IntegerField or PositiveIntegerField.) This eld must be of the same type as the primary key of the models that will be involved in the generic relation. For example, if you use IntegerField, you wont be able to form a generic relation with a model that uses a CharField as a primary key. 3. Give your model a GenericForeignKey, and pass it the names of the two elds described above. If these elds are named content_type and object_id, you can omit this those are the default eld names GenericForeignKey will look for.
489
This will enable an API similar to the one used for a normal ForeignKey; each TaggedItem will have a content_object eld that returns the object its related to, and you can also assign to that eld or use it when creating a TaggedItem:
>>> from django.contrib.auth.models import User >>> guido = User.objects.get(username=Guido) >>> t = TaggedItem(content_object=guido, tag=bdfl) >>> t.save() >>> t.content_object <User: Guido>
Due to the way GenericForeignKey is implemented, you cannot use such elds directly with lters (filter() and exclude(), for example) via the database API. They arent normal eld objects. These examples will not work:
# This will fail >>> TaggedItem.objects.filter(content_object=guido) # This will also fail >>> TaggedItem.objects.get(content_object=guido)
Reverse generic relations If you know which models youll be using most often, you can also add a reverse generic relationship to enable an additional API. For example:
class Bookmark(models.Model): url = models.URLField() tags = generic.GenericRelation(TaggedItem)
Bookmark instances will each have a tags attribute, which can be used to retrieve their associated TaggedItems:
>>> b = Bookmark(url=http://www.djangoproject.com/) >>> b.save() >>> t1 = TaggedItem(content_object=b, tag=django) >>> t1.save() >>> t2 = TaggedItem(content_object=b, tag=python) >>> t2.save() >>> b.tags.all() [<TaggedItem: django>, <TaggedItem: python>]
Just as django.contrib.contenttypes.generic.GenericForeignKey accepts the names of the content-type and object-ID elds as arguments, so too does GenericRelation; if the model which has the generic foreign key is using non-default names for those elds, you must pass the names of the elds when setting up a GenericRelation to it. For example, if the TaggedItem model referred to above used elds named content_type_fk and object_primary_key to create its generic foreign key, then a GenericRelation back to it would need to be dened like so:
Of course, if you dont add the reverse relationship, you can do the same types of lookups manually:
>>> b = Bookmark.objects.get(url=http://www.djangoproject.com/) >>> bookmark_type = ContentType.objects.get_for_model(b) >>> TaggedItem.objects.filter(content_type__pk=bookmark_type.id, ... object_id=b.id) [<TaggedItem: django>, <TaggedItem: python>]
490
Note that if the model with a GenericForeignKey that youre referring to uses a non-default value for ct_field or fk_field (e.g. the django.contrib.comments app uses ct_field="object_pk"), youll need to pass content_type_field and object_id_field to GenericRelation.:
Note that if you delete an object that has a GenericRelation, any objects which have a GenericForeignKey pointing at it will be deleted as well. In the example above, this means that if a Bookmark object were deleted, any TaggedItem objects pointing at it would be deleted at the same time. Generic relations and aggregation Djangos database aggregation API doesnt work with a GenericRelation. For example, you might be tempted to try something like:
Bookmark.objects.aggregate(Count(tags))
This will not work correctly, however. The generic relation adds extra lters to the queryset to ensure the correct content type, but the aggregate method doesnt take them into account. For now, if you need aggregates on generic relations, youll need to calculate them without using the aggregation API. Generic relations in forms and admin django.contrib.contenttypes.generic provides both a GenericInlineFormSet and GenericInlineModelAdmin. This enables the use of generic relations in forms and the admin. See the model formset and admin documentation for more information. class GenericInlineModelAdmin() The GenericInlineModelAdmin class inherits all properties from an InlineModelAdmin class. However, it adds a couple of its own for working with the generic relation: ct_field The name of the ContentType foreign key eld on the model. Defaults to content_type. ct_fk_field The name of the integer eld that represents the ID of the related object. Defaults to object_id.
491
This should not be done for POST forms that target external URLs, since that would cause the CSRF token to be leaked, leading to a vulnerability. 3. In the corresponding view functions, ensure that the django.core.context_processors.csrf context processor is being used. Usually, this can be done in one of two ways: (a) Use RequestContext, which always uses django.core.context_processors.csrf (no matter what your TEMPLATE_CONTEXT_PROCESSORS setting). If you are using generic views or contrib apps, you are covered already, since these apps use RequestContext throughout. (b) Manually import and use the processor to generate the CSRF token and add it to the template context. e.g.:
from django.core.context_processors import csrf from django.shortcuts import render_to_response def my_view(request): c = {} c.update(csrf(request)) # ... view code here return render_to_response("a_template.html", c)
You may want to write your own render_to_response wrapper that takes care of this step for you. The utility script extras/csrf_migration_helper.py can help to automate the nding of code and templates that may need to be upgraded. It contains full help on how to use it. The decorator method Rather than adding CsrfViewMiddleware as a blanket protection, you can use the csrf_protect decorator, which has exactly the same functionality, on particular views that need the protection. It must be used both on views that insert the CSRF token in the output, and on those that accept the POST form data. (These are often the same view function, but not always). It is used like this:
from django.views.decorators.csrf import csrf_protect from django.template import RequestContext @csrf_protect def my_view(request): c = {} # ...
492
Use of the decorator is not recommended by itself, since if you forget to use it, you will have a security hole. The belt and braces strategy of using both is ne, and will incur minimal overhead. Legacy method In Django 1.1, the template tag did not exist. Instead, a post-processing middleware that re-wrote POST forms to include the CSRF token was used. If you are upgrading a site from version 1.1 or earlier, please read this section and the Upgrading notes below. The post-processing middleware is still available as CsrfResponseMiddleware, and it can be used by following these steps: 1. Follow step 1 above to install CsrfViewMiddleware. 2. Add django.middleware.csrf.CsrfResponseMiddleware to your MIDDLEWARE_CLASSES setting. CsrfResponseMiddleware needs to process the response before things like compression or setting ofETags happen to the response, so it must come after GZipMiddleware, CommonMiddleware and ConditionalGetMiddleware in the list. It also must come after CsrfViewMiddleware. Use of the CsrfResponseMiddleware is not recommended because of the performance hit it imposes, and because of a potential security problem (see below). It can be used as an interim measure until applications have been updated to use the csrf_token tag. It is deprecated and will be removed in Django 1.4. Django 1.1 and earlier provided a single CsrfMiddleware class. This is also still available for backwards compatibility. It combines the functions of the two middleware. Note also that previous versions of these classes depended on the sessions framework, but this dependency has now been removed, with backward compatibility support so that upgrading will not produce any issues.
493
You should update any imports, and also the paths in your MIDDLEWARE_CLASSES. If you have CsrfMiddleware in your MIDDLEWARE_CLASSES, you will now have a working installation with CSRF protection. It is recommended at this point that you replace CsrfMiddleware with its two components, CsrfViewMiddleware and CsrfResponseMiddleware (in that order). If you do not have any of the middleware in your MIDDLEWARE_CLASSES, you will have a working installation but without any CSRF protection for your views (just as you had before). It is strongly recommended to install CsrfViewMiddleware and CsrfResponseMiddleware, as described above. Note that contrib apps, such as the admin, have been updated to use the csrf_protect decorator, so that they are secured even if you do not add the CsrfViewMiddleware to your settings. However, if you have supplied customised templates to any of the view functions of contrib apps (whether explicitly via a keyword argument, or by overriding built-in templates), you MUST update them to include the csrf_token template tag as described above, or they will stop working. (If you cannot update these templates for some reason, you will be forced to use CsrfResponseMiddleware for these views to continue working). Note also, if you are using the comments app, and you are not going to add CsrfViewMiddleware to your settings (not recommended), you will need to add the csrf_protect decorator to any views that include the comment forms and target the comment views (usually using the comment_form_target template tag). Assuming you have followed the above, all views in your Django site will now be protected by the CsrfViewMiddleware. Contrib apps meet the requirements imposed by the CsrfViewMiddleware using the template tag, and other applications in your project will meet its requirements by virtue of the CsrfResponseMiddleware. The next step is to update all your applications to use the template tag, as described in How to use it, steps 2-3. This can be done as soon as is practical. Any applications that are updated will now require Django 1.1.2 or later, since they will use the CSRF template tag which was not available in earlier versions. (The template tag in 1.1.2 is actually a no-op that exists solely to ease the transition to 1.2 it allows apps to be created that have CSRF protection under 1.2 without requiring users of the apps to upgrade to the Django 1.2.X series). The utility script extras/csrf_migration_helper.py can help to automate the nding of code and templates that may need to be upgraded. It contains full help on how to use it. Finally, once all applications are upgraded, CsrfResponseMiddleware can be removed from your settings. While CsrfResponseMiddleware is still in use, the csrf_response_exempt decorator, described in Exceptions, may be useful. The post-processing middleware imposes a performance hit and a potential vulnerability, and any views that have been upgraded to use the new template tag method no longer need it. Exceptions New in version 1.1: Please, see the release notesChanged in version 1.2: Import paths for the decorators below were changed. To manually exclude a view function from being handled by either of the two CSRF middleware, you can use the csrf_exempt decorator, found in the django.views.decorators.csrf module. For example:
from django.views.decorators.csrf import csrf_exempt @csrf_exempt
494
Like the middleware, the csrf_exempt decorator is composed of two parts: a csrf_view_exempt decorator and a csrf_response_exempt decorator, found in the same module. These disable the view protection mechanism (CsrfViewMiddleware) and the response post-processing (CsrfResponseMiddleware) respectively. They can be used individually if required. You dont have to worry about doing this for most AJAX views. Any request sent with X-Requested-With: XMLHttpRequest is automatically exempt. (See the How it works section.) Subdomains By default, CSRF cookies are specic to the subdomain they are set for. This means that a form served from one subdomain (e.g. server1.example.com) will not be able to have a target on another subdomain (e.g. server2.example.com). This restriction can be removed by setting CSRF_COOKIE_DOMAIN to be something like ".example.com". Please note that, with or without use of this setting, this CSRF protection mechanism is not safe against crosssubdomain attacks see Limitations.
where reason is a short message (intended for developers or logging, not for end users) indicating the reason the request was rejected.
3. For all incoming POST requests, a CSRF cookie must be present, and the csrfmiddlewaretoken eld must be present and correct. If it isnt, the user will get a 403 error. This check is done by CsrfViewMiddleware. 49.5. Cross Site Request Forgery protection 495
4. In addition, for HTTPS requests, strict referer checking is done by CsrfViewMiddleware. This is necessary to address a Man-In-The-Middle attack that is possible under HTTPS when using a session independent nonce, due to the fact that HTTP Set-Cookie headers are (unfortunately) accepted by clients that are talking to a site under HTTPS. (Referer checking is not done for HTTP requests because the presence of the Referer header is not reliable enough under HTTP.) This ensures that only forms that have originated from your Web site can be used to POST data back. It deliberately only targets HTTP POST requests (and the corresponding POST forms). GET requests ought never to have any potentially dangerous side effects (see 9.1.1 Safe Methods, HTTP 1.1, RFC 2616), and so a CSRF attack with a GET request ought to be harmless. CsrfResponseMiddleware checks the Content-Type before modifying the response, and only pages that are served as text/html or application/xml+xhtml are modied. AJAX The middleware tries to be smart about requests that come in via AJAX. Most modern JavaScript toolkits send an X-Requested-With: XMLHttpRequest HTTP header; these requests are detected and automatically not handled by this middleware. We can do this safely because, in the context of a browser, the header can only be added by using XMLHttpRequest, and browsers already implement a same-domain policy for XMLHttpRequest. For the more recent browsers that relax this same-domain policy, custom headers like X-Requested-With are only allowed after the browser has done a preight check to the server to see if the cross-domain request is allowed, using a strictly opt in mechanism, so the exception for AJAX is still safeif the developer has specically opted in to allowing cross-site AJAX POST requests on a specic URL, they obviously dont want the middleware to disallow exactly that.
49.5.4 Caching
If the csrf_token template tag is used by a template (or the get_token function is called some other way), CsrfViewMiddleware will add a cookie and a Vary: Cookie header to the response. Similarly, CsrfResponseMiddleware will send the Vary: Cookie header if it inserted a token. This means that these middleware will play well with the cache middleware if it is used as instructed (UpdateCacheMiddleware goes before all other middleware). However, if you use cache decorators on individual views, the CSRF middleware will not yet have been able to set the Vary header. In this case, on any views that will require a CSRF token to be inserted you should use the django.views.decorators.vary.vary_on_cookie() decorator rst:
from django.views.decorators.cache import cache_page from django.views.decorators.vary import vary_on_cookie @cache_page(60 * 15) @vary_on_cookie def my_view(request): # ...
49.5.5 Testing
The CsrfViewMiddleware will usually be a big hindrance to testing view functions, due to the need for the CSRF token which must be sent with every POST request. For this reason, Djangos HTTP client for tests has been modied to set a ag on requests which relaxes the middleware and the csrf_protect decorator so that they no longer rejects requests. In every other respect (e.g. sending cookies etc.), they behave the same.
496
49.5.6 Limitations
Subdomains within a site will be able to set cookies on the client for the whole domain. By setting the cookie and using a corresponding token, subdomains will be able to circumvent the CSRF protection. The only way to avoid this is to ensure that subdomains are controlled by trusted users (or, are at least unable to set cookies). Note that even without CSRF, there are other vulnerabilities, such as session xation, that make giving subdomains to untrusted parties a bad idea, and these vulnerabilities cannot easily be xed with current browsers. If you are using CsrfResponseMiddleware and your app creates HTML pages and forms in some unusual way, (e.g. it sends fragments of HTML in JavaScript document.write statements) you might bypass the lter that adds the hidden eld to the form, in which case form submission will always fail. You should use the template tag or django.middleware.csrf.get_token() to get the CSRF token and ensure it is included when your form is submitted.
49.6 Databrowse
Databrowse is a Django application that lets you browse your data. As the Django admin dynamically creates an admin interface by introspecting your models, Databrowse dynamically creates a rich, browsable Web site by introspecting your models. Note Databrowse is very new and is currently under active development. It may change substantially before the next Django release. With that said, its easy to use, and it doesnt require writing any code. So you can play around with it today, with very little investment in time or coding.
49.6. Databrowse
497
Note that you should register the model classes, not instances. It doesnt matter where you put this, as long as it gets executed at some point. A good place for it is in your URLconf le (urls.py). 3. Change your URLconf to import the databrowse module:
from django.contrib import databrowse
The prex doesnt matter you can use databrowse/ or db/ or whatever youd like. 4. Run the Django server and visit /databrowse/ in your browser.
view
is
decorated
with
If you havent already added support for user logins to your URLconf , as described in the user authentication docs, then you will need to do so now with the following mapping:
(r^accounts/login/$, django.contrib.auth.views.login),
The nal step is to create the login form required by django.contrib.auth.views.login(). The user authentication docs provide full details and a sample template that can be used for this purpose.
498
49.7.1 Installation
To install the atpages app, follow these steps: 1. Install the sites framework by adding django.contrib.sites to your INSTALLED_APPS setting, if its not already in there. Also make sure youve correctly set SITE_ID to the ID of the site the settings le represents. This will usually be 1 (i.e. SITE_ID = 1, but if youre using the sites framework to manage multiple sites, it could be the ID of a different site. 2. Add django.contrib.flatpages to your INSTALLED_APPS setting. 3. Add django.contrib.flatpages.middleware.FlatpageFallbackMiddleware to your MIDDLEWARE_CLASSES setting. 4. Run the command manage.py syncdb.
It passes that template a single context variable, flatpage, which is the atpage object. RequestContext in rendering the template. If it doesnt nd a match, the request continues to be processed as usual. The middleware only gets activated for 404s not for 500s or responses of any other status code. Flatpages will not apply view middleware
Because the FlatpageFallbackMiddleware is applied only after URL resolution has failed and produced a 404, the response it returns will not apply any view middleware methods. Only requests which are successfully routed to a view via normal URL resolution apply view middleware. Note that the order of MIDDLEWARE_CLASSES matters. Generally, FlatpageFallbackMiddleware at the end of the list, because its a last resort. For more on middleware, read the middleware docs. Ensure that your 404 template works Note that the FlatpageFallbackMiddleware only steps in once another view has successfully produced a 404 response. If another view or middleware class attempts to produce a 404 but ends up raising an exception instead (such as a TemplateDoesNotExist exception if your site does not have an appropriate template to use for HTTP 404 responses), the response will become an HTTP 500 (Internal Server Error) and the FlatpageFallbackMiddleware will not attempt to serve a at page. you can put
499
Since youre already entering raw HTML into the admin page for a atpage, both flatpage.title and flatpage.content are marked as not requiring automatic HTML escaping in the template.
49.8 django.contrib.formtools
A set of high-level abstractions for Django forms (django.forms).
500
Overview Given a django.forms.Form subclass that you dene, this application takes care of the following workow: 1. Displays the form as HTML on a Web page. 2. Validates the form data when its submitted via POST. a. If its valid, displays a preview page. b. If its not valid, redisplays the form with error messages. 3. When the conrmation form is submitted from the preview page, calls a hook that you dene a done() method that gets passed the valid data. The framework enforces the required preview by passing a shared-secret hash to the preview page via hidden form elds. If somebody tweaks the form parameters on the preview page, the form submission will fail the hashcomparison test. How to use FormPreview 1. Point Django at the default FormPreview templates. There are two ways to do this: Add django.contrib.formtools to your INSTALLED_APPS setting. This will work if your TEMPLATE_LOADERS setting includes the app_directories template loader (which is the case by default). See the template loader docs for more. Otherwise, determine the full lesystem path to the django/contrib/formtools/templates directory, and add that directory to your TEMPLATE_DIRS setting. 2. Create a FormPreview subclass that overrides the done() method:
from django.contrib.formtools.preview import FormPreview from myapp.models import SomeModel class SomeModelFormPreview(FormPreview): def done(self, request, cleaned_data): # Do something with the cleaned_data, then redirect # to a "success" page. return HttpResponseRedirect(/form/success)
This method takes an HttpRequest object and a dictionary of the form data after it has been validated and cleaned. It should return an HttpResponseRedirect that is the end result of the form being submitted. 3. Change your URLconf to point to an instance of your FormPreview subclass:
from myapp.preview import SomeModelFormPreview from myapp.forms import SomeModelForm from django import forms
...and add the following line to the appropriate model in your URLconf:
(r^post/$, SomeModelFormPreview(SomeModelForm)),
where SomeModelForm is a Form or ModelForm class for the model. 4. Run the Django server and visit /post/ in your browser.
49.8. django.contrib.formtools
501
FormPreview classes class FormPreview() A FormPreview class is a simple Python class that represents the preview workow. FormPreview classes must subclass django.contrib.formtools.preview.FormPreview and override the done() method. They can live anywhere in your codebase. FormPreview templates By default, the form is rendered via the template formtools/form.html, and the preview page is rendered via the template formtools/preview.html. These values can be overridden for a particular form preview by setting preview_template and form_template attributes on the FormPreview subclass. See django/contrib/formtools/templates for the default templates. Advanced FormPreview methods New in version 1.2: Please, see the release notes process_preview() Given a validated form, performs any extra processing before displaying the preview page, and saves any extra data in context. By default, this method is empty. It is called after the form is validated, but before the context is modied with hash information and rendered.
502
Usage This application handles as much machinery for you as possible. Generally, you just have to do these things: 1. Dene a number of Form classes one per wizard page. 2. Create a FormWizard class that species what to do once all of your forms have been submitted and validated. This also lets you override some of the wizards behavior. 3. Create some templates that render the forms. You can dene a single, generic template to handle every one of the forms, or you can dene a specic template for each form. 4. Point your URLconf at your FormWizard class. Dening Form classes The rst step in creating a form wizard is to create the Form classes. These should be standard django.forms.Form classes, covered in the forms documentation. These classes can live anywhere in your codebase, but convention is to put them in a le called forms.py in your application. For example, lets write a contact form wizard, where the rst pages form collects the senders e-mail address and subject, and the second page collects the message itself. Heres what the forms.py might look like:
from django import forms class ContactForm1(forms.Form): subject = forms.CharField(max_length=100) sender = forms.EmailField() class ContactForm2(forms.Form): message = forms.CharField(widget=forms.Textarea)
Important limitation: Because the wizard uses HTML hidden elds to store data between pages, you may not include a FileField in any form except the last one. Creating a FormWizard class The next step is to create a django.contrib.formtools.wizard.FormWizard subclass. As with your Form classes, this FormWizard class can live anywhere in your codebase, but convention is to put it in forms.py. The only requirement on this subclass is that it implement a done() method. done() This method species what should happen when the data for every form is submitted and validated. This method is passed two arguments: request an HttpRequest object form_list a list of Form classes In this simplistic example, rather than perform any database operation, the method simply renders a template of the validated data:
from django.shortcuts import render_to_response from django.contrib.formtools.wizard import FormWizard class ContactWizard(FormWizard): def done(self, request, form_list):
49.8. django.contrib.formtools
503
Note that this method will be called via POST, so it really ought to be a good Web citizen and redirect after processing the data. Heres another example:
from django.http import HttpResponseRedirect from django.contrib.formtools.wizard import FormWizard class ContactWizard(FormWizard): def done(self, request, form_list): do_something_with_the_form_data(form_list) return HttpResponseRedirect(/page-to-redirect-to-when-done/)
See the section Advanced FormWizard methods below to learn about more FormWizard hooks. Creating templates for the forms Next, youll need to create a template that renders the wizards forms. By default, every form uses a template called forms/wizard.html. (You can change this template name by overriding get_template(), which is documented below. This hook also allows you to use a different template for each form.) This template expects the following context: step_field The name of the hidden eld containing the step. step0 The current step (zero-based). step The current step (one-based). step_count The total number of steps. form The Form instance for the current step (either empty or with errors). previous_fields A string representing every previous data eld, plus hashes for completed forms, all in the form of hidden elds. Note that youll need to run this through the safe template lter, to prevent auto-escaping, because its raw HTML. You can supply extra context to this template in two ways: Set the extra_context attribute on your FormWizard subclass to a dictionary. Pass a dictionary as a parameter named extra_context to your wizards URL pattern in your URLconf. See Hooking the wizard into a URLconf . Heres a full example template:
{% extends "base.html" %} {% block content %} <p>Step {{ step }} of {{ step_count }}</p> <form action="." method="post">{% csrf_token %} <table> {{ form }} </table> <input type="hidden" name="{{ step_field }}" value="{{ step0 }}" /> {{ previous_fields|safe }} <input type="submit">
504
</form> {% endblock %}
Note that previous_fields, step_field and step0 are all required for the wizard to work properly. Hooking the wizard into a URLconf Finally, give your new FormWizard object a URL in urls.py. The wizard takes a list of your Form objects as arguments:
from django.conf.urls.defaults import * from mysite.testapp.forms import ContactForm1, ContactForm2, ContactWizard urlpatterns = patterns(, (r^contact/$, ContactWizard([ContactForm1, ContactForm2])), )
Advanced FormWizard methods class FormWizard() Aside from the done() method, FormWizard offers a few advanced method hooks that let you customize how your wizard works. Some of these methods take an argument step, which is a zero-based counter representing the current step of the wizard. (E.g., the rst form is 0 and the second form is 1.) prefix_for_step() Given the step, returns a form prex to use. By default, this simply uses the step itself. For more, see the form prex documentation. Default implementation:
def prefix_for_step(self, step): return str(step)
render_hash_failure() Renders a template if the hash check fails. Its rare that youd need to override this. Default implementation:
def render_hash_failure(self, request, step): return self.render(self.get_form(step), request, step, context={wizard_error: We apologize, but your form has expired. Please continue filling out the form from this page.})
security_hash() Calculates the security hash for the given request object and Form instance. By default, this uses an MD5 hash of the form data and your SECRET_KEY setting. Its rare that somebody would need to override this. Example:
def security_hash(self, request, form): return my_hash_function(request, form)
49.8. django.contrib.formtools
505
parse_params() A hook for saving state from the request object and args / kwargs that were captured from the URL by your URLconf. By default, this does nothing. Example:
def parse_params(self, request, *args, **kwargs): self.my_state = args[0]
get_template() Returns the name of the template that should be used for the given step. By default, this returns forms/wizard.html, regardless of step. Example:
def get_template(self, step): return myapp/wizard_%s.html % step
If get_template() returns a list of strings, then the wizard will use the template systems select_template() function. This means the system will use the rst template that exists on the lesystem. For example:
def get_template(self, step): return [myapp/wizard_%s.html % step, myapp/wizard.html]
render_template() Renders the template for the given step, returning an HttpResponse object. Override this method if you want to add a custom context, return a different MIME type, etc. If you only need to override the template name, use get_template() instead. The template will be rendered with the context documented in the Creating templates for the forms section above. process_step() Hook for modifying the wizards internal state, given a fully validated Form object. The Form is guaranteed to have clean, valid data. This method should not modify any of that data. Rather, it might want to set self.extra_context or dynamically alter self.form_list, based on previously submitted forms. Note that this method is called every time a page is rendered for all submitted steps. The function signature:
def process_step(self, request, form, step): # ...
49.9 GeoDjango
New in version 1.0: Please, see the release notes GeoDjango intends to be a world-class geographic web framework. Its goal is to make it as easy as possible to build GIS web applications and harness the power of spatially enabled data.
506
Note: This command must be issued by a database user that has permissions to create a database. Here is an example set of commands to create such a user:
$ sudo su - postgres $ createuser --createdb geo $ exit
Replace geo to correspond to the system login user name will be connecting to the database. For example, johndoe if that is the system user that will be running GeoDjango. Users of SQLite and SpatiaLite should consult the instructions on how to create a SpatiaLite database.
1 2
Special thanks to Bjrn Sandvik of thematicmapping.org for providing and maintaining this data set. GeoDjango basic apps was written by Dane Springmeyer, Josh Livni, and Christopher Schmidt.
49.9. GeoDjango
507
With the project initialized, now create a world Django application within the geodjango project:
$ cd geodjango $ python manage.py startapp world
Congure settings.py
The geodjango project settings are stored in the settings.py le. Edit the database connection settings appropriately:
DATABASES = { default: { ENGINE: django.contrib.gis.db.backends.postgis, NAME: geodjango, USER: geo, } }
Note: These database settings are for Django 1.2 and above. In addition, modify the INSTALLED_APPS setting to django.contrib.gis, and world (our newly created application):
INSTALLED_APPS = ( django.contrib.auth, django.contrib.contenttypes, django.contrib.sessions, django.contrib.sites, django.contrib.admin, django.contrib.gis, world )
include
django.contrib.admin,
Geographic Data
World Borders
The world borders data is available in this zip le. Create a data directory in the world application, download the world borders data, and unzip. On GNU/Linux platforms the following commands should do it:
$ $ $ $ $ mkdir world/data cd world/data wget http://thematicmapping.org/downloads/TM_WORLD_BORDERS-0.3.zip unzip TM_WORLD_BORDERS-0.3.zip cd ../..
508
The world borders ZIP le contains a set of data les collectively known as an ESRI Shapele, one of the most popular geospatial data formats. When unzipped the world borders data set includes les with the following extensions: .shp: Holds the vector data for the world borders geometries. .shx: Spatial index le for geometries stored in the .shp. .dbf: Database le for holding non-geometric attribute data (e.g., integer and character elds). .prj: Contains the spatial reference information for the geographic data stored in the shapele.
Here ogrinfo is telling us that the shapele has one layer, and that layer contains polygon data. To nd out more well specify the layer name and use the -so option to get only important summary information:
$ ogrinfo -so world/data/TM_WORLD_BORDERS-0.3.shp TM_WORLD_BORDERS-0.3 INFO: Open of world/data/TM_WORLD_BORDERS-0.3.shp using driver ESRI Shapefile successful. Layer name: TM_WORLD_BORDERS-0.3 Geometry: Polygon Feature Count: 246 Extent: (-180.000000, -90.000000) - (180.000000, 83.623596) Layer SRS WKT: GEOGCS["GCS_WGS_1984", DATUM["WGS_1984", SPHEROID["WGS_1984",6378137.0,298.257223563]], PRIMEM["Greenwich",0.0], UNIT["Degree",0.0174532925199433]] FIPS: String (2.0) ISO2: String (2.0) ISO3: String (3.0) UN: Integer (3.0) NAME: String (50.0) AREA: Integer (7.0) POP2005: Integer (10.0) REGION: Integer (3.0) SUBREGION: Integer (3.0) LON: Real (8.3) LAT: Real (7.3)
This detailed summary information tells us the number of features in the layer (246), the geographical extent, the spatial reference system (SRS WKT), as well as detailed information for each attribute eld. For example, FIPS: String (2.0) indicates that theres a FIPS character eld with a maximum length of 2; similarly, LON: Real (8.3) is a oating-point eld that holds a maximum of 8 digits up to three decimal places. Although this information may be found right on the world borders website, this shows you how to determine this information yourself when such metadata is not provided.
49.9. GeoDjango
509
Geographic Models
Two important things to note: 1. The models module is imported from django.contrib.gis.db. 2. The model overrides its default manager with GeoManager; this is required to perform spatial queries. When declaring a geometry eld on your model the default spatial reference system is WGS84 (meaning the SRID is 4326) in other words, the eld coordinates are in longitude/latitude pairs in units of degrees. If you want the coordinate system to be different, then SRID of the geometry eld may be customized by setting the srid with an integer corresponding to the coordinate system of your choice.
Run syncdb
After youve dened your model, it needs to be synced with the spatial database. First, lets look at the SQL that will generate the table for the WorldBorders model:
$ python manage.py sqlall world
510
BEGIN; CREATE TABLE "world_worldborders" ( "id" serial NOT NULL PRIMARY KEY, "name" varchar(50) NOT NULL, "area" integer NOT NULL, "pop2005" integer NOT NULL, "fips" varchar(2) NOT NULL, "iso2" varchar(2) NOT NULL, "iso3" varchar(3) NOT NULL, "un" integer NOT NULL, "region" integer NOT NULL, "subregion" integer NOT NULL, "lon" double precision NOT NULL, "lat" double precision NOT NULL ) ; SELECT AddGeometryColumn(world_worldborders, mpoly, 4326, MULTIPOLYGON, 2); ALTER TABLE "world_worldborders" ALTER "mpoly" SET NOT NULL; CREATE INDEX "world_worldborders_mpoly_id" ON "world_worldborders" USING GIST ( "mpoly" GIST_GEOMETRY COMMIT;
If satised, you may then create this table in the database by running the syncdb management command:
$ python manage.py syncdb Creating table world_worldborders Installing custom SQL for world.WorldBorders model
The syncdb command may also prompt you to create an admin user; go ahead and do so (not required now, may be done at any point in the future using the createsuperuser management command). Importing Spatial Data This section will show you how to take the data from the world borders shapele and import it into GeoDjango models using the LayerMapping data import utility. There are many different different ways to import data in to a spatial database besides the tools included within GeoDjango, you may also use the following to populate your spatial database: ogr2ogr: Command-line utility, included with GDAL, that supports loading a multitude of vector data formats into the PostGIS, MySQL, and Oracle spatial databases. shp2pgsql: This utility is included with PostGIS and only supports ESRI shapeles.
GDAL Interface
Earlier we used the the ogrinfo to explore the contents of the world borders shapele. Included within GeoDjango is an interface to GDALs powerful OGR library in other words, youll be able explore all the vector data sources that OGR supports via a Pythonic API. First, invoke the Django shell:
$ python manage.py shell
If the World Borders data was downloaded like earlier in the tutorial, then we can determine the path using Pythons built-in os module:
49.9. GeoDjango
511
>>> import os >>> from geodjango import world >>> world_shp = os.path.abspath(os.path.join(os.path.dirname(world.__file__), ... data/TM_WORLD_BORDERS-0.3.shp))
Now, the world borders shapele may be opened using GeoDjangos DataSource interface:
>>> from django.contrib.gis.gdal import * >>> ds = DataSource(world_shp) >>> print ds / ... /geodjango/world/data/TM_WORLD_BORDERS-0.3.shp (ESRI Shapefile)
Data source objects can have different layers of geospatial features; however, shapeles are only allowed to have one layer:
>>> print len(ds) 1 >>> lyr = ds[0] >>> print lyr TM_WORLD_BORDERS-0.3
You can see what the geometry type of the layer is and how many features it contains:
>>> print lyr.geom_type Polygon >>> print len(lyr) 246
Note: Unfortunately the shapele data format does not allow for greater specicity with regards to geometry types. This shapele, like many others, actually includes MultiPolygon geometries in its features. You need to watch out for this when creating your models as a GeoDjango PolygonField will not accept a MultiPolygon type geometry thus a MultiPolygonField is used in our models denition instead. The Layer may also have a spatial reference system associated with it if it does, the srs attribute will return a SpatialReference object:
>>> srs = lyr.srs >>> print srs GEOGCS["GCS_WGS_1984", DATUM["WGS_1984", SPHEROID["WGS_1984",6378137.0,298.257223563]], PRIMEM["Greenwich",0.0], UNIT["Degree",0.0174532925199433]] >>> srs.proj4 # PROJ.4 representation +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs
Here weve noticed that the shapele is in the popular WGS84 spatial reference system in other words, the data uses units of degrees longitude and latitude. In addition, shapeles also support attribute elds that may contain additional data. Here are the elds on the World Borders layer:
>>> print lyr.fields [FIPS, ISO2, ISO3, UN, NAME, AREA, POP2005, REGION, SUBREGION, LON, LAT]
Here we are examining the OGR types (e.g., whether a eld is an integer or a string) associated with each of the elds:
512
>>> [fld.__name__ for fld in lyr.field_types] [OFTString, OFTString, OFTString, OFTInteger, OFTString, OFTInteger, OFTInteger, OFTIn
You can iterate over each feature in the layer and extract information from both the features geometry (accessed via the geom attribute) as well as the features attribute elds (whose values are accessed via get() method):
>>> for feat in lyr: ... print feat.get(NAME), feat.geom.num_points ... Guernsey 18 Jersey 26 South Georgia South Sandwich Islands 338 Taiwan 363
Here the boundary geometry for San Marino is extracted and looking exported to WKT and GeoJSON:
>>> geom = feat.geom >>> print geom.wkt POLYGON ((12.415798 43.957954,12.450554 ... >>> print geom.json { "type": "Polygon", "coordinates": [ [ [ 12.415798, 43.957954 ], [ 12.450554, 43.979721 ], ...
LayerMapping
Were going to dive right in create a le called load.py inside the world application, and insert the following:
import os from django.contrib.gis.utils import LayerMapping from models import WorldBorders world_mapping = { fips : FIPS, iso2 : ISO2, iso3 : ISO3, un : UN, name : NAME, area : AREA, pop2005 : POP2005, region : REGION, subregion : SUBREGION, lon : LON, lat : LAT, mpoly : MULTIPOLYGON,
49.9. GeoDjango
513
world_shp = os.path.abspath(os.path.join(os.path.dirname(__file__), data/TM_WORLD_BORDERS-0.3.shp)) def run(verbose=True): lm = LayerMapping(WorldBorders, world_shp, world_mapping, transform=False, encoding=iso-8859-1) lm.save(strict=True, verbose=verbose)
A few notes about whats going on: Each key in the world_mapping dictionary corresponds to a eld in the WorldBorders model, and the value is the name of the shapele eld that data will be loaded from. The key mpoly for the geometry eld is MULTIPOLYGON, the geometry type we wish to import as. Even if simple polygons are encountered in the shapele they will automatically be converted into collections prior to insertion into the database. The path to the shapele is not absolute in other words, if you move the world application (with data subdirectory) to a different location, then the script will still work. The transform keyword is set to False because the data in the shapele does not need to be converted its already in WGS84 (SRID=4326). The encoding keyword is set to the character encoding of string values in the shapele. This ensures that string values are read and saved correctly from their original encoding system. Afterwards, invoke the Django shell from the geodjango project directory:
$ python manage.py shell
Next, import the load module, call the run routine, and watch LayerMapping do the work:
>>> from world import load >>> load.run()
Try ogrinspect
Now that youve seen how to dene geographic models and import data with the LayerMapping data import utility, its possible to further automate this process with use of the ogrinspect management command. The ogrinspect command introspects a GDAL-supported vector data source (e.g., a shapele) and generates a model denition and LayerMapping dictionary automatically. The general usage of the command goes as follows:
$ python manage.py ogrinspect [options] <data_source> <model_name> [options]
Where data_source is the path to the GDAL-supported data source and model_name is the name to use for the model. Command-line options may be used to further dene how the model is generated. For example, the following command nearly reproduces the WorldBorders model and mapping dictionary created above, automatically:
$ python manage.py ogrinspect world/data/TM_WORLD_BORDERS-0.3.shp WorldBorders --srid=4326 --mapping
514
The --srid=4326 option sets the SRID for the geographic eld. The --mapping option tells ogrinspect to also generate a mapping dictionary for use with LayerMapping. The --multi option is specied so that the geographic eld is a MultiPolygonField instead of just a PolygonField. The command produces the following output, which may be copied directly into the models.py of a GeoDjango application:
# This is an auto-generated Django model module created by ogrinspect. from django.contrib.gis.db import models class WorldBorders(models.Model): fips = models.CharField(max_length=2) iso2 = models.CharField(max_length=2) iso3 = models.CharField(max_length=3) un = models.IntegerField() name = models.CharField(max_length=50) area = models.IntegerField() pop2005 = models.IntegerField() region = models.IntegerField() subregion = models.IntegerField() lon = models.FloatField() lat = models.FloatField() geom = models.MultiPolygonField(srid=4326) objects = models.GeoManager() # Auto-generated LayerMapping dictionary for WorldBorders model worldborders_mapping = { fips : FIPS, iso2 : ISO2, iso3 : ISO3, un : UN, name : NAME, area : AREA, pop2005 : POP2005, region : REGION, subregion : SUBREGION, lon : LON, lat : LAT, geom : MULTIPOLYGON, }
Spatial Queries
Spatial Lookups
GeoDjango extends the Django ORM and allows the use of spatial lookups. Lets do an example where we nd the WorldBorder model that contains a point. First, re up the management shell:
$ python manage.py shell
49.9. GeoDjango
515
The pnt_wkt string represents the point at -95.3385 degrees longitude, and 29.7245 degrees latitude. The geometry is in a format known as Well Known Text (WKT), an open standard issued by the Open Geospatial Consortium (OGC). 4 Import the WorldBorders model, and perform a contains lookup using the pnt_wkt as the parameter:
>>> from world.models import WorldBorders >>> qs = WorldBorders.objects.filter(mpoly__contains=pnt_wkt) >>> qs [<WorldBorders: United States>]
Here we retrieved a GeoQuerySet that has only one model: the one for the United States (which is what we would expect). Similarly, a GEOS geometry object may also be used here the intersects spatial lookup is combined with the get method to retrieve only the WorldBorders instance for San Marino instead of a queryset:
>>> from django.contrib.gis.geos import Point >>> pnt = Point(12.4604, 43.9420) >>> sm = WorldBorders.objects.get(mpoly__intersects=pnt) >>> sm <WorldBorders: San Marino>
The contains and intersects lookups are just a subset of whats available the GeoDjango Database API documentation has more.
Note that pnt may also constructed with EWKT, an extended form of WKT that includes the SRID:
>>> pnt = GEOSGeometry(SRID=32140;POINT(954158.1 4215137.1))
When using GeoDjangos ORM, it will automatically wrap geometry values in transformation SQL, allowing the developer to work at a higher level of abstraction:
>>> qs = WorldBorders.objects.filter(mpoly__intersects=pnt) >>> qs.query.as_sql() # Generating the SQL (SELECT "world_worldborders"."id", "world_worldborders"."name", "world_worldborders"."area", "world_worldborders"."pop2005", "world_worldborders"."fips", "world_worldborders"."iso2", "world_worldborders"."iso3", "world_worldborders"."un", "world_worldborders"."region", "world_worldborders"."subregion", "world_worldborders"."lon", "world_worldborders"."lat", "world_worldborders"."mpoly" FROM "world_worldborders" WHERE ST_Intersects("world_worldborders"."mpoly", ST_Transform(%s, 4326)), (<django.contrib.gis.db.backend.postgis.adaptor.PostGISAdaptor object at 0x25641b0>,)) >>> qs # printing evaluates the queryset [<WorldBorders: United States>]
4
Open Geospatial Consortium, Inc., OpenGIS Simple Feature Specication For SQL, Document 99-049.
516
Lazy Geometries
Geometries come to GeoDjango in a standardized textual representation. Upon access of the geometry eld, GeoDjango creates a GEOS geometry object <ref-geos>, exposing powerful functionality, such as serialization properties for popular geospatial formats:
>>> sm = WorldBorders.objects.get(name=San Marino) >>> sm.mpoly <MultiPolygon object at 0x24c6798> >>> sm.mpoly.wkt # WKT MULTIPOLYGON (((12.4157980000000006 43.9579540000000009, 12.4505540000000003 43.9797209999999978, ... >>> sm.mpoly.wkb # WKB (as Python binary buffer) <read-only buffer for 0x1fe2c70, size -1, offset 0 at 0x2564c40> >>> sm.mpoly.geojson # GeoJSON (requires GDAL) { "type": "MultiPolygon", "coordinates": [ [ [ [ 12.415798, 43.957954 ], [ 12.450554, 43.979721 ], .
This includes access to all of the advanced geometric operations provided by the GEOS library:
>>> pnt = Point(12.4604, 43.9420) >>> sm.mpoly.contains(pnt) True >>> pnt.contains(sm.mpoly) False
GeoQuerySet Methods
Putting your data on the map
Next, edit your urls.py in the geodjango project folder to look as follows:
from django.conf.urls.defaults import * from django.contrib.gis import admin admin.autodiscover() urlpatterns = patterns(,
49.9. GeoDjango
517
(r^admin/(.*), include(admin.site.urls)), )
Finally, browse to http://localhost:8000/admin/, and log in with the admin user created after running syncdb. Browse to any of the WorldBorders entries the borders may be edited by clicking on a polygon and dragging the vertexes to the desired position. OSMGeoAdmin With the OSMGeoAdmin, GeoDjango uses a Open Street Map layer in the admin. This provides more context (including street and thoroughfare details) than available with the GeoModelAdmin (which uses the Vector Map Level 0 WMS data set hosted at Metacarta). First, there are some important requirements and limitations: OSMGeoAdmin requires that the spherical mercator projection be added to the to be added to the spatial_ref_sys table (PostGIS 1.3 and below, only). The PROJ.4 datum shifting les must be installed (see the PROJ.4 installation instructions for more details). If you meet these requirements, then just substitute in the OSMGeoAdmin option class in your admin.py le:
admin.site.register(WorldBorders, admin.OSMGeoAdmin)
518
Requirements
Python 2.4+
Because of heavy use of the decorator syntax, Python 2.4 is minimum version supported by GeoDjango. Python 2.5+ is recommended because the ctypes module comes included; otherwise, 2.4 users will need to download and install ctypes.
Django
Because GeoDjango is included with Django, please refer to Djangos installation instructions for details on how to install.
Spatial Database
PostgreSQL (with PostGIS), MySQL, Oracle, and SQLite (with SpatiaLite) are the spatial databases currently supported. Note: PostGIS is recommended, because it is the most mature and feature-rich open source spatial database. The geospatial libraries required for a GeoDjango installation depends on the spatial database used. The following lists the library requirements, supported versions, and any notes for each of the supported database backends: Database PostgreSQL MySQL Oracle SQLite Library Requirements GEOS, PROJ.4, PostGIS GEOS GEOS GEOS, GDAL, PROJ.4, SpatiaLite Supported Versions 8.1+ 5.x 10.2, 11 3.6.+ Notes Requires PostGIS. Not OGC-compliant; limited functionality. XE not supported; not tested with 9. Requires SpatiaLite 2.3+, pysqlite2 2.5+, and Django 1.1.
Geospatial Libraries
GeoDjango uses and/or provides interfaces for the the following open source geospatial libraries: Program GEOS PROJ.4 GDAL GeoIP PostGIS SpatiaLite Install GDAL While GDAL is technically not required, it is recommended. Some features of GeoDjango (including the LayerMapping data import utility and the geographic admin) depend on its functionality. Note: The GeoDjango interfaces to GEOS, GDAL, and GeoIP may be used independently of Django. In other words, no database or settings le required just import them as normal from django.contrib.gis. Description Geometry Engine Open Source Cartographic Projections library Geospatial Data Abstraction Library IP-based geolocation library Spatial extensions for PostgreSQL Spatial extensions for SQLite Required Yes Yes (PostgreSQL and SQLite only) No (but, required for SQLite) No Yes (PostgreSQL only) Yes (SQLite only) Supported Versions 3.2, 3.1, 3.0 4.7, 4.6, 4.5, 4.4 1.7, 1.6, 1.5, 1.4 1.4 1.5, 1.4, 1.3 2.4, 2.3
49.9. GeoDjango
519
Building from Source When installing from source on UNIX and GNU/Linux systems, please follow the installation instructions carefully, and install the libraries in the given order. If using MySQL or Oracle as the spatial database, only GEOS is required. Note: On Linux platforms, it may be necessarry to run the ldconfig command after installing each library. For example:
$ sudo make install $ sudo ldconfig
Note: OS X users are required to install Apple Developer Tools in order to compile software from source. This is typically included on your OS X installation DVDs.
GEOS
GEOS is a C++ library for performing geometric operations, and is the default internal geometry representation used by GeoDjango (its behind the lazy geometries). Specically, the C API library is called (e.g., libgeos_c.so) directly from Python using ctypes. First, download GEOS 3.2 from the refractions website and untar the source archive:
$ wget http://download.osgeo.org/geos/geos-3.2.2.tar.bz2 $ tar xjf geos-3.2.2.tar.bz2
Next, change into the directory where GEOS was unpacked, run the congure script, compile, and install:
$ $ $ $ $ cd geos-3.2.2 ./configure make sudo make install cd ..
Troubleshooting Cant nd GEOS Library When GeoDjango cant nd GEOS, this error is raised:
ImportError: Could not find the GEOS library (tried "geos_c"). Try setting GEOS_LIBRARY_PATH in your
The most common solution is to properly congure your Library Environment Settings or set GEOS_LIBRARY_PATH in your settings. If using a binary package of GEOS (e.g., on Ubuntu 8.10), you may need to Install binutils. GEOS_LIBRARY_PATH If your GEOS library is in a non-standard location, or you dont want to modify the systems library path then the GEOS_LIBRARY_PATH setting may be added to your Django settings le with the full path to the GEOS C library. For example:
GEOS_LIBRARY_PATH = /home/bob/local/lib/libgeos_c.so
Note: The setting must be the full path to the C shared library; in other words you want to use libgeos_c.so, not libgeos.so.
520
PROJ.4
PROJ.4 is a library for converting geospatial data to different coordinate reference systems. First, download the PROJ.4 source code and datum shifting les 5 :
$ wget http://download.osgeo.org/proj/proj-4.7.0.tar.gz $ wget http://download.osgeo.org/proj/proj-datumgrid-1.5.zip
Next, untar the source code archive, and extract the datum shifting les in the nad subdirectory. This must be done prior to conguration:
$ $ $ $ tar xzf proj-4.7.0.tar.gz cd proj-4.7.0/nad unzip ../../proj-datumgrid-1.5.zip cd ..
PostGIS
PostGIS adds geographic object support to PostgreSQL, turning it into a spatial database. GEOS and PROJ.4 should be installed prior to building PostGIS. Note: The psycopg2 module is required for use as the database adaptor when using GeoDjango with PostGIS. First download the source archive, and extract:
$ wget http://postgis.refractions.net/download/postgis-1.5.1.tar.gz $ tar xzf postgis-1.5.1.tar.gz $ cd postgis-1.5.1
Note: GeoDjango does not automatically create a spatial database. Please consult the section on Creating a Spatial Database Template for PostGIS for more information.
5 The datum shifting les are needed for converting data to and from certain projections. For example, the PROJ.4 string for the Google projection (900913) requires the null grid le only included in the extra datum shifting les. It is easier to install the shifting les now, then to have debug a problem caused by their absence later.
49.9. GeoDjango
521
GDAL
GDAL is an excellent open source geospatial library that has support for reading most vector and raster spatial data formats. Currently, GeoDjango only supports GDALs vector data capabilities 6 . GEOS and PROJ.4 should be installed prior to building GDAL. First download the latest GDAL release version and untar the archive:
$ wget http://download.osgeo.org/gdal/gdal-1.7.2.tar.gz $ tar xzf gdal-1.7.2.tar.gz $ cd gdal-1.7.2
Note: Because GeoDjango has its own Python interface, the preceding instructions do not build GDALs own Python bindings. The bindings may be built by adding the --with-python ag when running configure. See GDAL/OGR In Python for more information on GDALs bindings. If you have any problems, please see the troubleshooting section below for suggestions and solutions. Troubleshooting Cant nd GDAL Library When GeoDjango cant nd the GDAL library, the HAS_GDAL ag will be false:
>>> from django.contrib.gis import gdal >>> gdal.HAS_GDAL False
The solution is to properly congure your Library Environment Settings or set GDAL_LIBRARY_PATH in your settings. GDAL_LIBRARY_PATH If your GDAL library is in a non-standard location, or you dont want to modify the systems library path then the GDAL_LIBRARY_PATH setting may be added to your Django settings le with the full path to the GDAL library. For example:
GDAL_LIBRARY_PATH = /home/sue/local/lib/libgdal.so
Cant nd GDAL data les (GDAL_DATA) When installed from source, GDAL versions 1.5.1 and below have an autoconf bug that places data in the wrong location. 7 This can lead to error messages like this:
ERROR 4: Unable to open EPSG support file gcs.csv. ... OGRException: OGR failure.
6 7
Specically, GeoDjango provides support for the OGR library, a component of GDAL. See GDAL ticket #2382.
522
The solution is to set the GDAL_DATA environment variable to the location of the GDAL data les before invoking Python (typically /usr/local/share; use gdal-config --datadir to nd out). For example:
$ export GDAL_DATA=gdal-config --datadir $ python manage.py shell
If using Apache, you may need to add this environment variable to your conguration le:
SetEnv GDAL_DATA /usr/local/share
SpatiaLite
New in version 1.1: Please, see the release notes Note: Mac OS X users should follow the instructions in the KyngChaos Packages section, as it is much easier than building from source. SpatiaLite adds spatial support to SQLite, turning it into a full-featured spatial database. Because SpatiaLite has special requirements, it typically requires SQLite and pysqlite2 (the Python SQLite DB-API adaptor) to be built from source. GEOS and PROJ.4 should be installed prior to building SpatiaLite. After installation is complete, dont forget to read the post-installation docs on Creating a Spatial Database for SpatiaLite. SQLite Typically, SQLite packages are not compiled to include the R*Tree module thus it must be compiled from source. First download the latest amalgamation source archive from the SQLite download page, and extract:
$ wget http://www.sqlite.org/sqlite-amalgamation-3.6.22.tar.gz $ tar xzf sqlite-amalgamation-3.6.22.tar.gz $ cd sqlite-3.6.22
Next, run the configure script however the CFLAGS environment variable needs to be customized so that SQLite knows to build the R*Tree module:
$ $ $ $ CFLAGS="-DSQLITE_ENABLE_RTREE=1" ./configure make sudo make install cd ..
Note: If using Ubuntu, installing a newer SQLite from source can be very difcult because it links to the existing libsqlite3.so in /usr/lib which many other packages depend on. Unfortunately, the best solution at this time is to overwrite the existing library by adding --prefix=/usr to the configure command. SpatiaLite Library (libspatialite) and Tools (spatialite) After SQLite has been built with the R*Tree module enabled, get the latest SpatiaLite library source and tools bundle from the download page:
$ $ $ $ wget http://www.gaia-gis.it/spatialite/libspatialite-amalgamation-2.3.1.tar.gz wget http://www.gaia-gis.it/spatialite/spatialite-tools-2.3.1.tar.gz tar xzf libspatialite-amalgamation-2.3.1.tar.gz tar xzf spatialite-tools-2.3.1.tar.gz
Prior to attempting to build, please read the important notes below to see if customization of the configure command is necessary. If not, then run the configure script, make, and install for the SpatiaLite library:
49.9. GeoDjango
523
$ $ $ $ $
cd libspatialite-amalgamation-2.3.1 ./configure # May need to modified, see notes below. make sudo make install cd ..
Note: If youve installed GEOS and PROJ.4 from binary packages, you will have to specify their paths when running the configure scripts for both the library and the tools (the congure scripts look, by default, in /usr/local). For example, on Debian/Ubuntu distributions that have GEOS and PROJ.4 packages, the command would be:
Note: For Mac OS X users building from source, the SpatiaLite library and tools need to be linked into the existing iconv library. While this happens automatically on Linux, the configure scripts need to know about the specic location on Mac OS X (via modication of the CFLAGS and LDFLAGS environment variables prior to conguration):
$ CFLAGS=-I/usr/include LDFLAGS="-L/usr/lib -liconv" ./configure
pysqlite2 Because SpatiaLite must be loaded as an external extension, it requires the enable_load_extension method, which is only available in versions 2.5+. Thus, download pysqlite2 2.6, and untar:
$ wget http://pysqlite.googlecode.com/files/pysqlite-2.6.0.tar.gz $ tar xzf pysqlite-2.6.0.tar.gz $ cd pysqlite-2.6.0
Next, use a text editor (e.g., emacs or vi) to edit the setup.cfg le to look like the following:
[build_ext] #define= include_dirs=/usr/local/include library_dirs=/usr/local/lib libraries=sqlite3 #define=SQLITE_OMIT_LOAD_EXTENSION
Note: The important thing here is to make sure you comment out the the define=SQLITE_OMIT_LOAD_EXTENSION ag and that the include_dirs and library_dirs settings are uncommented and set to the appropriate path if the SQLite header les and libraries are not in /usr/include and /usr/lib, respectively. After modifying setup.cfg appropriately, then run the setup.py script to build and install:
$ sudo python setup.py install
524
Post-Installation
Note: The location and name of the PostGIS SQL les (e.g., from POSTGIS_SQL_PATH below) depends on the version of PostGIS. PostGIS versions 1.3 and below use <pg_sharedir>/contrib/lwpostgis.sql; whereas version 1.4 uses <sharedir>/contrib/postgis.sql and version 1.5 uses <sharedir>/contrib/postgis-1.5/postgis.sql. The example below assumes PostGIS 1.5, thus you may need to modify POSTGIS_SQL_PATH and the name of the SQL le for the specic version of PostGIS you are using. Once youre a database super user, then you may execute the following commands to create a PostGIS spatial database template. If running Ubuntu 8.10 or Debian 5.0 (Lenny), please refer to their specic documentation for modications to these commands:
$ # $ $ # $ # $ $ # $ $ $
POSTGIS_SQL_PATH=pg_config --sharedir/contrib/postgis-1.5 Creating the template spatial database. createdb -E UTF8 template_postgis createlang -d template_postgis plpgsql # Adding PLPGSQL language support. Allows non-superusers the ability to create from this template psql -d postgres -c "UPDATE pg_database SET datistemplate=true WHERE datname=template_postgis;" Loading the PostGIS SQL routines psql -d template_postgis -f $POSTGIS_SQL_PATH/postgis.sql psql -d template_postgis -f $POSTGIS_SQL_PATH/spatial_ref_sys.sql Enabling users to alter spatial tables. psql -d template_postgis -c "GRANT ALL ON geometry_columns TO PUBLIC;" psql -d template_postgis -c "GRANT ALL ON geography_columns TO PUBLIC;" psql -d template_postgis -c "GRANT ALL ON spatial_ref_sys TO PUBLIC;"
These commands may be placed in a shell script for later use; for convenience the following scripts are available: PostGIS Version 1.3 1.4 1.5 Shell Script create_template_postgis-1.3.sh create_template_postgis-1.4.sh create_template_postgis-1.5.sh
Afterwards, you may create a spatial database by simply specifying template_postgis as the template to use (via the -T option):
$ createdb -T template_postgis <db name>
Note: While the createdb command does not require database super-user privileges, it must be executed by a database user that has permissions to create databases. You can create such a user with the following command:
$ createuser --createdb <user>
49.9. GeoDjango
525
Note: The parameter geodjango.db is the lename of the SQLite database you want to use. Use the same in the DATABASE_NAME inside your settings.py.
Note: In Django 1.1 the name of this function is add_postgis_srs. This adds an entry for the 900913 SRID to the spatial_ref_sys (or equivalent) table, making it possible for the spatial database to transform coordinates in this projection. You only need to execute this command once per spatial database. Troubleshooting If you cant nd the solution to your problem here then participate in the community! You can: Join the #geodjango IRC channel on FreeNode (may be accessed on the web via Mibbit). Please be patient and polite while you may not get an immediate response, someone will attempt to answer your question as soon as they see it. Ask your question on the GeoDjango mailing list. File a ticket on the Django trac if you think theres a bug. Make sure to provide a complete description of the problem, versions used, and specify the component as GIS.
526
Setting System Library Path On GNU/Linux systems, there is typically a le in /etc/ld.so.conf, which may include additional paths from les in another directory, such as /etc/ld.so.conf.d. As the root user, add the custom library path (like /usr/local/lib) on a new line in ld.so.conf. This is one example of how to do so:
$ sudo echo /usr/local/lib >> /etc/ld.so.conf $ sudo ldconfig
For OpenSolaris users, the system library path may be modied using the crle utility. Run crle with no options to see the current conguration and use crle -l to set with the new library path. Be very careful when modifying the system library path:
# crle -l $OLD_PATH:/usr/local/lib
Install binutils GeoDjango uses the find_library function (from the ctypes.util Python module) to discover libraries. The find_library routine uses a program called objdump (part of the binutils package) to verify a shared library on GNU/Linux systems. Thus, if binutils is not installed on your Linux system then Pythons ctypes may not be able to nd your library even if your library path is set correctly and geospatial libraries were built perfectly. The binutils package may be installed on Debian and Ubuntu systems using the following command:
$ sudo apt-get install binutils
Mac OS X
Because of the variety of packaging systems available for OS X, users have several different options for installing GeoDjango. These options are:
8
GeoDjango uses the nd_library routine from ctypes.util to locate shared libraries.
49.9. GeoDjango
527
KyngChaos Packages Fink MacPorts Building from Source Note: Currently, the easiest and recommended approach for installing GeoDjango on OS X is to use the KyngChaos packages. This section also includes instructions for installing an upgraded version of Python from packages provided by the Python Software Foundation, however, this is not required. Python Although OS X comes with Python installed, users can use framework installers (2.5 and 2.6 are available) provided by the Python Software Foundation. An advantage to using the installer is that OS Xs Python will remain pristine for internal operating system use. Note: You will need to modify the PATH environment variable in your .profile le so that the new version of Python is used when python is entered at the command-line:
export PATH=/Library/Frameworks/Python.framework/Versions/Current/bin:$PATH
KyngChaos Packages William Kyngesburye provides a number of geospatial library binary packages that make it simple to get GeoDjango installed on OS X without compiling them from source. However, the Apple Developer Tools are still necessary for compiling the Python database adapters psycopg2 (for PostGIS) and pysqlite2 (for SpatiaLite). Note: SpatiaLite users should consult the SpatiaLite section after installing the packages for additional instructions. Download the framework packages for: UnixImageIO PROJ GEOS SQLite3 (includes the SpatiaLite library) GDAL Install the packages in the order they are listed above, as the GDAL and SQLite packages require the packages listed before them. Afterwards, you can also install the KyngChaos binary packages for PostgreSQL and PostGIS. After installing the binary packages, youll want to add the following to your .profile to be able to run the package programs from the command-line:
export export export export export export PATH=/Library/Frameworks/UnixImageIO.framework/Programs:$PATH PATH=/Library/Frameworks/PROJ.framework/Programs:$PATH PATH=/Library/Frameworks/GEOS.framework/Programs:$PATH PATH=/Library/Frameworks/SQLite3.framework/Programs:$PATH PATH=/Library/Frameworks/GDAL.framework/Programs:$PATH PATH=/usr/local/pgsql/bin:$PATH
Note: Use of these binaries requires Django 1.0.3 and above. If you are using a previous version of Django (like 1.0.2), then you will have to add the the following in your settings:
GEOS_LIBRARY_PATH=/Library/Frameworks/GEOS.framework/GEOS GDAL_LIBRARY_PATH=/Library/Frameworks/GDAL.framework/GDAL
528
psycopg2 After youve installed the KyngChaos binaries and modied your PATH, as described above, psycopg2 may be installed using the following command:
$ sudo python easy_install psycopg2
Note: To use easy_install youll need to install Pythons setuptools. pysqlite2 Follow the pysqlite2 source install instructions, however, when editing the setup.cfg use the following instead:
[build_ext] #define= include_dirs=/Library/Frameworks/SQLite3.framework/unix/include library_dirs=/Library/Frameworks/SQLite3.framework/unix/lib libraries=sqlite3 #define=SQLITE_OMIT_LOAD_EXTENSION
SpatiaLite When Creating a Spatial Database for SpatiaLite, the spatialite program is required. However, instead of attempting to compile the SpatiaLite tools from source, download the SpatiaLite Binaries for OS X, and install spatialite in a location available in your PATH. For example:
$ $ $ $ curl -O http://www.gaia-gis.it/spatialite/spatialite-tools-osx-x86-2.3.1.tar.gz tar xzf spatialite-tools-osx-x86-2.3.1.tar.gz cd spatialite-tools-osx-x86-2.3.1/bin sudo cp spatialite /Library/Frameworks/SQLite3.framework/Programs
Finally, for GeoDjango to be able to nd the KyngChaos SpatiaLite library, add the following to your settings.py:
SPATIALITE_LIBRARY_PATH=/Library/Frameworks/SQLite3.framework/SQLite3
Fink Kurt Schwehr has been gracious enough to create GeoDjango packages for users of the Fink package system. The following packages are available, depending on which version of Python you want to use: django-gis-py26 django-gis-py25 django-gis-py24 MacPorts MacPorts may be used to install GeoDjango prerequisites on Macintosh computers running OS X. Because MacPorts still builds the software from source, the Apple Developer Tools are required. Summary:
$ $ $ $ $ $ sudo sudo sudo sudo sudo sudo port port port port port port install install install install install install postgresql83-server geos proj postgis gdal libgeoip
Note: You will also have to modify the PATH in your .profile so that the MacPorts programs are accessible from the command-line:
49.9. GeoDjango
529
export PATH=/opt/local/bin:/opt/local/lib/postgresql83/bin
In addition, add the FALLBACK_DYLD_LIBRARY_PATH setting so that the libraries can be found by Python:
export FALLBACK_DYLD_LIBRARY_PATH=/opt/local/lib:/opt/local/lib/postgresql83
Afterwards, you may install Django with Pythons easy_install script (the Ubuntu package python-django uses an older version missing several important bug xes for GeoDjango):
$ sudo easy_install Django
Thats it! For the curious, the required binary prerequisites packages are: binutils: for ctypes to nd libraries postgresql-8.3 postgresql-server-dev-8.3: for pg_config postgresql-8.3-postgis: for PostGIS 1.3.3 libgeos-3.0.0, and libgeos-c1: for GEOS 3.0.0 libgdal1-1.5.0: for GDAL 1.5.0 library proj: for PROJ 4.6.0 but no datum shifting les, see note below python-psycopg2 python-setuptools: for easy_install Optional packages to consider: libgeoip1: for GeoIP support gdal-bin: for GDAL command line programs like ogr2ogr python-gdal for GDALs own Python bindings includes interfaces for raster manipulation Note: The Ubuntu proj package does not come with the datum shifting les installed, which will cause problems with the geographic admin because the null datum grid is not available for transforming geometries to the spherical mercator projection. A solution is to download the datum-shifting les, create the grid le, and install it yourself:
530
$ $ $ $ $ $
wget http://download.osgeo.org/proj/proj-datumgrid-1.4.tar.gz mkdir nad cd nad tar xzf ../proj-datumgrid-1.4.tar.gz nad2bin null < null.lla sudo cp null /usr/share/proj
Otherwise, the Ubuntu proj package is ne for general use as long as you do not plan on doing any database transformation of geometries to the Google projection (900913). Note: The PostGIS SQL les are not placed the PostgreSQL share directory in the Ubuntu packages. Use the create_template_postgis-debian.sh script instead when Creating a Spatial Database Template for PostGIS.
Debian
4.0 (Etch) The situation here is the same as that of Ubuntu 8.04 and lower in other words, some packages must be built from source to work properly with GeoDjango. Binary Packages The following command will install acceptable binary packages, as well as the development tools necessary to build the rest of the requirements:
$ sudo apt-get install binutils bzip2 gcc g++ flex make postgresql-8.1 postgresql-server-dev-8.1 pyth
Required package information: binutils: for ctypes to nd libraries bzip2: for decompressing the source packages gcc, g++, make: GNU developer tools used to compile the libraries flex: required to build PostGIS postgresql-8.1 postgresql-server-dev-8.1: for pg_config python-ctypes: Python 2.4 needs to have ctypes installed separately python-psycopg2 python-setuptools: for easy_install Optional packages: libgeoip: for GeoIP support Source Packages You will still have to install GEOS, PROJ.4, PostGIS, and GDAL from source. Please follow the directions carefully. 5.0 (Lenny) This version is comparable to Ubuntu 8.10, so the command is very similar:
49.9. GeoDjango
531
This assumes that you are using PostgreSQL version 8.3. Else, replace 8.3 in the above command with the appropriate PostgreSQL version. Note: Please read the note in the Ubuntu 8.10 install documentation about the proj package it also applies here because the package does not include the datum shifting les. Post-installation Notes If the PostgreSQL database cluster was not initiated after installing, then it can be created (and started) with the following command:
$ sudo pg_createcluster --start 8.3 main
Afterwards, the /etc/init.d/postgresql-8.3 script should be used to manage the starting and stopping of PostgreSQL. In addition, the SQL les for PostGIS are placed in a different location on Debian 5.0 . Thus when Creating a Spatial Database Template for PostGIS either: Create a symbolic link to these les:
If not running PostgreSQL 8.3, then replace 8.3 in the command above with the correct version. Or use the create_template_postgis-debian.sh to create the spatial database.
Windows XP
Python First, download the Python 2.6 installer from the Python website. Next, execute the installer and use defaults, e.g., keep Install for all users checked and the installation path set as C:\Python26. Note: You may already have a version of Python installed in C:\python as ESRI products sometimes install a copy there. You should still install a fresh version of Python 2.6. PostgreSQL First, select a mirror and download the latest PostgreSQL 8.3 installer from the EnterpriseDB website. Note: PostgreSQL 8.3 is required because PostGIS is not available yet for 8.4. After downloading, simply click on the installer, follow the on-screen directions, and keep the default options (e.g., keep the installation path as C:\Program Files\PostgreSQL\8.3). Note: This PostgreSQL installation process will create both a new windows user to be the postgres service account and a special postgres superuser to own the database cluster. You will be prompted to set a password for both users (make sure to write them down!). To see basic details on the service user account right click on My Computer and select Manage or go to: Control Panel -> Administrative Tools -> Computer Management -> System Tools -> Local Users and Groups. If installed successfully, the PostgreSQL server will run in the background each time the system as started as a Windows service. When nished, the installer should launch the Application Stack Builder (ASB) use this to install PostGIS, see instructions below for more details. A PostgreSQL 8.3 start menu group should be created that contains shortcuts for the ASB and Command Prompt, which launches a terminal window in the PostgreSQL directory.
532
PostGIS From the Application Stack Builder (Programs -> PostgreSQL 8.3), select PostgreSQL Database Server 8.3 on port 5432 from the drop down menu. Next, select PostGIS 1.3.6 for PostgreSQL 8.3 from the Spatial Extensions tree in the list. Select only the default options during install (do not uncheck the option to create a default PostGIS database). Note: You will be prompted to enter your postgres superuser password in the Database Connection Information dialog. psycopg2 The psycopg2 Python module provides the interface between Python and the PostgreSQL database. Download the Windows installer (v2.0.10) and run using the default settings. 9 GeoDjango Installer Download the GeoDjango Installer; this was created 10 to simplify the rest of the process for installing GeoDjango on Windows platforms. The installer automatically installs Django 1.1, GDAL 1.6.0, PROJ 4.6.1 (including datum grid les), and congures the necessary environment variables. Once the installer has completed, log out and log back in so that the modications to the system environment variables take effect, and you should be good to go. Note: The installer modies the system Path environment variable to include C:\Program Files\PostgreSQL\8.3\bin and C:\Program Files\GeoDjango\bin. This is required so that Python may nd the GEOS DLL provided by PostGIS and the GDAL DLL provided by the installer. The installer also sets the GDAL_DATA and PROJ_LIB environment variables.
Geometry Field Types Each of the following geometry eld types correspond with the OpenGIS Simple Features specication 11 .
GeometryField
class GeometryField()
PointField
class PointField()
9 10 11
The psycopg2 Windows installers are packaged and maintained by Jason Erickson. The source code for the installer is available in the nsis_installer GeoDjango mercurial repository. OpenGIS Consortium, Inc., Simple Feature Specication For SQL, Document 99-049 (May 5, 1999).
49.9. GeoDjango
533
LineStringField
class LineStringField()
PolygonField
class PolygonField()
MultiPointField
class MultiPointField()
MultiLineStringField
class MultiLineStringField()
MultiPolygonField
class MultiPolygonField()
GeometryCollectionField
class GeometryCollectionField() Geometry Field Options In addition to the regular Field options available for Django model elds, geometry elds have the following additional options. All are optional.
srid
srid Sets the SRID 12 (Spatial Reference System Identity) of the geometry eld to the given value. Defaults to 4326 (also known as WGS84, units are in degrees of longitude and latitude). Selecting an SRID Choosing an appropriate SRID for your model is an important decision that the developer should consider carefully. The SRID is an integer specier that corresponds to the projection system that will be used to interpret the data in the spatial database. 13 Projection systems give the context to the coordinates that specify a location. Although the details of geodesy are beyond the scope of this documentation, the general problem is that the earth is spherical and representations of the earth (e.g., paper maps, web maps) are not.
See id. at Ch. 2.3.8, p. 39 (Geometry Values and Spatial Reference Systems). Typically, SRID integer corresponds to an EPSG (European Petroleum Survey Group) identier. However, it may also be associated with custom projections dened in spatial databases spatial reference systems table.
13 12
534
Most people are familiar with using latitude and longitude to reference a location on the earths surface. However, latitude and longitude are angles, not distances. 14 In other words, while the shortest path between two points on a at surface is a straight line, the shortest path between two points on a curved surface (such as the earth) is an arc of a great circle. 15 Thus, additional computation is required to obtain distances in planar units (e.g., kilometers and miles). Using a geographic coordinate system may introduce complications for the developer later on. For example, PostGIS versions 1.4 and below do not have the capability to perform distance calculations between non-point geometries using geographic coordinate systems, e.g., constructing a query to nd all points within 5 miles of a county boundary stored as WGS84. 16 Portions of the earths surface may projected onto a two-dimensional, or Cartesian, plane. Projected coordinate systems are especially convenient for region-specic applications, e.g., if you know that your database will only cover geometries in North Kansas, then you may consider using projection system specic to that region. Moreover, projected coordinate systems are dened in Cartesian units (such as meters or feet), easing distance calculations. Note: If you wish to peform arbitrary distance queries using non-point geometries in WGS84, consider upgrading to PostGIS 1.5. For better performance, enable the GeometryField.geography keyword so that geography database type is used instead. Additional Resources: spatialreference.org: A Django-powered database of spatial reference systems. The State Plane Coordinate System: A website covering the various projection systems used in the United States. Much of the U.S. spatial data encountered will be in one of these coordinate systems rather than in a geographic coordinate system such as WGS84.
spatial_index
spatial_index Defaults to True. Creates a spatial index for the given geometry eld. Note: This is different from the db_index eld option because spatial indexes are created in a different manner than regular database indexes. Specically, spatial indexes are typically created using a variant of the R-Tree, while regular database indexes typically use B-Trees.
dim
New in version 1.2: Please, see the release notes dim This option may be used for customizing the coordinate dimension of the geometry eld. By default, it is set to 2, for representing two-dimensional geometries. For spatial backends that support it, it may be set to 3 for three-dimensonal support. Note: At this time 3D support requires that GEOS 3.1 be installed, and is limited only to the PostGIS spatial backend.
14 Harvard Graduate School of Design, An Overview of Geodesy and Geographic Referencing Systems. This is an excellent resource for an overview of principles relating to geographic and Cartesian coordinate systems. 15 Terry A. Slocum, Robert B. McMaster, Fritz C. Kessler, & Hugh H. Howard, Thematic Cartography and Geographic Visualization (Prentice Hall, 2nd edition), at Ch. 7.1.3. 16 This limitation does not apply to PostGIS 1.5. It should be noted that even in previous versions of PostGIS, this isnt impossible using GeoDjango; you could for example, take a known point in a projected coordinate system, buffer it to the appropriate radius, and then perform an intersection operation with the buffer transformed to the geographic coordinate system.
49.9. GeoDjango
535
geography
New in version 1.2: Please, see the release notes geography If set to True, this option will create a database column of type geography, rather than geometry. Please refer to the geography type section below for more details. Note: Geography support is limited only to PostGIS 1.5+, and will force the SRID to be 4326. Geography Type In PostGIS 1.5, the geography type was introduced it provides provides native support for spatial features represented with geographic coordinates (e.g., WGS84 longitude/latitude). 17 Unlike the plane used by a geometry type, the geography type uses a spherical representation of its data. Distance and measurement operations performed on a geography column automatically employ great circle arc calculations and return linear units. In other words, when ST_Distance is called on two geographies, a value in meters is returned (as opposed to degrees if called on a geometry column in WGS84). Because geography calculations involve more mathematics, only a subset of the PostGIS spatial lookups are available for the geography type. Practically, this means that in addition to the distance lookups only the following additional spatial lookups are available for geography columns: bboverlaps exact, and same_as coveredby covers intersects For more information, the PostGIS documentation contains a helpful section on determining when to use geography data type over geometry data type. GeoManager class GeoManager() In order to conduct geographic queries, each geographic model requires a GeoManager model manager. This manager allows for the proper SQL construction for geographic queries; thus, without it, all geographic lters will fail. It should also be noted that GeoManager is required even if the model does not have a geographic eld itself, e.g., in the case of a ForeignKey relation to a model with a geographic eld. For example, if we had an Address model with a ForeignKey to our Zipcode model:
from django.contrib.gis.db import models from django.contrib.localflavor.us.models import USStateField class Address(models.Model): num = models.IntegerField() street = models.CharField(max_length=100) city = models.CharField(max_length=100) state = USStateField() zipcode = models.ForeignKey(Zipcode) objects = models.GeoManager()
The geographic manager is needed to do spatial queries on related Zipcode objects, for example:
17
Please refer to the PostGIS Geography Type documentation for more details.
536
qs = Address.objects.filter(zipcode__poly__contains=POINT(-104.590948 38.319914))
49.9. GeoDjango
537
Warning: True spatial indexes (R-trees) are only supported with MyISAM tables on MySQL. a In other words, when using MySQL spatial extensions you have to choose between fast spatial lookups and the integrity of your data MyISAM tables do not support transactions or foreign key constraints.
a
See Creating Spatial Indexes in the MySQL 5.1 Reference Manual: For MyISAM tables, SPATIAL INDEX creates an R-tree index. For storage engines that support nonspatial indexing of spatial columns, the engine creates a B-tree index. A B-tree index on spatial values will be useful for exact-value lookups, but not for range scans.
Creating and Saving Geographic Models Here is an example of how to create a geometry object (assuming the Zipcode model):
>>> from zipcode.models import Zipcode >>> z = Zipcode(code=77096, poly=POLYGON(( 10 10, 10 20, 20 20, 20 15, 10 10))) >>> z.save()
Moreover, if the GEOSGeometry is in a different coordinate system (has a different SRID value) than that of the eld, then it will be implicitly transformed into the SRID of the models eld, using the spatial databases transform procedure:
>>> poly_3084 = GEOSGeometry(POLYGON(( 10 10, 10 20, 20 20, 20 15, 10 10)), srid=3084) # SRID 3084 >>> z = Zipcode(code=78212, poly=poly_3084) >>> z.save() >>> from django.db import connection >>> print connection.queries[-1][sql] # printing the last SQL statement executed (requires DEBUG=Tr INSERT INTO "geoapp_zipcode" ("code", "poly") VALUES (78212, ST_Transform(ST_GeomFromWKB(\\001 ...
Thus, geometry parameters may be passed in using the GEOSGeometry object, WKT (Well Known Text 18 ), HEXEWKB (PostGIS specic a WKB geometry in hexadecimal 19 ), and GeoJSON 20 (requires GDAL). Essentially, if the input is not a GEOSGeometry object, the geometry eld will attempt to create a GEOSGeometry instance from the input. For more information creating GEOSGeometry objects, refer to the GEOS tutorial. Spatial Lookups GeoDjangos lookup types may be used with any manager method like filter(), exclude(), etc. However, the lookup types unique to GeoDjango are only available on geometry elds. Filters on normal elds (e.g. CharField) may be chained with those on geographic elds. Thus, geographic queries take the following general form (assuming the Zipcode model used in the GeoDjango Model API ):
18 See Open Geospatial Consortium, Inc., OpenGIS Simple Feature Specication For SQL, Document 99-049 (May 5, 1999), at Ch. 3.2.5, p. 3-11 (SQL Textual Representation of Geometry). 19 See PostGIS EWKB, EWKT and Canonical Forms, PostGIS documentation at Ch. 4.1.2. 20 See Howard Butler, Martin Daly, Allan Doyle, Tim Schaub, & Christopher Schmidt, The GeoJSON Format Specication, Revision 1.0 (June 16, 2008).
538
For example:
>>> qs = Zipcode.objects.filter(poly__contains=pnt)
In this case, poly is the geographic eld, contains is the spatial lookup type, and pnt is the parameter (which may be a GEOSGeometry object or a string of GeoJSON , WKT, or HEXEWKB). A complete reference can be found in the spatial lookup reference. Note: GeoDjango constructs spatial SQL with the GeoQuerySet, a subclass of QuerySet. The GeoManager instance attached to your model is what enables use of GeoQuerySet. Distance Queries
Introduction
Distance calculations with spatial data is tricky because, unfortunately, the Earth is not at. Some distance queries with elds in a geographic coordinate system may have to be expressed differently because of limitations in PostGIS. Please see the Selecting an SRID section in the GeoDjango Model API documentation for more details.
Distance Lookups
Availability: PostGIS, Oracle, SpatiaLite The following distance lookups are available: distance_lt distance_lte distance_gt distance_gte dwithin Note: For measuring, rather than querying on distances, use the GeoQuerySet.distance() method. Distance lookups take a tuple parameter comprising: 1. A geometry to base calculations from; and 2. A number or Distance object containing the distance. If a Distance object is used, it may be expressed in any units (the SQL generated will use units converted to those of the eld); otherwise, numeric parameters are assumed to be in the units of the eld. Note: For users of PostGIS 1.4 and below, the routine ST_Distance_Sphere is used by default for calculating distances on geographic coordinate systems (e.g., WGS84) which may only be called with point geometries 21 . Thus, geographic distance lookups on traditional PostGIS geometry columns are only allowed on PointField model elds using a point for the geometry parameter.
21
49.9. GeoDjango
539
Note: In PostGIS 1.5, ST_Distance_Sphere does not limit the geometry types geographic distance queries are performed with. 22 However, these queries may take a long time, as great-circle distances must be calculated on the y for every row in the query. This is because the spatial index on traditional geometry elds cannot be used. For much better performance on WGS84 distance queries, consider using geography columns in your database instead because they are able to use their spatial index in distance queries. You can tell GeoDjango to use a geography column by setting geography=True in your eld denition. For example, lets say we have a SouthTexasCity model (from the GeoDjango distance tests ) on a projected coordinate system valid for cities in southern Texas:
from django.contrib.gis.db import models class SouthTexasCity(models.Model): name = models.CharField(max_length=30) # A projected coordinate system (only valid for South Texas!) # is used, units are in meters. point = models.PointField(srid=32140) objects = models.GeoManager()
Compatibility Tables
Spatial Lookups
The following table provides a summary of what spatial lookups are available for each spatial database backend. Lookup Type bbcontains bboverlaps contained contains contains_properly coveredby covers crosses disjoint distance_gt distance_gte
22 23
PostGIS X X X X X X X X X X X
Oracle
X X X X X X
MySQL 23 X X X X
SpatiaLite X X X X
See PostGIS 1.5 documentation on ST_distance_sphere. Refer MySQL Spatial Limitations section for more details.
540
Table 49.1 continued from previous page distance_lt X X distance_lte X X dwithin X X equals X X X exact X X X intersects X X X overlaps X X X relate X X same_as X X X touches X X X within X X X left X right X overlaps_left X overlaps_right X overlaps_above X overlaps_below X strictly_above X strictly_below X
X X X X X X X X X X
GeoQuerySet Methods
The following table provides a summary of what GeoQuerySet methods are available on each spatial backend. Please note that MySQL does not support any of these methods, and is thus excluded from the table. Method GeoQuerySet.area() GeoQuerySet.centroid() GeoQuerySet.collect() GeoQuerySet.difference() GeoQuerySet.distance() GeoQuerySet.envelope() GeoQuerySet.extent() GeoQuerySet.extent3d() GeoQuerySet.force_rhr() GeoQuerySet.geohash() GeoQuerySet.geojson() GeoQuerySet.gml() GeoQuerySet.intersection() GeoQuerySet.kml() GeoQuerySet.length() GeoQuerySet.make_line() GeoQuerySet.mem_size() GeoQuerySet.num_geom() GeoQuerySet.num_points() GeoQuerySet.perimeter() GeoQuerySet.point_on_surface() GeoQuerySet.reverse_geom() GeoQuerySet.scale() GeoQuerySet.snap_to_grid() GeoQuerySet.svg() PostGIS X X X X X X X X X X X X X X X X X X X X X X X X X Oracle X X X X X SpatiaLite X X X X X
X X X
X X
X X X X X
X X X X
49.9. GeoDjango
Table 49.2 continued from previous page GeoQuerySet.sym_difference() X X GeoQuerySet.transform() X X GeoQuerySet.translate() X GeoQuerySet.union() X X GeoQuerySet.unionagg() X X
X X X X X
bbcontains
Availability: PostGIS, MySQL, SpatiaLite Tests if the geometry elds bounding box completely contains the lookup geometrys bounding box. Example:
Zipcode.objects.filter(poly__bbcontains=geom)
bboverlaps
Availability: PostGIS, MySQL, SpatiaLite Tests if the geometry elds bounding box overlaps the lookup geometrys bounding box. Example:
Zipcode.objects.filter(poly__bboverlaps=geom)
542
contained
Availability: PostGIS, MySQL, SpatiaLite Tests if the geometry elds bounding box is completely contained by the lookup geometrys bounding box. Example:
Zipcode.objects.filter(poly__contained=geom)
contains
Availability: PostGIS, Oracle, MySQL, SpatiaLite Tests if the geometry eld spatially contains the lookup geometry. Example:
Zipcode.objects.filter(poly__contains=geom)
SQL Equivalent ST_Contains(poly, geom) SDO_CONTAINS(poly, geom) MBRContains(poly, geom) Contains(poly, geom)
contains_properly
New in version 1.2: Please, see the release notes Availability: PostGIS Returns true if the lookup geometry intersects the interior of the geometry eld, but not the boundary (or exterior). Note: Requires PostGIS 1.4 and above. Example:
Zipcode.objects.filter(poly__contains_properly=geom)
24
Backend PostGIS
coveredby
Availability: PostGIS, Oracle Tests if no point in the geometry eld is outside the lookup geometry. Example:
24 25
25
Refer to the PostGIS ST_ContainsProperly documentation for more details. For an explanation of this routine, read Quirks of the Contains Spatial Predicate by Martin Davis (a PostGIS developer).
49.9. GeoDjango
543
Zipcode.objects.filter(poly__coveredby=geom)
covers
Availability: PostGIS, Oracle Tests if no point in the lookup geometry is outside the geometry eld. Example:
Zipcode.objects.filter(poly__covers=geom)
3
crosses
Availability: PostGIS, SpatiaLite Tests if the geometry eld spatially crosses the lookup geometry. Example:
Zipcode.objects.filter(poly__crosses=geom)
disjoint
Availability: PostGIS, Oracle, MySQL, SpatiaLite Tests if the geometry eld is spatially disjoint from the lookup geometry. Example:
Zipcode.objects.filter(poly__disjoint=geom)
SQL Equivalent ST_Disjoint(poly, geom) SDO_GEOM.RELATE(poly, DISJOINT, geom, 0.05) MBRDisjoint(poly, geom) Disjoint(poly, geom)
544
equals
Availability: PostGIS, Oracle, MySQL, SpatiaLite
exact, same_as
Availability: PostGIS, Oracle, MySQL, SpatiaLite
intersects
Availability: PostGIS, Oracle, MySQL, SpatiaLite Tests if the geometry eld spatially intersects the lookup geometry. Example:
Zipcode.objects.filter(poly__intersects=geom)
SQL Equivalent ST_Intersects(poly, geom) SDO_OVERLAPBDYINTERSECT(poly, geom) MBRIntersects(poly, geom) Intersects(poly, geom)
overlaps
Availability: PostGIS, Oracle, MySQL, SpatiaLite
relate
Availability: PostGIS, Oracle, SpatiaLite Tests if the geometry eld is spatially related to the the lookup geometry by the values given in the given pattern. This lookup requires a tuple parameter, (geom, pattern); the form of pattern will depend on the spatial backend: PostGIS & SpatiaLite On these spatial backends the intersection pattern is a string comprising nine characters, which dene intersections between the interior, boundary, and exterior of the geometry eld and the lookup geometry. The intersection pattern matrix may only use the following characters: 1, 2, T, F, or *. This lookup type allows users to ne tune a specic geometric relationship consistent with the DE-9IM model. 26 Example:
# A tuple lookup parameter is used to specify the geometry and # the intersection pattern (the pattern here is for contains). Zipcode.objects.filter(poly__relate(geom, T*T***FF*))
See OpenGIS Simple Feature Specication For SQL, at Ch. 2.1.13.2, p. 2-13 (The Dimensionally Extended Nine-Intersection Model).
49.9. GeoDjango
545
Oracle Here the relation pattern is compreised at least one of the nine relation strings: TOUCH, OVERLAPBDYDISJOINT, OVERLAPBDYINTERSECT, EQUAL, INSIDE, COVEREDBY, CONTAINS, COVERS, ON, and ANYINTERACT. Multiple strings may be combined with the logical Boolean operator OR, for example, inside+touch. 27 The relation strings are case-insensitive. Example:
Zipcode.objects.filter(poly__relate(geom, anyinteract))
touches
Availability: PostGIS, Oracle, MySQL, SpatiaLite Tests if the geometry eld spatially touches the lookup geometry. Example:
Zipcode.objects.filter(poly__touches=geom)
SQL Equivalent ST_Touches(poly, geom) MBRTouches(poly, geom) SDO_TOUCH(poly, geom) Touches(poly, geom)
within
Availability: PostGIS, Oracle, MySQL, SpatiaLite Tests if the geometry eld is spatially within the lookup geometry. Example:
Zipcode.objects.filter(poly__within=geom)
SQL Equivalent ST_Within(poly, geom) MBRWithin(poly, geom) SDO_INSIDE(poly, geom) Within(poly, geom)
See SDO_RELATE documentation, from Ch. 11 of the Oracle Spatial Users Guide and Manual.
546
left
Availability: PostGIS Tests if the geometry elds bounding box is strictly to the left of the lookup geometrys bounding box. Example:
Zipcode.objects.filter(poly__left=geom)
PostGIS equivalent:
SELECT ... WHERE poly << geom
right
Availability: PostGIS Tests if the geometry elds bounding box is strictly to the right of the lookup geometrys bounding box. Example:
Zipcode.objects.filter(poly__right=geom)
PostGIS equivalent:
SELECT ... WHERE poly >> geom
overlaps_left
Availability: PostGIS Tests if the geometry elds bounding box overlaps or is to the left of the lookup geometrys bounding box. Example:
Zipcode.objects.filter(poly__overlaps_left=geom)
PostGIS equivalent:
SELECT ... WHERE poly &< geom
overlaps_right
Availability: PostGIS Tests if the geometry elds bounding box overlaps or is to the right of the lookup geometrys bounding box. Example:
Zipcode.objects.filter(poly__overlaps_right=geom)
PostGIS equivalent:
49.9. GeoDjango
547
overlaps_above
Availability: PostGIS Tests if the geometry elds bounding box overlaps or is above the lookup geometrys bounding box. Example:
Zipcode.objects.filter(poly__overlaps_above=geom)
PostGIS equivalent:
SELECT ... WHERE poly |&> geom
overlaps_below
Availability: PostGIS Tests if the geometry elds bounding box overlaps or is below the lookup geometrys bounding box. Example:
Zipcode.objects.filter(poly__overlaps_below=geom)
PostGIS equivalent:
SELECT ... WHERE poly &<| geom
strictly_above
Availability: PostGIS Tests if the geometry elds bounding box is strictly above the lookup geometrys bounding box. Example:
Zipcode.objects.filter(poly__strictly_above=geom)
PostGIS equivalent:
SELECT ... WHERE poly |>> geom
548
strictly_below
Availability: PostGIS Tests if the geometry elds bounding box is strictly above the lookup geometrys bounding box. Example:
Zipcode.objects.filter(poly__strictly_above=geom)
PostGIS equivalent:
SELECT ... WHERE poly |>> geom
Distance Lookups Availability: PostGIS, Oracle, SpatiaLite For an overview on performing distance queries, please refer to the distance queries introduction. Distance lookups take the following form:
<field>__<distance lookup>=(<geometry>, <distance value>[, spheroid])
The value passed into a distance lookup is a tuple; the rst two values are mandatory, and are the geometry to calculate distances to, and a distance value (either a number in units of the eld or a Distance object). On every distance lookup but dwithin, an optional third element, spheroid, may be included to tell GeoDjango to use the more accurate spheroid distance calculation functions on elds with a geodetic coordinate system (e.g., ST_Distance_Spheroid would be used instead of ST_Distance_Sphere).
distance_gt
Returns models where the distance to the geometry eld from the lookup geometry is greater than the given distance value. Example:
Zipcode.objects.filter(poly__distance_gt=(geom, D(m=5)))
SQL Equivalent ST_Distance(poly, geom) > 5 SDO_GEOM.SDO_DISTANCE(poly, geom, 0.05) > 5 Distance(poly, geom) > 5
distance_gte
Returns models where the distance to the geometry eld from the lookup geometry is greater than or equal to the given distance value. Example:
Zipcode.objects.filter(poly__distance_gte=(geom, D(m=5)))
49.9. GeoDjango
549
SQL Equivalent ST_Distance(poly, geom) >= 5 SDO_GEOM.SDO_DISTANCE(poly, geom, 0.05) >= 5 Distance(poly, geom) >= 5
distance_lt
Returns models where the distance to the geometry eld from the lookup geometry is less than the given distance value. Example:
Zipcode.objects.filter(poly__distance_lt=(geom, D(m=5)))
SQL Equivalent ST_Distance(poly, geom) < 5 SDO_GEOM.SDO_DISTANCE(poly, geom, 0.05) < 5 Distance(poly, geom) < 5
distance_lte
Returns models where the distance to the geometry eld from the lookup geometry is less than or equal to the given distance value. Example:
Zipcode.objects.filter(poly__distance_lte=(geom, D(m=5)))
SQL Equivalent ST_Distance(poly, geom) <= 5 SDO_GEOM.SDO_DISTANCE(poly, geom, 0.05) <= 5 Distance(poly, geom) <= 5
dwithin
Returns models where the distance to the geometry eld from the lookup geometry are within the given distance from one another. Example:
Zipcode.objects.filter(poly__dwithin=(geom, D(m=5)))
550
GeoQuerySet Methods GeoQuerySet methods specify that a spatial operation be performed on each patial operation on each geographic eld in the queryset and store its output in a new attribute on the model (which is generally the name of the GeoQuerySet method). There are also aggregate GeoQuerySet methods which return a single value instead of a queryset. This section will describe the API and availability of every GeoQuerySet method available in GeoDjango. Note: What methods are available depend on your spatial backend. See the compatibility table for more details. With a few exceptions, the following keyword arguments may be used with all GeoQuerySet methods: Keyword Description Argument field_name By default, GeoQuerySet methods use the rst geographic eld encountered in the model. This keyword should be used to specify another geographic eld (e.g., field_name=point2) when there are multiple geographic elds in a model. On PostGIS, the field_name keyword may also be used on geometry elds in models that are related via a ForeignKey relation (e.g., field_name=related__point). model_att By default, GeoQuerySet methods typically attach their output in an attribute with the same name as the GeoQuerySet method. Setting this keyword with the desired attribute name will override this default behavior. For example, qs = Zipcode.objects.centroid(model_att=c) will attach the centroid of the Zipcode geometry eld in a c attribute on every model rather than in a centroid attribute. This keyword is required if a method name clashes with an existing GeoQuerySet method if you wanted to use the area() method on model with a PolygonField named area, for example.
Measurement
Availability: PostGIS, Oracle, SpatiaLite area area(**kwargs) Returns the area of the geographic eld in an area attribute on each element of this GeoQuerySet. distance distance(geom, **kwargs) This method takes a geometry as a parameter, and attaches a distance attribute to every model in the returned queryset that contains the distance (as a Distance object) to the given geometry. In the following example (taken from the GeoDjango distance tests), the distance from the Tasmanian city of Hobart to every other PointField in the AustraliaCity queryset is calculated:
>>> pnt = AustraliaCity.objects.get(name=Hobart).point >>> for city in AustraliaCity.objects.distance(pnt): print city.name, city.distance Wollongong 990071.220408 m Shellharbour 972804.613941 m Thirroul 1002334.36351 m Mittagong 975691.632637 m Batemans Bay 834342.185561 m Canberra 598140.268959 m Melbourne 575337.765042 m
49.9. GeoDjango
551
Note: Because the distance attribute is a Distance object, you can easily express the value in the units of your choice. For example, city.distance.mi is the distance value in miles and city.distance.km is the distance value in kilometers. See the Measurement Objects for usage details and the list of Supported units. length length(**kwargs) Returns the length of the geometry eld in a length attribute (a Distance object) on each model in the queryset. perimeter perimeter(**kwargs) Returns the perimeter of the geometry eld in a perimeter attribute (a Distance object) on each model in the queryset.
Geometry Relationships
The following methods take no arguments, and attach geometry objects each element of the GeoQuerySet that is the result of relationship function evaluated on the the geometry eld. centroid centroid(**kwargs) Availability: PostGIS, Oracle, SpatiaLite Returns the centroid value for the geographic eld in a centroid attribute on each element of the GeoQuerySet. envelope envelope(**kwargs) Availability: PostGIS, SpatiaLite Returns a geometry representing the bounding box of the geometry eld in an envelope attribute on each element of the GeoQuerySet. point_on_surface point_on_surface(**kwargs) Availability: PostGIS, Oracle, SpatiaLite Returns a Point geometry guaranteed to lie on the surface of the geometry eld in a point_on_surface attribute on each element of the queryset; otherwise sets with None.
Geometry Editors
force_rhr force_rhr(**kwargs)
552
New in version 1.2: Please, see the release notes Availability: PostGIS Returns a modied version of the polygon/multipolygon in which all of the vertices follow the Right-Hand-Rule, and attaches as a force_rhr attribute on each element of the queryset. reverse_geom reverse_geom(**kwargs) New in version 1.2: Please, see the release notes Availability: PostGIS, Oracle Reverse the coordinate order of the geometry eld, and attaches as a reverse attribute on each element of the queryset. scale scale(x, y, z=0.0, **kwargs) Availability: PostGIS, SpatiaLite snap_to_grid snap_to_grid(*args, **kwargs) New in version 1.1: Please, see the release notes Snap all points of the input geometry to the grid. How the geometry is snapped to the grid depends on how many numeric (either oat, integer, or long) arguments are given. Number of Arguments 1 2 4 Description A single size to snap bot the X and Y grids to. X and Y sizes to snap the grid to. X, Y sizes and the corresponding X, Y origins.
transform transform(srid=4326, **kwargs) Availability: PostGIS, Oracle, SpatiaLite The transform method transforms the geometry eld of a model to the spatial reference system specied by the srid parameter. If no srid is given, then 4326 (WGS84) is used by default. Note: Unlike other GeoQuerySet methods, transform stores its output in-place. In other words, no new attribute for the transformed geometry is placed on the models. Note: What spatial reference system an integer SRID corresponds to may depend on the spatial database used. In other words, the SRID numbers used for Oracle are not necessarily the same as those used by PostGIS. Example:
>>> qs = Zipcode.objects.all().transform() # Transforms to WGS84 >>> qs = Zipcode.objects.all().transform(32140) # Transforming to "NAD83 / Texas South Central" >>> print qs[0].poly.srid 32140 >>> print qs[0].poly POLYGON ((234055.1698884720099159 4937796.9232223574072123 ...
translate translate(x, y, z=0.0, **kwargs) Availability: PostGIS, SpatiaLite Translates the geometry eld to a new location using the given numeric parameters as offsets.
49.9. GeoDjango
553
Geometry Operations
Availability: PostGIS, Oracle, SpatiaLite The following methods all take a geometry as a parameter and attach a geometry to each element of the GeoQuerySet that is the result of the operation. difference difference(geom) Returns the spatial difference of the geographic eld with the given geometry in a difference attribute on each element of the GeoQuerySet. intersection intersection(geom) Returns the spatial intersection of the geographic eld with the given geometry in an intersection attribute on each element of the GeoQuerySet. sym_difference sym_difference(geom) Returns the symmetric difference of the geographic eld with the given geometry in a sym_difference attribute on each element of the GeoQuerySet. union union(geom) Returns the union of the geographic eld with the given geometry in an union attribute on each element of the GeoQuerySet.
Geometry Output
The following GeoQuerySet methods will return an attribute that has the value of the geometry eld in each model converted to the requested output format. geohash geohash(preceision=20, **kwargs) New in version 1.2: Please, see the release notes Attaches a geohash attribute to every model the the queryset containing the GeoHash representation of the geometry. geojson geojson(**kwargs) New in version 1.1: Please, see the release notes Availability: PostGIS Attaches a geojson attribute to every model in the queryset that contains the GeoJSON representation of the geometry.
554
Description It may be used to specify the number of signicant digits for the coordinates in the GeoJSON representation the default value is 8. Set this to True if you want the coordinate reference system to be included in the returned GeoJSON. Set this to True if you want the bounding box to be included in the returned GeoJSON.
gml gml(**kwargs) Availability: PostGIS, Oracle Attaches a gml attribute to every model in the queryset that contains the Geographic Markup Language (GML) representation of the geometry. Example:
>>> qs = Zipcode.objects.all().gml() >>> print qs[0].gml <gml:Polygon srsName="EPSG:4326"><gml:OuterBoundaryIs>-147.78711,70.245363 ...
-147.78711,70.245363<
Description This keyword is for PostGIS only. It may be used to specify the number of signicant digits for the coordinates in the GML representation the default value is 8. This keyword is for PostGIS only. It may be used to specify the GML version used, and may only be values of 2 or 3. The default value is 2.
kml kml(**kwargs) Availability: PostGIS Attaches a kml attribute to every model in the queryset that contains the Keyhole Markup Language (KML) representation of the geometry elds. It should be noted that the contents of the KML are transformed to WGS84 if necessary. Example:
Description This keyword may be used to specify the number of signicant digits for the coordinates in the KML representation the default value is 8.
svg svg(**kwargs) Availability: PostGIS, SpatiaLite Attaches a svg attribute to every model in the queryset that contains the Scalable Vector Graphics (SVG) path data of the geometry elds.
49.9. GeoDjango
555
Description If set to True, the path data will be implemented in terms of relative moves. Defaults to False, meaning that absolute moves are used instead. This keyword may be used to specify the number of signicant digits for the coordinates in the SVG representation the default value is 8.
Miscellaneous
mem_size mem_size(**kwargs) Availability: PostGIS Returns the memory size (number of bytes) that the geometry eld takes in a mem_size attribute on each element of the GeoQuerySet. num_geom num_geom(**kwargs) Availability: PostGIS, Oracle, SpatiaLite Returns the number of geometries in a num_geom attribute on each element of the GeoQuerySet if the geometry eld is a collection (e.g., a GEOMETRYCOLLECTION or MULTI* eld); otherwise sets with None. num_points num_points(**kwargs) Availability: PostGIS, Oracle, SpatiaLite Returns the number of points in the rst linestring in the geometry eld in a num_points attribute on each element of the GeoQuerySet; otherwise sets with None. Spatial Aggregates New in version 1.1: Please, see the release notes
Aggregate Methods
collect collect(**kwargs) New in version 1.1: Please, see the release notes Availability: PostGIS Returns a GEOMETRYCOLLECTION or a MULTI geometry object from the geometry column. This is analagous to a simplied version of the GeoQuerySet.unionagg() method, except it can be several orders of magnitude faster than peforming a union because it simply rolls up geometries into a collection or multi object, not caring about dissolving boundaries. extent extent(**kwargs) Availability: PostGIS, Oracle Returns the extent of the GeoQuerySet as a four-tuple, comprising the lower left coordinate and the upper right coordinate.
556
Example:
>>> qs = City.objects.filter(name__in=(Houston, Dallas)) >>> print qs.extent() (-96.8016128540039, 29.7633724212646, -95.3631439208984, 32.782058715820)
extent3d extent3d(**kwargs) New in version 1.2: Please, see the release notes Availability: PostGIS Returns the 3D extent of the GeoQuerySet as a six-tuple, comprising the lower left coordinate and upper right coordinate. Example:
>>> qs = City.objects.filter(name__in=(Houston, Dallas)) >>> print qs.extent3d() (-96.8016128540039, 29.7633724212646, 0, -95.3631439208984, 32.782058715820, 0)
make_line make_line(**kwargs) Availability: PostGIS Returns a LineString constructed from the point eld geometries in the GeoQuerySet. Currently, ordering the queryset has no effect. Example:
>>> print City.objects.filter(name__in=(Houston, Dallas)).make_line() LINESTRING (-95.3631510000000020 29.7633739999999989, -96.8016109999999941 32.7820570000000018)
unionagg unionagg(**kwargs) Availability: PostGIS, Oracle, SpatiaLite This method returns a GEOSGeometry object comprising the union of every geometry in the queryset. Please note that use of unionagg is processor intensive and may take a signicant amount of time on large querysets. Note: If the computation time for using this method is too expensive, consider using GeoQuerySet.collect() instead. Example:
>>> u = Zipcode.objects.unionagg() # This may take a long time. >>> u = Zipcode.objects.filter(poly__within=bbox).unionagg() # A more sensible approach.
Description This keyword is for Oracle only. It is for the tolerance value used by the SDOAGGRTYPE procedure; the Oracle documentation has more details.
49.9. GeoDjango
557
Aggregate Functions
Example:
>>> from django.contrib.gis.db.models import Extent, Union >>> WorldBorders.objects.aggregate(Extent(mpoly), Union(mpoly))
Collect class Collect(geo_eld) Returns the same as the GeoQuerySet.collect() aggregate method. Extent class Extent(geo_eld) Returns the same as the GeoQuerySet.extent() aggregate method. Extent3D class Extent3D(geo_eld) New in version 1.2: Please, see the release notes Returns the same as the GeoQuerySet.extent3d() aggregate method. MakeLine class MakeLine(geo_eld) Returns the same as the GeoQuerySet.make_line() aggregate method. Union class Union(geo_eld) Returns the same as the GeoQuerySet.union() aggregate method.
28 Robert Coup is the initial author of the measure objects, and was inspired by Brian Becks work in geopy and Geoff Biggs PhD work on dimensioned units for robotics.
558
Conversions are easy, just access the preferred unit attribute to get a converted distance quantity:
>>> print d1.mi # Converting 5 kilometers to miles 3.10685596119 >>> print d2.km # Converting 5 miles to kilometers 8.04672
Two Distance objects multiplied together will yield an Area object, which uses squared units of measure:
>>> a = d1 * d2 # Returns an Area object. >>> print a 40.2336 sq_km
To determine what the attribute abbreviation of a unit is, the unit_attname class method may be used:
>>> print Distance.unit_attname(US Survey Foot) survey_ft >>> print Distance.unit_attname(centimeter) cm
Supported units Unit Attribute km mi m yd ft survey_ft inch cm mm um british_ft british_yd british_chain_sears indian_yd sears_yd clarke_ft chain chain_benoit chain_sears british_chain_benoit british_chain_sears_truncated gold_coast_ft link Full name or alias(es) Kilometre, Kilometer Mile Meter, Metre Yard Foot, Foot (International) U.S. Foot, US survey foot Inches Centimeter Millimetre, Millimeter Micrometer, Micrometre British foot (Sears 1922) British yard (Sears 1922) British chain (Sears 1922) Indian yard, Yard (Indian) Yard (Sears) Clarkes Foot Chain Chain (Benoit) Chain (Sears) British chain (Benoit 1895 B) British chain (Sears 1922 truncated) Gold Coast foot Link Continued on next page 559
49.9. GeoDjango
Table 49.3 continued from previous page Link (Benoit) Link (Sears) Clarkes link Fathom Rod Nautical Mile Nautical Mile (UK) German legal metre
Note: Area attributes are the same as Distance attributes, except they are prexed with sq_ (area units are square in nature). For example, Area(sq_m=2) creates an Area object representing two square meters. Measurement API
Distance
class Distance(**kwargs) To initialize a distance object, pass in a keyword corresponding to the desired unit attribute name set with desired value. For example, the following creates a distance object representing 5 miles:
>>> dist = Distance(mi=5)
__getattr__(unit_att) Returns the distance value in units corresponding to the given unit attribute. For example:
>>> print dist.km 8.04672
class unit_attname(unit_name) Returns the distance unit attribute name for the given full unit name. For example:
>>> Distance.unit_attname(Mile) mi
Area
class Area(**kwargs) To initialize a distance object, pass in a keyword corresponding to the desired unit attribute name set with desired value. For example, the following creates a distance object representing 5 square miles:
>>> a = Area(sq_mi=5)
__getattr__(unit_att) Returns the area value in units corresponding to the given unit attribute. For example:
560
class unit_attname(unit_name) Returns the area unit attribute name for the given full unit name. For example:
>>> Area.unit_attname(Kilometer) sq_km
What is GEOS?
GEOS stands for Geometry Engine - Open Source, and is a C++ library, ported from the Java Topology Suite. GEOS implements the OpenGIS Simple Features for SQL spatial predicate functions and spatial operators. GEOS, now an OSGeo project, was initially developed and maintained by Refractions Research of Victoria, Canada.
Features
GeoDjango implements a high-level Python wrapper for the GEOS library, its features include: A BSD-licensed interface to the GEOS geometry routines, implemented purely in Python using ctypes. Loosely-coupled to GeoDjango. For example, GEOSGeometry objects may be used outside of a django project/application. In other words, no need to have DJANGO_SETTINGS_MODULE set or use a database, etc. Mutability: GEOSGeometry objects may be modied. Cross-platform and tested; compatible with Windows, Linux, Solaris, and Mac OS X platforms. Tutorial This section contains a brief introduction and tutorial to using GEOSGeometry objects.
Creating a Geometry
GEOSGeometry objects may be created in a few ways. The rst is to simply instantiate the object on some spatial input the following are examples of creating the same geometry from WKT, HEX, WKB, and GeoJSON:
>>> >>> >>> >>> >>>
from django.contrib.gis.geos import GEOSGeometry pnt = GEOSGeometry(POINT(5 23)) # WKT pnt = GEOSGeometry(010100000000000000000014400000000000003740) # HEX pnt = GEOSGeometry(buffer(\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14@\x00\x00\x00\x00\x00\ pnt = GEOSGeometry({ "type": "Point", "coordinates": [ 5.000000, 23.000000 ] }) # GeoJSON
49.9. GeoDjango
561
Another option is to use the constructor for the specic geometry type that you wish to create. For example, a Point object may be created by passing in the X and Y coordinates into its constructor:
>>> from django.contrib.gis.geos import Point >>> pnt = Point(5, 23)
Finally, there are fromstr() and fromfile() factory methods, which return a GEOSGeometry object from an input string or a le:
>>> >>> >>> >>> from django.contrib.gis.geos import fromstr, fromfile pnt = fromstr(POINT(5 23)) pnt = fromfile(/path/to/pnt.wkt) pnt = fromfile(open(/path/to/pnt.wkt))
With any geometry object, the GEOSGeometry.coords property may be used to get the geometry coordinates as a Python tuple:
>>> pnt.coords (5.0, 23.0)
You can get/set geometry components using standard Python indexing techniques. However, what is returned depends on the geometry type of the object. For example, indexing on a LineString returns a coordinate tuple:
>>> from django.contrib.gis.geos import LineString >>> line = LineString((0, 0), (0, 50), (50, 50), (50, 0), (0, 0)) >>> line[0] (0.0, 0.0) >>> line[-2] (50.0, 0.0)
Whereas indexing on a Polygon will return the ring (a LinearRing object) corresponding to the index:
>>> from django.contrib.gis.geos import Polygon >>> poly = Polygon( ((0.0, 0.0), (0.0, 50.0), (50.0, 50.0), (50.0, 0.0), (0.0, 0.0)) ) >>> poly[0] <LinearRing object at 0x1044395b0> >>> poly[0][-2] # second-to-last coordinate of external ring (50.0, 0.0)
In addition, coordinates/components of the geometry may added or modied, just like a Python list:
>>> line[0] = (1.0, 1.0) >>> line.pop() (0.0, 0.0) >>> line.append((1.0, 1.0))
562
>>> line.coords ((1.0, 1.0), (0.0, 50.0), (50.0, 50.0), (50.0, 0.0), (1.0, 1.0))
Geometry Objects
GEOSGeometry
class GEOSGeometry(geo_input, [srid=None]) Parameters geo_input (string or buffer) Geometry input value srid (integer) spatial reference identier This is the base class for all GEOS geometry objects. It initializes on the given geo_input argument, and then assumes the proper geometry subclass (e.g., GEOSGeometry(POINT(1 1)) will create a Point object). The following input formats, along with their corresponding Python types, are accepted: Format WKT / EWKT HEX / HEXEWKB WKB / EWKB GeoJSON Input Type str or unicode str or unicode buffer str or unicode
Properties coords Returns the coordinates of the geometry as a tuple. empty Returns whether or not the set of points in the geometry is empty. geom_type Returns a string corresponding to the type of geometry. For example:
>>> pnt = GEOSGeometry(POINT(5 23)) >>> pnt.geom_type Point
geom_typeid Returns the GEOS geometry type identication number. The following table shows the value for each geometry type: Geometry Point LineString LinearRing Polygon MultiPoint MultiLineString MultiPolygon GeometryCollection num_coords Returns the number of coordinates in the geometry. 49.9. GeoDjango 563 ID 0 1 2 3 4 5 6 7
num_geom Returns the number of geometries in this geometry. In other words, will return 1 on anything but geometry collections. hasz Returns a boolean indicating whether the geometry is three-dimensional. ring Returns a boolean indicating whether the geometry is a LinearRing. simple Returns a boolean indicating whether the geometry is simple. A geometry is simple if and only if it does not intersect itself (except at boundary points). For example, a LineString object is not simple if it intersects itself. Thus, LinearRing and :classPolygon objects are always simple because they do cannot intersect themselves, by denition. valid Returns a boolean indicating whether the geometry is valid. srid Property that may be used to retrieve or set the SRID associated with the geometry. For example:
>>> pnt = Point(5, 23) >>> print pnt.srid None >>> pnt.srid = 4326 >>> pnt.srid 4326
Output Properties The properties in this section export the GEOSGeometry object into a different. This output may be in the form of a string, buffer, or even another object. ewkt Returns the extended Well-Known Text of the geometry. This representation is specic to PostGIS and is a super set of the OGC WKT standard. 29 Essentially the SRID is prepended to the WKT representation, for example SRID=4326;POINT(5 23). Note: The output from this property does not include the 3dm, 3dz, and 4d information that PostGIS supports in its EWKT representations. hex Returns the WKB of this Geometry in hexadecimal form. Please note that the SRID and Z values are not included in this representation because it is not a part of the OGC specication (use the GEOSGeometry.hexewkb property instead). hexewkb New in version 1.2: Please, see the release notes Returns the EWKB of this Geometry in hexadecimal form. This is an extension of the WKB specication that includes SRID and Z values that are a part of this geometry. Note: GEOS 3.1 is required if you want valid 3D HEXEWKB. json
29
See PostGIS EWKB, EWKT and Canonical Forms, PostGIS documentation at Ch. 4.1.2.
564
Returns the GeoJSON representation of the geometry. Note: Requires GDAL. geojson Alias for GEOSGeometry.json. kml Returns a KML (Keyhole Markup Language) representation of the geometry. This should only be used for geometries with an SRID of 4326 (WGS84), but this restriction is not enforced. ogr Returns an OGRGeometry object correspondg to the GEOS geometry. Note: Requires GDAL. wkb Returns the WKB (Well-Known Binary) representation of this Geometry as a Python buffer. SRID and Z values are not included, use the GEOSGeometry.ewkb property instead. ewkb New in version 1.2: Please, see the release notes Return the EWKB representation of this Geometry as a Python buffer. This is an extension of the WKB specication that includes any SRID and Z values that are a part of this geometry. Note: GEOS 3.1 is required if you want valid 3D EWKB. wkt Returns the Well-Known Text of the geometry (an OGC standard). Spatial Predicate Methods All of the following spatial predicate methods take another GEOSGeometry instance (other) as a parameter, and return a boolean. contains(other) Returns True if GEOSGeometry.within() is False. crosses(other) Returns True if the DE-9IM intersection matrix for the two Geometries is T*T****** (for a point and a curve,a point and an area or a line and an area) 0******** (for two curves). disjoint(other) Returns True if the DE-9IM intersection matrix for the two geometries is FF*FF****. equals(other) Returns True if the DE-9IM intersection matrix for the two geometries is T*F**FFF*. equals_exact(other, tolerance=0) Returns true if the two geometries are exactly equal, up to a specied tolerance. The tolerance value should be a oating point number representing the error tolerance in the comparison, e.g., poly1.equals_exact(poly2, 0.001) will compare equality to within one thousandth of a unit. intersects(other) Returns True if GEOSGeometry.disjoint() is False. overlaps(other)
49.9. GeoDjango
565
Returns true if the DE-9IM intersection matrix for the two geometries is T*T***T** (for two points or two surfaces) 1*T***T** (for two curves). relate_pattern(other, pattern) Returns True if the elements in the DE-9IM intersection matrix for this geometry and the other matches the given pattern a string of nine characters from the alphabet: {T, F, *, 0}. touches(other) Returns True if the DE-9IM intersection matrix for the two geometries is FT*******, F**T***** or F***T****. within(other) Returns True if the DE-9IM intersection matrix for the two geometries is T*F**F***. Topological Methods buffer(width, quadsegs=8) Returns a GEOSGeometry that represents all points whose distance from this geometry is less than or equal to the given width. The optional quadsegs keyword sets the number of segments used to approximate a quarter circle (defaults is 8). difference(other) Returns a GEOSGeometry representing the points making up this geometry that do not make up other. GEOSGeometry:intersection(other)() Returns a GEOSGeometry representing the points shared by this geometry and other. relate(other) Returns the DE-9IM intersection matrix (a string) representing the topological relationship between this geometry and the other. simplify(tolerance=0.0, preserve_topology=False) Returns a new GEOSGeometry, simplied using the Douglas-Peucker algorithm to the specied tolerance. A higher tolerance value implies less points in the output. If no tolerance is tolerance provided, it defaults to 0. By default, this function does not preserve topology - e.g., Polygon objects can be split, collapsed into lines or disappear. Polygon holes can be created or disappear, and lines can cross. By specifying preserve_topology=True, the result will have the same dimension and number of components as the input, however, this is signicantly slower. sym_difference(other) Returns a GEOSGeometry combining the points in this geometry not in other, and the points in other not in this geometry. union(other) Returns a GEOSGeometry representing all the points in this geometry and the other. Topological Properties boundary Returns the boundary as a newly allocated Geometry object. centroid Returns a Point object representing the geometric center of the geometry. The point is not guaranteed to be on the interior of the geometry.
566
convex_hull Returns the smallest Polygon that contains all the points in the geometry. envelope Returns a Polygon that represents the bounding envelope of this geometry. point_on_surface Computes and returns a Point guaranteed to be on the interior of this geometry. Other Properties & Methods area This property returns the area of the Geometry. extent This property returns the extent of this geometry as a 4-tuple, consisting of (xmin, ymin, xmax, ymax). clone() This method returns a GEOSGeometry that is a clone of the original. distance(geom) Returns the distance between the closest points on this geometry and the given geom (another GEOSGeometry object). Note: GEOS distance calculations are linear in other words, GEOS does not perform a spherical calculation even if the SRID species a geographic coordinate system. length Returns the length of this geometry (e.g., 0 for a Point, the length of a LineString, or the circumference of a Polygon). prepared New in version 1.1: Please, see the release notes Note: Support for prepared geometries requires GEOS 3.1. Returns a GEOS PreparedGeometry for the contents of this geometry. PreparedGeometry objects are optimized for the contains, intersects, and covers operations. Refer to the Prepared Geometries documentation for more information. srs Returns a SpatialReference object corresponding to the SRID of the geometry or None. Note: Requires GDAL. transform(ct, clone=False) Transforms the geometry according to the given coordinate transformation paramter (ct), which may be an integer SRID, spatial reference WKT string, a PROJ.4 string, a SpatialReference object, or a CoordTransform object. By default, the geometry is transformed in-place and nothing is returned. However if the clone keyword is set, then the geometry is not modied and a transformed clone of the geometry is returned instead. Note: Requires GDAL.
49.9. GeoDjango
567
Point
class Point(x, y, z=None, srid=None) Point objects are instantiated using arguments that represent the component coordinates of the point or with a single sequence coordinates. For example, the following are equivalent:
>>> pnt = Point(5, 23) >>> pnt = Point([5, 23])
LineString
class LineString(*args, **kwargs) LineString objects are instantiated using arguments that are either a sequence of coordinates or Point objects. For example, the following are equivalent:
>>> ls = LineString((0, 0), (1, 1)) >>> ls = LineString(Point(0, 0), Point(1, 1))
In addition, LineString objects may also be created by passing in a single sequence of coordinate or Point objects:
>>> ls = LineString( ((0, 0), (1, 1)) ) >>> ls = LineString( [Point(0, 0), Point(1, 1)] )
LinearRing
class LinearRing(*args, **kwargs) LinearRing objects are constructed in the exact same way as LineString objects, however the coordinates must be closed, in other words, the rst coordinates must be the same as the last coordinates. For example:
>>> ls = LinearRing((0, 0), (0, 1), (1, 1), (0, 0))
Notice that (0, 0) is the rst and last coordinate if they were not equal, an error would be raised.
Polygon
class Polygon(*args, **kwargs) Polygon objects may be instantiated by passing in one or more parameters that represent the rings of the polygon. The parameters must either be LinearRing instances, or a sequence that may be used to construct a LinearRing:
>>> >>> >>> >>> ext_coords = ((0, 0), (0, 1), (1, 1), (1, 0), (0, 0)) int_coords = ((0.4, 0.4), (0.4, 0.6), (0.6, 0.6), (0.6, 0.4), (0.4, 0.4)) poly = Polygon(ext_coords, int_coords) poly = Polygon(LinearRing(ext_coords), LinearRing(int_coords))
class from_bbox(bbox) New in version 1.1: Please, see the release notes Returns a polygon object from the given bounding-box, a 4-tuple comprising (xmin, ymin, xmax, ymax).
568
num_interior_rings Returns the number of interior rings in this geometry. Geometry Collections
MultiPoint
class MultiPoint(*args, **kwargs) MultiPoint objects may be instantiated by passing in one or more Point objects as arguments, or a single sequence of Point objects:
>>> mp = MultiPoint(Point(0, 0), Point(1, 1)) >>> mp = MultiPoint( (Point(0, 0), Point(1, 1)) )
MultiLineString
class MultiLineString(*args, **kwargs) MultiLineString objects may be instantiated by passing in one or more LineString objects as arguments, or a single sequence of LineString objects:
>>> >>> >>> >>> ls1 ls2 mls mls = = = = LineString((0, 0), (1, 1)) LineString((2, 2), (3, 3)) MultiLineString(ls1, ls2) MultiLineString([ls1, ls2])
merged New in version 1.1: Please, see the release notes Returns a LineString representing the line merge of all the components in this MultiLineString.
MultiPolygon
class MultiPolygon(*args, **kwargs) MultiPolygon objects may be instantiated by passing one or more Polygon objects as arguments, or a single sequence of Polygon objects:
>>> >>> >>> >>> p1 p2 mp mp = = = = Polygon( ((0, 0), (0, 1), (1, 1), (0, 0)) ) Polygon( ((1, 1), (1, 2), (2, 2), (1, 1)) ) MultiPolygon(p1, p2) MultiPolygon([p1, p2])
cascaded_union New in version 1.1: Please, see the release notes Returns a Polygon that is the union of all of the component polygons in this collection. The algorithm employed is signicantly more efcient (faster) than trying to union the geometries together individually. 30 Note: GEOS 3.1 is required to peform cascaded unions.
30 For more information, read Paul Ramseys blog post about (Much) Faster Unions in PostGIS 1.4 and Martin Davis blog post on Fast polygon merging in JTS using Cascaded Union.
49.9. GeoDjango
569
GeometryCollection
class GeometryCollection(*args, **kwargs) GeometryCollection objects may be instantiated by passing in one or more other GEOSGeometry as arguments, or a single sequence of GEOSGeometry objects:
>>> poly = Polygon( ((0, 0), (0, 1), (1, 1), (0, 0)) ) >>> gc = GeometryCollection(Point(0, 0), MultiPoint(Point(0, 0), Point(1, 1)), poly) >>> gc = GeometryCollection((Point(0, 0), MultiPoint(Point(0, 0), Point(1, 1)), poly))
Prepared Geometries In order to obtain a prepared geometry, just access the GEOSGeometry.prepared property. Once you have a PreparedGeometry instance its spatial predicate methods, listed below, may be used with other GEOSGeometry objects. An operation with a prepared geometry can be orders of magnitude faster the more complex the geometry that is prepared, the larger the speedup in the operation. For more information, please consult the GEOS wiki page on prepared geometries. Note: GEOS 3.1 is required in order to use prepared geometries. For example:
>>> from django.contrib.gis.geos import Point, Polygon >>> poly = Polygon.from_bbox((0, 0, 5, 5)) >>> prep_poly = poly.prepared >>> prep_poly.contains(Point(2.5, 2.5)) True
PreparedGeometry
class PreparedGeometry() All methods on PreparedGeometry take an other argument, which must be a GEOSGeometry instance. contains(other) contains_properly(other) covers(other) intersects(other) Geometry Factories fromfile(le_h) Parameter le_h (a Python file object or a string path to the le) input le that contains spatial data Return type a GEOSGeometry corresponding to the spatial data in the le Example:
>>> from django.contrib.gis.geos import fromfile >>> g = fromfile(/home/bob/geom.wkt)
570
fromstr(string, [srid=None]) Parameters string (string) string that contains spatial data srid (integer) spatial reference identier Return type a GEOSGeometry corresponding to the spatial data in the string Example:
>>> from django.contrib.gis.geos import fromstr >>> pnt = fromstr(POINT(-90.5 29.5), srid=4326)
I/O Objects
Reader Objects
The reader I/O classes simply return a GEOSGeometry instance from the WKB and/or WKT input given to their read(geom) method. class WKBReader() Example:
>>> from django.contrib.gis.geos import WKBReader >>> wkb_r = WKBReader() >>> wkb_r.read(0101000000000000000000F03F000000000000F03F) <Point object at 0x103a88910>
Writer Objects
All writer objects have a write(geom) method that returns either the WKB or WKT of the given geometry. In addition, WKBWriter objects also have properties that may be used to change the byte order, and or include the SRID and 3D values (in other words, EWKB). class WKBWriter() WKBWriter provides the most control over its output. By default it returns OGC-compliant WKB when its write method is called. However, it has properties that allow for the creation of EWKB, a superset of the WKB standard that includes additional information. write(geom) Returns the WKB of the given geometry as a Python buffer object. Example:
49.9. GeoDjango
571
>>> from django.contrib.gis.geos import Point, WKBWriter >>> pnt = Point(1, 1) >>> wkb_w = WKBWriter() >>> wkb_w.write(pnt) <read-only buffer for 0x103a898f0, size -1, offset 0 at 0x103a89930>
byteorder This property may be be set to change the byte-order of the geometry representation. Byteorder Value 0 1 Example:
>>> from django.contrib.gis.geos import Point, WKBWriter >>> wkb_w = WKBWriter() >>> pnt = Point(1, 1) >>> wkb_w.write_hex(pnt) 0101000000000000000000F03F000000000000F03F >>> wkb_w.byteorder = 0 00000000013FF00000000000003FF0000000000000
Description Big Endian (e.g., compatible with RISC systems) Little Endian (e.g., compatible with x86 systems)
outdim This property may be set to change the output dimension of the geometry representation. In other words, if you have a 3D geometry then set to 3 so that the Z value is included in the WKB. Outdim Value 2 3 Example:
>>> from django.contrib.gis.geos import Point, WKBWriter >>> wkb_w = WKBWriter() >>> wkb_w.outdim 2 >>> pnt = Point(1, 1, 1) >>> wkb_w.write_hex(pnt) # By default, no Z value included: 0101000000000000000000F03F000000000000F03F >>> wkb_w.outdim = 3 # Tell writer to include Z values >>> wkb_w.write_hex(pnt) 0101000080000000000000F03F000000000000F03F000000000000F03F
srid
572
Set this property with a boolean to indicate whether the SRID of the geometry should be included with the WKB representation. Example:
>>> from django.contrib.gis.geos import Point, WKBWriter >>> wkb_w = WKBWriter() >>> pnt = Point(1, 1, srid=4326) >>> wkb_w.write_hex(pnt) # By default, no SRID included: 0101000000000000000000F03F000000000000F03F >>> wkb_w.srid = True # Tell writer to include SRID >>> wkb_w.write_hex(pnt) 0101000020E6100000000000000000F03F000000000000F03F
class WKTWriter() write(geom) Returns the WKT of the given geometry. Example:
>>> from django.contrib.gis.geos import Point, WKTWriter >>> pnt = Point(1, 1) >>> wkt_w = WKTWriter() >>> wkt_w.write(pnt) POINT (1.0000000000000000 1.0000000000000000)
Settings
GEOS_LIBRARY_PATH
A string specifying the location of the GEOS C library. Typically, this setting is only used if the GEOS C library is in a non-standard location (e.g., /home/bob/lib/libgeos_c.so). Note: The setting must be the full path to the C shared library; in other words you want to use libgeos_c.so, not libgeos.so.
Sample Data
The GDAL/OGR tools described here are designed to help you read in your geospatial data, in order for most of them to be useful you have to have some data to work with. If youre starting out and dont yet have any data of your own to use, GeoDjango comes with a number of simple data sets that you can use for testing. This snippet will determine where these sample les are installed on your computer: 49.9. GeoDjango 573
DataSource
DataSource is a wrapper for the OGR data source object that supports reading data from a variety of OGR-supported geospatial le formats and data sources using a simple, consistent interface. Each data source is represented by a DataSource object which contains one or more layers of data. Each layer, represented by a Layer object, contains some number of geographic features (Feature), information about the type of features contained in that layer (e.g. points, polygons, etc.), as well as the names and types of any additional elds (Field) of data that may be associated with each feature in that layer. class DataSource(ds_input) The constructor for DataSource just a single parameter: the path of the le you want to read. However, OGR also supports a variety of more complex data sources, including databases, that may be accessed by passing a special name string instead of a path. For more information, see the OGR Vector Formats documentation. The name property of a DataSource instance gives the OGR name of the underlying data source that it is using. Once youve created your DataSource, you can nd out how many layers of data it contains by accessing the layer_count property, or (equivalently) by using the len() function. For information on accessing the layers of data themselves, see the next section:
>>> from django.contrib.gis.gdal import DataSource >>> ds = DataSource(CITIES_PATH) >>> ds.name # The exact filename may be different on your computer /usr/local/lib/python2.6/site-packages/django/contrib/gis/tests/data/cities/cities.shp >>> ds.layer_count # This file only contains one layer 1
layer_count Returns the number of layers in the data source. name Returns the name of the data source.
Layer
class Layer() Layer is a wrapper for a layer of data in a DataSource object. You never create a Layer object directly. Instead, you retrieve them from a DataSource object, which is essentially a standard Python container of Layer objects. For example, you can access a specic layer by its index (e.g. ds[0] to access the rst layer), or you can iterate over all the layers in the container in a for loop. The Layer itself acts as a container for geometric features. Typically, all the features in a given layer have the same geometry type. The geom_type property of a layer is an OGRGeomType that identies the feature type. We can use it to print out some basic information about each layer in a DataSource:
574
>>> for layer in ds: ... print Layer "%s": %i %ss % (layer.name, len(layer), layer.geom_type.name) ... Layer "cities": 3 Points
The example output is from the cities data source, loaded above, which evidently contains one layer, called "cities", which contains three point features. For simplicity, the examples below assume that youve stored that layer in the variable layer:
>>> layer = ds[0]
num_fields Returns the number of elds in the layer, i.e the number of elds of data associated with each feature in the layer:
>>> layer.num_fields 4
fields Returns a list of the names of each of the elds in this layer:
>>> layer.fields [Name, Population, Density, Created]
Returns a list of the data types of each of the elds in this layer. These are subclasses of Field, discussed below:
>>> [ft.__name__ for ft in layer.field_types] [OFTString, OFTReal, OFTReal, OFTDate]
field_widths Returns a list of the maximum eld widths for each of the elds in this layer:
49.9. GeoDjango
575
field_precisions Returns a list of the numeric precisions for each of the elds in this layer. This is meaningless (and set to zero) for non-numeric elds:
>>> layer.field_precisions [0, 0, 15, 0]
srs Property that returns the SpatialReference associated with this layer:
>>> print layer.srs GEOGCS["GCS_WGS_1984", DATUM["WGS_1984", SPHEROID["WGS_1984",6378137,298.257223563]], PRIMEM["Greenwich",0], UNIT["Degree",0.017453292519943295]]
If the Layer has no spatial reference information associated with it, None is returned. spatial_filter New in version 1.2: Please, see the release notes Property that may be used to retrieve or set a spatial lter for this layer. A spatial lter can only be set with an OGRGeometry instance, a 4-tuple extent, or None. When set with something other than None, only features that intersect the lter will be returned when iterating over the layer:
>>> print layer.spatial_filter None >>> print len(layer) 3 >>> [feat.get(Name) for feat in layer] [Pueblo, Lawrence, Houston] >>> ks_extent = (-102.051, 36.99, -94.59, 40.00) # Extent for state of Kansas >>> layer.spatial_filter = ks_extent >>> len(layer) 1 >>> [feat.get(Name) for feat in layer] [Lawrence] >>> layer.spatial_filter = None >>> len(layer) 3
get_fields() A method that returns a list of the values of a given eld for each feature in the layer:
576
get_geoms([geos=False]) A method that returns a list containing the geometry of each feature in the layer. If the optional argument geos is set to True then the geometries are converted to GEOSGeometry objects. Otherwise, they are returned as OGRGeometry objects:
>>> [pt.tuple for pt in layer.get_geoms()] [(-104.609252, 38.255001), (-95.23506, 38.971823), (-95.363151, 29.763374)]
test_capability(capability) Returns a boolean indicating whether this layer supports the given capability (a string). Examples of valid capability strings include: RandomRead, SequentialWrite, RandomWrite, FastSpatialFilter, FastFeatureCount, FastGetExtent, CreateField, Transactions, DeleteFeature, and FastSetNextByIndex.
Feature
class Feature() Feature wraps an OGR feature. You never create a Feature object directly. Instead, you retrieve them from a Layer object. Each feature consists of a geometry and a set of elds containing additional properties. The geometry of a eld is accessible via its geom property, which returns an OGRGeometry object. A Feature behaves like a standard Python container for its elds, which it returns as Field objects: you can access a eld directly by its index or name, or you can iterate over a features elds, e.g. in a for loop. geom Returns the geometry for this feature, as an OGRGeometry object:
>>> city.geom.tuple (-104.609252, 38.255001)
get A method that returns the value of the given eld (specied by name) for this feature, not a Field wrapper object:
>>> city.get(Population) 102121
geom_type Returns the type of geometry for this feature, as an OGRGeomType object. This will be the same for all features in a given layer, and is equivalent to the Layer.geom_type property of the Layer object the feature came from. num_fields Returns the number of elds of data associated with the feature. This will be the same for all features in a given layer, and is equivalent to the Layer.num_fields property of the Layer object the feature came from. fields
49.9. GeoDjango
577
Returns a list of the names of the elds of data associated with the feature. This will be the same for all features in a given layer, and is equivalent to the Layer.fields property of the Layer object the feature came from. fid Returns the feature identier within the layer:
>>> city.fid 0
layer_name Returns the name of the Layer that the feature came from. This will be the same for all features in a given layer:
>>> city.layer_name cities
index A method that returns the index of the given eld name. This will be the same for all features in a given layer:
>>> city.index(Population) 1
Field
class Field() name Returns the name of this eld:
>>> city[Name].name Name
type Returns the OGR type of this eld, as an integer. The FIELD_CLASSES dictionary maps these values onto subclasses of Field:
>>> city[Density].type 2
type_name Returns a string with the name of the data type of this eld:
>>> city[Name].type_name String
value Returns the value of this eld. The Field class itself returns the value as a string, but each subclass returns the value in the most appropriate form:
578
precision Returns the numeric precision of this eld. This is meaningless (and set to zero) for non-numeric elds:
>>> city[Density].precision 15
as_datetime() Returns the value of the eld as a tuple of date and time components:
>>> city[Created].as_datetime() (c_long(1999), c_long(5), c_long(23), c_long(0), c_long(0), c_long(0), c_long(0))
Driver
class Driver(dr_input) The Driver class is used internally to wrap an OGR DataSource driver. driver_count Returns the number of OGR vector drivers currently registered.
49.9. GeoDjango
579
OGR Geometries
OGRGeometry
OGRGeometry objects share similar functionality with GEOSGeometry objects, and are thin wrappers around OGRs internal geometry representation. Thus, they allow for more efcient access to data when using DataSource. Unlike its GEOS counterpart, OGRGeometry supports spatial reference systems and coordinate transformation:
>>> from django.contrib.gis.gdal import OGRGeometry >>> polygon = OGRGeometry(POLYGON((0 0, 5 0, 5 5, 0 5)))
class OGRGeometry(geom_input, [srs=None]) This object is a wrapper for the OGR Geometry class. These objects are instantiated directly from the given geom_input parameter, which may be a string containing WKT or HEX, a buffer containing WKB data, or an OGRGeomType object. These objects are also returned from the Feature.geom attribute, when reading vector data from Layer (which is in turn a part of a DataSource). class from_bbox(bbox) New in version 1.1: Please, see the release notes Constructs a Polygon from the given bounding-box (a 4-tuple). __len__() Returns the number of points in a LineString, the number of rings in a Polygon, or the number of geometries in a GeometryCollection. Not applicable to other geometry types. __iter__() Iterates over the points in a LineString, the rings in a Polygon, or the geometries in a GeometryCollection. Not applicable to other geometry types. __getitem__() Returns the point at the specied index for a LineString, the interior ring at the specied index for a Polygon, or the geometry at the specied index in a GeometryCollection. Not applicable to other geometry types. dimension Returns the number of coordinated dimensions of the geometry, i.e. 0 for points, 1 for lines, and so forth:
>> polygon.dimension 2
coord_dim Changed in version 1.2: Please, see the release notes Returns or sets the coordinate dimension of this geometry. For example, the value would be 2 for two-dimensional geometries. Note: Setting this property is only available in versions 1.2 and above. geom_count Returns the number of elements in this geometry:
>>> polygon.geom_count 1
point_count Returns the number of points used to describe this geometry: 580 Chapter 49. contrib packages
>>> polygon.point_count 4
num_points Alias for point_count. num_coords Alias for point_count. geom_type Returns the type of this geometry, as an OGRGeomType object. geom_name Returns the name of the type of this geometry:
>>> polygon.geom_name POLYGON
area Returns the area of this geometry, or 0 for geometries that do not contain an area:
>>> polygon.area 25.0
envelope Returns the envelope of this geometry, as an Envelope object. extent Returns the envelope of this geometry as a 4-tuple, instead of as an Envelope object:
>>> point.extent (0.0, 0.0, 5.0, 5.0)
srs This property controls the spatial reference for this geometry, or None if no spatial reference system has been assigned to it. If assigned, accessing this property returns a SpatialReference object. It may be set with another SpatialReference object, or any input that SpatialReference accepts. Example:
>>> city.geom.srs.name GCS_WGS_1984
srid Returns or sets the spatial reference identier corresponding to SpatialReference of this geometry. Returns None if there is no spatial reference information associated with this geometry, or if an SRID cannot be determined. geos Returns a GEOSGeometry object corresponding to this geometry. gml Returns a string representation of this geometry in GML format:
49.9. GeoDjango
581
kml New in version 1.1: Please, see the release notes Returns a string representation of this geometry in KML format. wkb_size Returns the size of the WKB buffer needed to hold a WKB representation of this geometry:
>>> OGRGeometry(POINT(1 2)).wkb_size 21
wkb Returns a buffer containing a WKB representation of this geometry. wkt Returns a string representation of this geometry in WKT format. ewkt New in version 1.2: Please, see the release notes Returns the EWKT representation of this geometry. clone() Returns a new OGRGeometry clone of this geometry object. close_rings() If there are any rings within this geometry that have not been closed, this routine will do so by adding the starting point to the end:
>>> triangle = OGRGeometry(LINEARRING (0 0,0 1,1 0)) >>> triangle.close_rings() >>> triangle.wkt LINEARRING (0 0,0 1,1 0,0 0)
transform(coord_trans, clone=False) Transforms this geometry to a different spatial reference system. May take a CoordTransform object, a SpatialReference object, or any other input accepted by SpatialReference (including spatial reference WKT and PROJ.4 strings, or an integer SRID). By default nothing is returned and the geometry is transformed in-place. However, if the clone keyword is set to True then a transformed clone of this geometry is returned instead. 582 Chapter 49. contrib packages
intersects(other) Returns True if this geometry intersects the other, otherwise returns False. equals(other) Returns True if this geometry is equivalent to the other, otherwise returns False. disjoint(other) Returns True if this geometry is spatially disjoint to (i.e. does not intersect) the other, otherwise returns False. touches(other) Returns True if this geometry touches the other, otherwise returns False. crosses(other) Returns True if this geometry crosses the other, otherwise returns False. within(other) Returns True if this geometry is contained within the other, otherwise returns False. contains(other) Returns True if this geometry contains the other, otherwise returns False. overlaps(other) Returns True if this geometry overlaps the other, otherwise returns False. boundary() The boundary of this geometry, as a new OGRGeometry object. convex_hull The smallest convex polygon that contains this geometry, as a new OGRGeometry object. difference() Returns the region consisting of the difference of this geometry and the other, as a new OGRGeometry object. intersection() Returns the region consisting of the intersection of this geometry and the other, as a new OGRGeometry object. sym_difference() Returns the region consisting of the symmetric difference of this geometry and the other, as a new OGRGeometry object. union() Returns the region consisting of the union of this geometry and the other, as a new OGRGeometry object. tuple Returns the coordinates of a point geometry as a tuple, the coordinates of a line geometry as a tuple of tuples, and so forth:
>>> OGRGeometry(POINT (1 2)).tuple (1.0, 2.0) >>> OGRGeometry(LINESTRING (1 2,3 4)).tuple ((1.0, 2.0), (3.0, 4.0))
49.9. GeoDjango
583
coords An alias for tuple. class Point() x Returns the X coordinate of this point:
>>> OGRGeometry(POINT (1 2)).x 1.0
z Returns the Z coordinate of this point, or None if the the point does not have a Z coordinate:
>>> OGRGeometry(POINT (1 2 3)).z 3.0
z Returns a list of Z coordinates in this line, or None if the line does not have Z coordinates:
>>> OGRGeometry(LINESTRING (1 2 3,4 5 6)).z [3.0, 6.0]
class Polygon() shell Returns the shell or exterior ring of this polygon, as a LinearRing geometry. exterior_ring An alias for shell.
584
centroid Returns a Point representing the centroid of this polygon. class GeometryCollection() add(geom) Adds a geometry to this geometry collection. Not applicable to other geometry types.
OGRGeomType
class OGRGeomType(type_input) This class allows for the representation of an OGR geometry type in any of several ways:
>>> from django.contrib.gis.gdal import OGRGeomType >>> gt1 = OGRGeomType(3) # Using an integer for the type >>> gt2 = OGRGeomType(Polygon) # Using a string >>> gt3 = OGRGeomType(POLYGON) # Its case-insensitive >>> print gt1 == 3, gt1 == Polygon # Equivalence works w/non-OGRGeomType objects True True
django Returns the Django eld type (a subclass of GeometryField) to use for storing this OGR type, or None if there is no appropriate Django type:
>>> gt1.django PolygonField
Envelope
class Envelope(*args) Represents an OGR Envelope structure that contains the minimum and maximum X, Y coordinates for a rectangle bounding box. The naming of the variables is compatible with the OGR Envelope C structure. min_x The value of the minimum X coordinate. min_y The value of the maximum X coordinate. 49.9. GeoDjango 585
max_x The value of the minimum Y coordinate. max_y The value of the maximum Y coordinate. ur The upper-right coordinate, as a tuple. ll The lower-left coordinate, as a tuple. tuple A tuple representing the envelope. wkt A string representing this envelope as a polygon in WKT format. expand_to_include(self, *args) New in version 1.1: Please, see the release notes Coordinate System Objects
SpatialReference
class SpatialReference(srs_input) Spatial reference objects are initialized on the given srs_input, which may be one of the following: OGC Well Known Text (WKT) (a string) EPSG code (integer or string) PROJ.4 string A shorthand string for well-known standards (WGS84, WGS72, NAD27, NAD83) Example:
>>> wgs84 = SpatialReference(WGS84) # shorthand string >>> wgs84 = SpatialReference(4326) # EPSG code >>> wgs84 = SpatialReference(EPSG:4326) # EPSG string >>> proj4 = +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs >>> wgs84 = SpatialReference(proj4) # PROJ.4 string >>> wgs84 = SpatialReference("""GEOGCS["WGS 84", DATUM["WGS_1984", SPHEROID["WGS 84",6378137,298.257223563, AUTHORITY["EPSG","7030"]], AUTHORITY["EPSG","6326"]], PRIMEM["Greenwich",0, AUTHORITY["EPSG","8901"]], UNIT["degree",0.01745329251994328, AUTHORITY["EPSG","9122"]], AUTHORITY["EPSG","4326"]]""") # OGC WKT
__getitem__(target)
586
Returns the value of the given string attribute node, None if the node doesnt exist. Can also take a tuple as a parameter, (target, child), where child is the index of the attribute in the WKT. For example:
>>> wkt = >>> srs = >>> print WGS 84 >>> print WGS_1984 >>> print EPSG >>> print 4326 >>> print 0 >>> print EPSG >>> print 9122 GEOGCS["WGS 84", DATUM["WGS_1984, ... AUTHORITY["EPSG","4326"]]) SpatialReference(wkt) # could also use WGS84, or 4326 srs[GEOGCS] srs[DATUM] srs[AUTHORITY] srs[AUTHORITY, 1] # The authority value srs[TOWGS84, 4] # the fourth value in this wkt srs[UNIT|AUTHORITY] # For the units authority, have to use the pipe symbole. srs[UNIT|AUTHORITY, 1] # The authority value for the untis
attr_value(target, index=0) The attribute value for the given target node (e.g. PROJCS). The index keyword species an index of the child node to return. auth_name(target) Returns the authority name for the given string target node. auth_code(target) Returns the authority code for the given string target node. clone() Returns a clone of this spatial reference object. identify_epsg() This method inspects the WKT of this SpatialReference, and will add EPSG authority nodes where an EPSG identier is applicable. from_esri() Morphs this SpatialReference from ESRIs format to EPSG to_esri() Morphs this SpatialReference to ESRIs format. validate() Checks to see if the given spatial reference is valid, if not an exception will be raised. import_epsg(epsg) Import spatial reference from EPSG code. import_proj(proj) Import spatial reference from PROJ.4 string. import_user_input(user_input) New in version 1.1: Please, see the release notes
49.9. GeoDjango
587
import_wkt(wkt) Import spatial reference from WKT. import_xml(xml) Import spatial reference from XML. name Returns the name of this Spatial Reference. srid Returns the SRID of top-level authority, or None if undened. linear_name Returns the name of the linear units. linear_units Returns the value of the linear units. angular_name Returns the name of the angular units. angular_units Returns the value of the angular units. units Returns a 2-tuple of the units value and the units name, and will automatically determines whether to return the linear or angular units. ellisoid Returns a tuple of the ellipsoid parameters for this spatial reference: (semimajor axis, semiminor axis, and inverse attening) semi_major Returns the semi major axis of the ellipsoid for this spatial reference. semi_minor Returns the semi minor axis of the ellipsoid for this spatial reference. inverse_flattening Returns the inverse attening of the ellipsoid for this spatial reference. geographic Returns True if this spatial reference is geographic (root node is GEOGCS). local Returns True if this spatial reference is local (root node is LOCAL_CS). projected Returns True if this spatial reference is a projected coordinate system (root node is PROJCS). wkt Returns the WKT representation of this spatial reference. pretty_wkt
588
Returns the pretty representation of the WKT. proj Returns the PROJ.4 representation for this spatial reference. proj4 Alias for SpatialReference.proj. xml Returns the XML representation of this spatial reference.
CoordTransform
class CoordTransform(source, target) Represents a coordinate system transform. It is initialized with two SpatialReference, representing the source and target coordinate systems, respectively. These objects should be used when performing the same coordinate transformation repeatedly on different geometries:
>>> ct = CoordTransform(SpatialReference(WGS84), SpatialReference(NAD83)) >>> for feat in layer: ... geom = feat.geom # getting clone of feature geometry ... geom.transform(ct) # transforming
Settings
GDAL_LIBRARY_PATH
A string specifying the location of the GDAL library. Typically, this setting is only used if the GDAL library is in a non-standard location (e.g., /home/john/lib/libgdal.so).
49.9. GeoDjango
589
Example
Assuming you have the GeoIP C library installed, here is an example of its usage:
>>> from django.contrib.gis.utils import GeoIP >>> g = GeoIP() >>> g.country(google.com) {country_code: US, country_name: United States} >>> g.city(72.14.207.99) {area_code: 650, city: Mountain View, country_code: US, country_code3: USA, country_name: United States, dma_code: 807, latitude: 37.419200897216797, longitude: -122.05740356445312, postal_code: 94043, region: CA} >>> g.lat_lon(salon.com) (37.789798736572266, -122.39420318603516) >>> g.lon_lat(uh.edu) (-95.415199279785156, 29.77549934387207) >>> g.geos(24.124.1.80).wkt POINT (-95.2087020874023438 39.0392990112304688)
GeoIP Settings
GEOIP_PATH A string specifying the directory where the GeoIP data les are located. This setting is required unless manually specied with path keyword when initializing the GeoIP object. GEOIP_LIBRARY_PATH A string specifying the location of the GeoIP C library. Typically, this setting is only used if the GeoIP C library is in a non-standard location (e.g., /home/sue/lib/libGeoIP.so). GEOIP_COUNTRY The basename to use for the GeoIP country data le. Defaults to GeoIP.dat. GEOIP_CITY The basename to use for the GeoIP city data le. Defaults to GeoLiteCity.dat.
GeoIP API
class GeoIP([path=None, cache=0, country=None, city=None]) The GeoIP object does not require any parameters to use the default settings. However, at the very least the GEOIP_PATH setting should be set with the path of the location of your GeoIP data sets. The following intialization keywords may be used to customize any of the defaults.
590
Description Base directory to where GeoIP data is located or the full path to where the city or country data les (.dat) are located. Assumes that both the city and country data sets are located in this directory; overrides the GEOIP_PATH settings attribute. The cache settings when opening up the GeoIP datasets, and may be an integer in (0, 1, 2, 4) corresponding to the GEOIP_STANDARD, GEOIP_MEMORY_CACHE, GEOIP_CHECK_CACHE, and GEOIP_INDEX_CACHE GeoIPOptions C API settings, respectively. Defaults to 0 (GEOIP_STANDARD). The name of the GeoIP country data le. Defaults to GeoIP.dat. Setting this keyword overrides the GEOIP_COUNTRY settings attribute. The name of the GeoIP city data le. Defaults to GeoLiteCity.dat. Setting this keyword overrides the GEOIP_CITY settings attribute.
cache
country city
GeoIP Methods
Querying All the following querying routines may take either a string IP address or a fully qualied domain name (FQDN). For example, both 24.124.1.80 and djangoproject.com would be valid query parameters. city(query) Returns a dictionary of city information for the given query. Some of the values in the dictionary may be undened (None). GeoIPcountry(query) Returns a dictionary with the country code and country for the given query. country_code(query) Returns only the country code corresponding to the query. country_name(query) Returns only the country name corresponding to the query. Coordinate Retrieval coords(query) Returns a coordinate tuple of (longitude, latitude). lon_lat(query) Returns a coordinate tuple of (longitude, latitude). lat_lon(query) Returns a coordinate tuple of (latitude, longitude), geos(query) Returns a django.contrib.gis.geos.Point object corresponding to the query. Database Information country_info This property returns information about the GeoIP country database. city_info This property returns information about the GeoIP city database.
49.9. GeoDjango
591
info This property returns information about all GeoIP databases (both city and country). GeoIP-Python API compatibility methods These methods exist to ease compatibility with any code using MaxMinds existing Python API. class open(path, cache) This classmethod instantiates the GeoIP object from the given database path and given cache setting. region_by_addr(query) region_by_name(query) record_by_addr(query) record_by_name(query) country_code_by_addr(query) country_code_by_name(query) country_name_by_addr(query) country_name_by_name(query) LayerMapping data import utility The LayerMapping class provides a way to map the contents of vector spatial data les (e.g. shapeles) intoto GeoDjango models. This utility grew out of the authors personal needs to eliminate the code repetition that went into pulling geometries and elds out of a vector layer, converting to another coordinate system (e.g. WGS84), and then inserting into a GeoDjango model. Note: Use of LayerMapping requires GDAL. Warning: GIS data sources, like shapeles, may be very large. If you nd that LayerMapping is using too much memory, set DEBUG to False in your settings. When DEBUG is set to True, Django automatically logs every SQL query thus, when SQL statements contain geometries, it is easy to consume more memory than is typical.
Example
1. You need a GDAL-supported data source, like a shapele (here were using a simple polygon shapele, test_poly.shp, with three features):
>>> from django.contrib.gis.gdal import DataSource >>> ds = DataSource(test_poly.shp) >>> layer = ds[0] >>> print layer.fields # Exploring the fields in the layer, we only want the str field. [float, int, str] >>> print len(layer) # getting the number of features in the layer (should be 3) 3 >>> print layer.geom_type # Should be Polygon Polygon
592
>>> print layer.srs # WGS84 in WKT GEOGCS["GCS_WGS_1984", DATUM["WGS_1984", SPHEROID["WGS_1984",6378137,298.257223563]], PRIMEM["Greenwich",0], UNIT["Degree",0.017453292519943295]]
2. Now we dene our corresponding Django model (make sure to use syncdb):
from django.contrib.gis.db import models class TestGeo(models.Model): name = models.CharField(max_length=25) # corresponds to the str field poly = models.PolygonField(srid=4269) # we want our model in a different SRID objects = models.GeoManager() def __unicode__(self): return Name: %s % self.name
3. Use LayerMapping to extract all the features and place them in the database:
>>> from django.contrib.gis.utils import LayerMapping >>> from geoapp.models import TestGeo >>> mapping = {name : str, # The name model field maps to the str layer field. poly : POLYGON, # For geometry fields use OGC name. } # The mapping is a dictionary >>> lm = LayerMapping(TestGeo, test_poly.shp, mapping) >>> lm.save(verbose=True) # Save the layermap, imports the data. Saved: Name: 1 Saved: Name: 2 Saved: Name: 3
Here, LayerMapping just transformed the three geometries from the shapele in their original spatial reference system (WGS84) to the spatial reference system of the GeoDjango model (NAD83). If no spatial reference system is dened for the layer, use the source_srs keyword with a SpatialReference object to specify one.
LayerMapping API
class LayerMapping(model, data_source, mapping, [layer=0, source_srs=None, encoding=None, transaction_mode=commit_on_success, transform=True, unique=True, using=default]) The following are the arguments and keywords that may be used during instantiation of LayerMapping objects. ArguDescription ment model The geographic model, not an instance. data_source The path to the OGR-supported data source le (e.g., a shapele). Also accepts django.contrib.gis.gdal.DataSource instances. mapping A dictionary: keys are strings corresponding to the model eld, and values correspond to string eld names for the OGR feature, or if the model eld is a geographic then it should correspond to the OGR geometry type, e.g., POINT, LINESTRING, POLYGON.
49.9. GeoDjango
593
Keyword Arguments layer The index of the layer to use from the Data Source (defaults to 0) source_srs Use this to specify the source SRS manually (for example, some shapeles dont come with a .prj le). An integer SRID, WKT or PROJ.4 strings, and django.contrib.gis.gdal.SpatialReference objects are accepted. encoding Species the character set encoding of the strings in the OGR data source. For example, latin-1, utf-8, and cp437 are all valid encoding parameters. transaction_mode May be commit_on_success (default) or autocommit. transform Setting this to False will disable coordinate transformations. In other words, geometries will be inserted into the database unmodied from their original state in the data source. unique Setting this to the name, or a tuple of names, from the given model will create models unique only to the given name(s). Geometries will from each feature will be added into the collection associated with the unique model. Forces the transaction mode to be autocommit. using New in version 1.2. Sets the database to use when importing spatial data. Default is default save() Keyword Arguments save([verbose=False, d_range=False, step=False, progress=False, silent=False, stream=sys.stdout, strict=False]) The save() method also accepts keywords. These keywords are used for controlling output logging, error handling, and for importing specic feature ranges. Save Keyword Arguments fid_range Description May be set with a slice or tuple of (begin, end) feature IDs to map from the data source. In other words, this keyword enables the user to selectively import a subset range of features in the geographic data source. When this keyword is set, status information will be printed giving the number of features processed and successfully saved. By default, progress information will be printed every 1000 features processed, however, this default may be overridden by setting this keyword with an integer for the desired interval. By default, non-fatal error notications are printed to sys.stdout, but this keyword may be set to disable these notications. If set with an integer, transactions will occur at every step interval. For example, if step=1000, a commit would occur after the 1,000th feature, the 2,000th feature etc. Status information will be written to this le handle. Defaults to using sys.stdout, but any object with a write method is supported. Execution of the model mapping will cease upon the rst error encountered. The default value (False) behavior is to attempt to continue. If set, information will be printed subsequent to each model save executed on the database.
progress
Troubleshooting
Running out of memory As noted in the warning at the top of this section, Django stores all SQL queries when DEBUG=True. Set DEBUG=False in your settings, and this should stop excessive memory use when running LayerMapping scripts. MySQL: max_allowed_packet error If you encounter the following error when using LayerMapping and MySQL:
OperationalError: (1153, "Got a packet bigger than max_allowed_packet bytes")
594
Then the solution is to increase the value of the max_allowed_packet setting in your MySQL conguration. For example, the default value may be something low like one megabyte the setting may be modied in MySQLs conguration le (my.cnf) in the [mysqld] section:
max_allowed_packet = 10M
OGR Inspection
ogrinspect
ogrinspect(data_source, model_name, [**kwargs])
mapping
mapping(data_source, [geom_name=geom, layer_key=0, multi_geom=False]) GeoIP Interface to the MaxMind GeoIP library for performing IP-based geolocation from GeoDjango. See GeoIP reference documentation for more information. LayerMapping The LayerMapping simplies the process of importing spatial data and attributes into your GeoDjango models.
49.9. GeoDjango
595
-geom-name <name> Species the model attribute name to use for the geometry eld. Defaults to geom. -layer <layer> The key for specifying which layer in the OGR DataSource source to use. Defaults to 0 (the rst layer). May be an integer or a string identier for the Layer. -mapping Automatically generate a mapping dictionary for use with LayerMapping. -multi-geom When generating the geometry eld, treat it as a geometry collection. For example, if this setting is enabled then a MultiPolygonField will be placed in the generated model rather than PolygonField. -name-field <name_field> Generates a __unicode__ routine on the model that will return the the given eld name. -no-imports Suppresses the from django.contrib.gis.db import models import statement. -null <null_field(s)> Use a comma separated list of OGR eld names to add the null=True keyword option to the eld denition. Set with true to apply to all applicable elds. -srid The SRID to use for the geometry eld. If not set, ogrinspect attempts to automatically determine of the SRID of the data source.
596
openlayers_url Link to the URL of the OpenLayers JavaScript. Defaults to http://openlayers.org/api/2.8/OpenLayers.js. modifiable Defaults to False. When set to to True, disables editing of existing geometry elds in the admin. Note: This is different from adding the geometry eld to readonly_fields, which will only display the WKT of the geometry. Setting modifiable=False, actually displays the geometry in a map, but disables the ability to edit its vertices. OSMGeoAdmin class OSMGeoAdmin() A subclass of GeoModelAdmin that uses a spherical mercator projection with OpenStreetMap street data tiles. See the OSMGeoAdmin introduction in the tutorial for a usage example.
Feed Subclass
class Feed() In addition to methods provided by the django.contrib.syndication.feeds.Feed base class, GeoDjangos Feed class provides the following overrides. Note that these overrides may be done in multiple ways:
from django.contrib.gis.feeds import Feed class MyFeed(Feed): # First, as a class attribute. geometry = ... item_geometry = ... # Also a function with no arguments def geometry(self): ... def item_geometry(self): ... # And as a function with a single argument def geometry(self, obj): ...
49.9. GeoDjango
597
geometry(obj) Takes the object returned by get_object() and returns the feeds geometry. GEOSGeometry instance, or can be a tuple to represent a point or a box. For example:
class ZipcodeFeed(Feed): def geometry(self, obj): # Can also return: obj.poly, and obj.poly.centroid. return obj.poly.extent # tuple like: (X0, Y0, X1, Y1).
Typically this is a
item_geometry(item) Set this to return the geometry for each item in the feed. This can be a GEOSGeometry instance, or a tuple that represents a point coordinate or bounding box. For example:
class ZipcodeFeed(Feed): def item_geometry(self, obj): # Returns the polygon. return obj.poly
SyndicationFeed Subclasses
The following django.utils.feedgenerator.SyndicationFeed subclasses are available: class GeoRSSFeed() class GeoAtom1Feed() class W3CGeoFeed() Note: W3C Geo formatted feeds only support PointField geometries.
Google, Inc., What is a Geo Sitemap?. Google, Inc., Submit Your Geo Content to Google.
598
Example Reference
Settings
Note: The settings below have sensible defaults, and shouldnt require manual setting. POSTGIS_TEMPLATE New in version 1.1: Please, see the release notesChanged in version 1.2: Please, see the release notes This setting may be used to customize the name of the PostGIS template database to use. In Django versions 1.2 and above, it automatically defaults to template_postgis (the same name used in the installation documentation). Note: Django 1.1 users will still have to dene the POSTGIS_TEMPLATE with a value, for example:
POSTGIS_TEMPLATE=template_postgis
POSTGIS_VERSION New in version 1.1: Please, see the release notes When GeoDjangos spatial backend initializes on PostGIS, it has to perform a SQL query to determine the version. Setting the version manually prevents this query to the database:
POSTGIS_VERSION=(1.3.6, 1, 3, 6)
49.9. GeoDjango
599
Create Database User To make database user with the ability to create databases, use the following command:
$ createuser --createdb -R -S <user_name>
The -R -S ags indicate that we do not want the user to have the ability to create additional users (roles) or to be a superuser, respectively. Alternatively, you may alter an existing users role from the SQL shell (assuming this is done from an existing superuser account):
postgres# ALTER ROLE <user_name> CREATEDB NOSUPERUSER NOCREATEROLE;
Create Database Superuser This may be done at the time the user is created, for example:
$ createuser --superuser <user_name>
Or you may alter the users role from the SQL shell (assuming this is done from an existing superuser account):
postgres# ALTER ROLE <user_name> SUPERUSER;
Create Local PostgreSQL Database 1. Initialize database: initdb -D /path/to/user/db 2. If theres already a Postgres instance on the machine, it will need to use a different TCP port than 5432. Edit postgresql.conf (in /path/to/user/db) to change the database port (e.g. port = 5433). 3. Start this database pg_ctl -D /path/to/user/db start
Windows
On Windows platforms the pgAdmin III utility may also be used as a simple way to add superuser privileges to your database user. By default, the PostGIS installer on Windows includes a template spatial database entitled template_postgis. SpatiaLite New in version 1.1: Please, see the release notes You will need to download the initialization SQL script for SpatiaLite:
$ wget http://www.gaia-gis.it/spatialite/init_spatialite-2.3.zip $ unzip init_spatialite-2.3.zip
If init_spatialite-2.3.sql is in the same path as your projects manage.py, then all you have to do is:
$ python manage.py test
600
Settings
SPATIALITE_SQL New in version 1.1: Please, see the release notes By default, the GeoDjango test runner looks for the SpatiaLite SQL in the same directory where it was invoked (by default the same directory where manage.py is located). If you want to use a different location, then you may add the following to your settings:
SPATIALITE_SQL=/path/to/init_spatialite-2.3.sql
Testing GeoDjango Applications in 1.1 In Django 1.1, to accommodate the extra steps required to scaffalod a spatial database automatically, a test runner customized for GeoDjango must be used. To use this runner, congure TEST_RUNNER as follows:
TEST_RUNNER=django.contrib.gis.tests.run_tests
Note: In order to create a spatial database, the DATABASE_USER setting (or TEST_DATABASE_USER, if optionally dened on Oracle) requires elevated privileges. When using PostGIS or MySQL, the database user must have at least the ability to create databases. When testing on Oracle, the user should be a superuser. GeoDjango Test Suite To run GeoDjangos own internal test suite, congure the TEST_RUNNER setting as follows:
TEST_RUNNER=django.contrib.gis.tests.run_gis_tests
Apache In this section there are some example VirtualHost directives for when deploying using either mod_python or mod_wsgi. At this time, we recommend mod_wsgi, as it is now ofcially recommended way to deploy Django applications with Apache. Moreover, if mod_python is used, then a prefork version of Apache must also be used. As long as mod_wsgi is congured correctly, it does not matter whether the version of Apache is prefork or worker. Note: The Alias and Directory congurations in the the examples below use an example path to a system-wide installation folder of Django. Substitute in an appropriate location, if necessary, as it may be different than the path on your system.
mod_wsgi
Example:
49.9. GeoDjango
601
<VirtualHost *:80> WSGIDaemonProcess geodjango user=geo group=geo processes=5 threads=1 WSGIProcessGroup geodjango WSGIScriptAlias / /home/geo/geodjango/world.wsgi Alias /media/ "/usr/lib/python2.5/site-packages/django/contrib/admin/media/" <Directory "/usr/lib/python2.5/site-packages/django/contrib/admin/media/"> Order allow,deny Options Indexes Allow from all IndexOptions FancyIndexing </Directory> </VirtualHost>
Warning: If the WSGIDaemonProcess attribute threads is not set to 1, then Apache may crash when running your GeoDjango application. Increase the number of processes instead. For more information, please consult Djangos mod_wsgi documentation.
mod_python
Example:
<VirtualHost *:80> <Location "/"> SetHandler mod_python PythonHandler django.core.handlers.modpython SetEnv DJANGO_SETTINGS_MODULE world.settings PythonDebug On PythonPath "[/var/www/apps] + sys.path" </Location> Alias /media/ "/usr/lib/python2.5/site-packages/django/contrib/admin/media/" <Location "/media"> SetHandler None </Location> </VirtualHost>
Warning: When using mod_python you must be using a prefork version of Apache, or else your GeoDjango application may crash Apache. For more information, please consult Djangos mod_python documentation.
602
Lighttpd
FastCGI
Nginx
FastCGI
49.10 django.contrib.humanize
A set of Django template lters useful for adding a human touch to data. To activate these lters, add django.contrib.humanize to your INSTALLED_APPS setting. Once youve done that, use {% load humanize %} in a template, and youll have access to these lters:
49.10.1 apnumber
For numbers 1-9, returns the number spelled out. Otherwise, returns the number. This follows Associated Press style. Examples: 1 becomes one. 2 becomes two. 10 becomes 10. You can pass in either an integer or a string representation of an integer.
49.10.2 intcomma
Converts an integer to a string containing commas every three digits. Examples: 4500 becomes 4,500. 45000 becomes 45,000. 450000 becomes 450,000. 4500000 becomes 4,500,000. You can pass in either an integer or a string representation of an integer.
49.10.3 intword
Converts a large integer to a friendly text representation. Works best for numbers over 1 million. Examples: 1000000 becomes 1.0 million. 1200000 becomes 1.2 million. 1200000000 becomes 1.2 billion.
49.10. django.contrib.humanize
603
Values up to 1000000000000000 (one quadrillion) are supported. You can pass in either an integer or a string representation of an integer.
49.10.4 ordinal
Converts an integer to its ordinal as a string. Examples: 1 becomes 1st. 2 becomes 2nd. 3 becomes 3rd. You can pass in either an integer or a string representation of an integer.
49.10.5 naturalday
New in version 1.0: Please, see the release notes For dates that are the current day or within one day, return today, tomorrow or yesterday, as appropriate. Otherwise, format the date using the passed in format string. Argument: Date formatting string as described in the now tag. Examples (when today is 17 Feb 2007): 16 Feb 2007 becomes yesterday. 17 Feb 2007 becomes today. 18 Feb 2007 becomes tomorrow. Any other day is formatted according to given argument or the DATE_FORMAT setting if no argument is given.
604
605
The django.contrib.localflavor package also includes a generic subpackage, containing useful code that is not specic to one particular country or culture. Currently, it denes date, datetime and split datetime input elds based on those from forms, but with non-US default formats. Heres an example of how to use them:
from django import forms from django.contrib.localflavor import generic class MyForm(forms.Form): my_date_field = generic.forms.DateField()
606
607
608
class ISPhoneNumberField() A form eld that validates input as an Icelandtic phone number (seven digits with an optional hyphen or space after the rst three digits). class ISPostalCodeSelect() A Select widget that uses a list of Icelandic postal codes as its choices.
609
class ITProvinceSelect() A Select widget that uses a list of Italian provinces as its choices. class ITRegionSelect() A Select widget that uses a list of Italian regions as its choices.
610
611
612
class SEOrganisationNumber() A form eld that validates input as a Swedish organisation number (organisationsnummer). It accepts the same input as SEPersonalIdentityField (for sole proprietorships (enskild rma). However, coordination numbers are not accepted. It also accepts ordinary Swedish organisation numbers with the format NNNNNNNNNN. The return value will be YYYYMMDDXXXX for sole proprietors, and NNNNNNNNNN for other organisations. class SEPersonalIdentityNumber() A form eld that validates input as a Swedish personal identity number (personnummer). The correct formats are YYYYMMDD-XXXX, YYYYMMDDXXXX, YYMMDD-XXXX, YYMMDDXXXX and YYMMDD+XXXX. A + indicates that the person is older than 100 years, which will be taken into consideration when the date is validated. The checksum will be calculated and checked. The birth date is checked to be a valid date. By default, co-ordination numbers (samordningsnummer) will be accepted. To only allow real personal identity numbers, pass the keyword argument coordination_number=False to the constructor. The cleaned value will always have the format YYYYMMDDXXXX. class SEPostalCodeField() A form eld that validates input as a Swedish postal code (postnummer). Valid codes consist of ve digits (XXXXX). The number can optionally be formatted with a space after the third digit (XXX XX). The cleaned value will never contain the space.
613
class UKNationSelect() A Select widget that uses a list of UK nations as its choices.
614
If you are using a storage backend that relies on sessions (the default), django.contrib.sessions.middleware.SessionMiddleware must be enabled and appear before MessageMiddleware in your MIDDLEWARE_CLASSES. Edit the TEMPLATE_CONTEXT_PROCESSORS setting and make django.contrib.messages.context_processors.messages. Add django.contrib.messages to your INSTALLED_APPS setting The default settings.py created by django-admin.py startproject has MessageMiddleware activated and the django.contrib.messages app installed. Also, the default value for TEMPLATE_CONTEXT_PROCESSORS contains django.contrib.messages.context_processors.messages. If you dont want to use messages, you can remove the MessageMiddleware line from MIDDLEWARE_CLASSES, the messages context processor from TEMPLATE_CONTEXT_PROCESSORS and django.contrib.messages from your INSTALLED_APPS. sure it contains
The value should be the full path of the desired storage class. Four storage classes are included: django.contrib.messages.storage.session.SessionStorage This class stores all messages inside of the requests session. It requires Djangos contrib.sessions application. django.contrib.messages.storage.cookie.CookieStorage This class stores the message data in a cookie (signed with a secret hash to prevent manipulation) to persist notications across requests. Old messages are dropped if the cookie data size would exceed 4096 bytes. django.contrib.messages.storage.fallback.FallbackStorage This class rst uses CookieStorage for all messages, falling back to using SessionStorage for the messages that could not t in a single cookie. Since it is uses SessionStorage, it also requires Djangos contrib.session application. django.contrib.messages.storage.user_messages.LegacyFallbackStorage This is the default temporary storage class. This class extends FallbackStorage and adds compatibility methods to to retrieve any messages stored in the user Message model by code that has not yet been updated to use the new API. This storage is temporary (because it makes use of code that is pending deprecation) and will be removed in Django 1.4. At that time, the default
615
storage will become django.contrib.messages.storage.fallback.FallbackStorage. For more information, see LegacyFallbackStorage below. To write your own storage class, subclass the BaseStorage class django.contrib.messages.storage.base and implement the _get and _store methods. in
LegacyFallbackStorage
The LegacyFallbackStorage is a temporary tool to facilitate the transition from the deprecated user.message_set API and will be removed in Django 1.4 according to Djangos standard deprecation policy. For more information, see the full release process documentation. In addition to the functionality in the FallbackStorage, it adds a custom, read-only storage class that retrieves messages from the user Message model. Any messages that were stored in the Message model (e.g., by code that has not yet been updated to use the messages framework) will be retrieved rst, followed by those stored in a cookie and in the session, if any. Since messages stored in the Message model do not have a concept of levels, they will be assigned the INFO level by default. Message levels The messages framework is based on a congurable level architecture similar to that of the Python logging module. Message levels allow you to group messages by type so they can be ltered or displayed differently in views and templates. The built-in levels (which can be imported from django.contrib.messages directly) are: Constant DEBUG INFO SUCCESS WARNING ERROR Purpose Development-related messages that will be ignored (or removed) in a production deployment Informational messages for the user An action was successful, e.g. Your prole was updated successfully A failure did not occur but may be imminent An action was not successful or some other failure occurred
The MESSAGE_LEVEL setting can be used to change the minimum recorded level (or it can be changed per request). Attempts to add messages of a level less than this will be ignored. Message tags Message tags are a string representation of the message level plus any extra tags that were added directly in the view (see Adding extra message tags below for more details). Tags are stored in a string and are separated by spaces. Typically, message tags are used as CSS classes to customize message style based on message type. By default, each level has a single tag thats a lowercase version of its own constant: Level Constant DEBUG INFO SUCCESS WARNING ERROR Tag debug info success warning error
To change the default tags for a message level (either built-in or custom), set the MESSAGE_TAGS setting to a dictionary containing the levels you wish to change. As this extends the default tags, you only need to provide tags for the levels you wish to override:
616
Some shortcut methods provide a standard way to add messages with commonly used tags (which are usually represented as HTML classes for the message):
messages.debug(request, %s SQL statements were executed. % count) messages.info(request, Three credits remain in your account.) messages.success(request, Profile details updated.) messages.warning(request, Your account expires in three days.) messages.error(request, Document deleted.)
If youre using the context processor, your template should be rendered with a RequestContext. Otherwise, ensure messages is available to the template context. Creating custom message levels Messages levels are nothing more than integers, so you can dene your own level constants and use them to create more customized user feedback, e.g.:
CRITICAL = 50 def my_view(request): messages.add_message(request, CRITICAL, A serious error occurred.)
617
When creating custom message levels you should be careful to avoid overloading existing levels. The values for the Level Constant Value DEBUG 10 INFO 20 built-in levels are: SUCCESS 25 WARNING 30 ERROR 40 If you need to identify the custom levels in your HTML or CSS, you need to provide a mapping via the MESSAGE_TAGS setting. Note: If you are creating a reusable application, it is recommended to use only the built-in message levels and not rely on any custom levels. Changing the minimum recorded level per-request The minimum recorded level can be set per request via the set_level method:
from django.contrib import messages # Change the messages level to ensure the debug message is added. messages.set_level(request, messages.DEBUG) messages.debug(request, Test message...) # In another request, record only messages with a level of WARNING and higher messages.set_level(request, messages.WARNING) messages.success(request, Your profile was updated.) # ignored messages.warning(request, Your account is about to expire.) # recorded # Set the messages level back to default. messages.set_level(request, None)
For more information on how the minimum recorded level functions, see Message levels above. Adding extra message tags For more direct control over message tags, you can optionally provide a string containing extra tags to any of the add methods:
messages.add_message(request, messages.INFO, Over 9000!, extra_tags=dragonball) messages.error(request, Email box full, extra_tags=email)
Extra tags are added before the default tag for that level and are space separated.
618
Failing silently when the message framework is disabled If youre writing a reusable app (or other piece of code) and want to include messaging functionality, but dont want to require your users to enable it if they dont want to, you may pass an additional keyword argument fail_silently=True to any of the add_message family of methods. For example:
messages.add_message(request, messages.SUCCESS, Profile details updated., fail_silently=True) messages.info(request, Hello world., fail_silently=True)
Internally, Django uses this functionality in the create, update, and delete generic views so that they work even if the message framework is disabled. Note: Setting fail_silently=True only hides the MessageFailure that would otherwise occur when the messages framework disabled and one attempts to use one of the add_message family of methods. It does not hide failures that may occur for other reasons.
49.12.6 Settings
A few Django settings give you control over message behavior: MESSAGE_LEVEL Default: messages.INFO This sets the minimum message that will be saved in the message storage. See Message levels above for more details. Important
619
If you override MESSAGE_LEVEL in your settings le and rely on any of the built-in constants, you must import the constants module directly to avoid the potential for circular imports, e.g.:
from django.contrib.messages import constants as message_constants MESSAGE_LEVEL = message_constants.DEBUG
If desired, you may specify the numeric values for the constants directly according to the values in the above constants table. MESSAGE_STORAGE Default: django.contrib.messages.storage.user_messages.LegacyFallbackStorage Controls where Django stores message data. Valid values are: django.contrib.messages.storage.fallback.FallbackStorage django.contrib.messages.storage.session.SessionStorage django.contrib.messages.storage.cookie.CookieStorage django.contrib.messages.storage.user_messages.LegacyFallbackStorage See Storage backends for more details. MESSAGE_TAGS Default:
{messages.DEBUG: debug, messages.INFO: info, messages.SUCCESS: success, messages.WARNING: warning, messages.ERROR: error,}
This sets the mapping of message level to message tag, which is typically rendered as a CSS class in HTML. If you specify a value, it will extend the default. This means you only have to specify those values which you need to override. See Displaying messages above for more details. Important If you override MESSAGE_TAGS in your settings le and rely on any of the built-in constants, you must import the constants module directly to avoid the potential for circular imports, e.g.:
from django.contrib.messages import constants as message_constants MESSAGE_TAGS = {message_constants.INFO: }
If desired, you may specify the numeric values for the constants directly according to the values in the above constants table.
620
49.13.1 Installation
To install the redirects app, follow these steps: 1. Add django.contrib.redirects to your INSTALLED_APPS setting. 2. Add django.contrib.redirects.middleware.RedirectFallbackMiddleware to your MIDDLEWARE_CLASSES setting. 3. Run the command manage.py syncdb.
621
49.14.1 Overview
A sitemap is an XML le on your Web site that tells search-engine indexers how frequently your pages change and how important certain pages are in relation to other pages on your site. This information helps search engines index your site. The Django sitemap framework automates the creation of this XML le by letting you express this information in Python code. It works much like Djangos syndication framework. To create a sitemap, just write a Sitemap class and point to it in your URLconf .
49.14.2 Installation
To install the sitemap app, follow these steps: 1. Add django.contrib.sitemaps to your INSTALLED_APPS setting. 2. Make sure django.template.loaders.app_directories.Loader is in your TEMPLATE_LOADERS setting. Its in there by default, so youll only need to change this if youve changed that setting. 3. Make sure youve installed the sites framework. (Note: The sitemap application doesnt install any database tables. The only reason it needs to go into INSTALLED_APPS is so that the Loader() template loader can nd the default templates.)
49.14.3 Initialization
To activate sitemap generation on your Django site, add this line to your URLconf :
(r^sitemap\.xml$, django.contrib.sitemaps.views.sitemap, {sitemaps: sitemaps})
This tells Django to build a sitemap when a client accesses /sitemap.xml. The name of the sitemap le is not important, but the location is. Search engines will only index links in your sitemap for the current URL level and below. For instance, if sitemap.xml lives in your root directory, it may reference any URL in your site. However, if your sitemap lives at /content/sitemap.xml, it may only reference URLs that begin with /content/. The sitemap view takes an extra, required argument: {sitemaps: sitemaps}. sitemaps should be a dictionary that maps a short section label (e.g., blog or news) to its Sitemap class (e.g., BlogSitemap or NewsSitemap). It may also map to an instance of a Sitemap class (e.g., BlogSitemap(some_var)).
622
Note: changefreq and priority are class attributes corresponding to <changefreq> and <priority> elements, respectively. They can be made callable as functions, as lastmod was in the example. items() is simply a method that returns a list of objects. The objects returned will get passed to any callable methods corresponding to a sitemap property (location, lastmod, changefreq, and priority). lastmod should return a Python datetime object. There is no location method in this example, but you can provide it in order to specify the URL for your object. By default, location() calls get_absolute_url() on each object and returns the result.
623
lastmod Optional. Either a method or attribute. If its a method, it should take one argument an object as returned by items() and return that objects last-modied date/time, as a Python datetime.datetime object. If its an attribute, its value should be a Python datetime.datetime object representing the lastmodied date/time for every object returned by items(). changefreq Optional. Either a method or attribute. If its a method, it should take one argument an object as returned by items() and return that objects change frequency, as a Python string. If its an attribute, its value should be a string representing the change frequency of every object returned by items(). Possible values for changefreq, whether you use a method or attribute, are: always hourly daily weekly monthly yearly never priority() Optional. Either a method or attribute. If its a method, it should take one argument an object as returned by items() and return that objects priority, as either a string or oat. If its an attribute, its value should be either a string or oat representing the priority of every object returned by items(). Example values for priority: 0.4, 1.0. The default priority of a page is 0.5. See the sitemaps.org documentation for more.
49.14.7 Shortcuts
The sitemap framework provides a couple convenience classes for common cases: class FlatPageSitemap() The django.contrib.sitemaps.FlatPageSitemap class looks at all flatpages dened for the current SITE_ID (see the sites documentation) and creates an entry in the sitemap. These entries include only the location attribute not lastmod, changefreq or priority. class GenericSitemap() The django.contrib.sitemaps.GenericSitemap class works with any generic views you already have. To use it, create an instance, passing in the same info_dict you pass to the generic views. The only requirement is that the dictionary have a queryset entry. It may also have a date_field entry that species a date eld for objects retrieved from the queryset. This will be used for the lastmod attribute in the generated sitemap. You may also pass priority and changefreq keyword arguments to the GenericSitemap constructor to specify these attributes for all URLs.
624
This will automatically generate a sitemap.xml le that references both sitemap-flatpages.xml and sitemap-blog.xml. The Sitemap classes and the sitemaps dict dont change at all. You should create an index le if one of your sitemaps has more than 50,000 URLs. In this case, Django will automatically paginate the sitemap, and the index will reect that.
625
sites sitemap (e.g., /sitemap.xml). If this argument isnt provided, ping_google() will attempt to gure out your sitemap by performing a reverse looking in your URLconf. ping_google() raises the exception django.contrib.sitemaps.SitemapNotFound if it cannot determine your sitemap URL. Register with Google rst! The ping_google() command only works if you have registered your site with Google Webmaster Tools. One useful way to call ping_google() is from a models save() method:
from django.contrib.sitemaps import ping_google class Entry(models.Model): # ... def save(self, force_insert=False, force_update=False): super(Entry, self).save(force_insert, force_update) try: ping_google() except Exception: # Bare except because we could get a variety # of HTTP-related exceptions. pass
A more efcient solution, however, would be to call ping_google() from a cron script, or some other scheduled task. The function makes an HTTP request to Googles servers, so you may not want to introduce that network overhead each time you call save(). Pinging Google via manage.py New in version 1.0: Please, see the release notes Once the sitemaps application is added to your project, you may also ping the Google servers through the command line manage.py interface:
python manage.py ping_google [/sitemap.xml]
Associating content with multiple sites The Django-powered sites LJWorld.com and Lawrence.com are operated by the same news organization the Lawrence Journal-World newspaper in Lawrence, Kansas. LJWorld.com focuses on news, while Lawrence.com focuses on local entertainment. But sometimes editors want to publish an article on both sites. The brain-dead way of solving the problem would be to require site producers to publish the same story twice: once for LJWorld.com and again for Lawrence.com. But thats inefcient for site producers, and its redundant to store multiple copies of the same story in the database. The better solution is simple: Both sites use the same article database, and an article is associated with one or more sites. In Django model terminology, thats represented by a ManyToManyField in the Article model:
from django.db import models from django.contrib.sites.models import Site class Article(models.Model): headline = models.CharField(max_length=200) # ... sites = models.ManyToManyField(Site)
This accomplishes several things quite nicely: It lets the site producers edit all content on both sites in a single interface (the Django admin). It means the same story doesnt have to be published twice in the database; it only has a single record in the database. It lets the site developers use the same Django view code for both sites. The view code that displays a given story just checks to make sure the requested story is on the current site. It looks something like this:
from django.conf import settings def article_detail(request, article_id): try: a = Article.objects.get(id=article_id, sites__id__exact=settings.SITE_ID) except Article.DoesNotExist: raise Http404 # ...
Associating content with a single site Similarly, you can associate a model to the Site model in a many-to-one relationship, using ForeignKey. For example, if an article is only allowed on a single site, youd use a model like this:
from django.db import models from django.contrib.sites.models import Site class Article(models.Model): headline = models.CharField(max_length=200) # ... site = models.ForeignKey(Site)
627
Hooking into the current site from views On a lower level, you can use the sites framework in your Django views to do particular things based on the site in which the view is being called. For example:
from django.conf import settings def my_view(request): if settings.SITE_ID == 3: # Do something. else: # Do something else.
Of course, its ugly to hard-code the site IDs like that. This sort of hard-coding is best for hackish xes that you need done quickly. A slightly cleaner way of accomplishing the same thing is to check the current sites domain:
from django.conf import settings from django.contrib.sites.models import Site def my_view(request): current_site = Site.objects.get(id=settings.SITE_ID) if current_site.domain == foo.com: # Do something else: # Do something else.
The idiom of retrieving the Site object for the value of settings.SITE_ID is quite common, so the Site models manager has a get_current() method. This example is equivalent to the previous one:
from django.contrib.sites.models import Site def my_view(request): current_site = Site.objects.get_current() if current_site.domain == foo.com: # Do something else: # Do something else.
Getting the current domain for display LJWorld.com and Lawrence.com both have e-mail alert functionality, which lets readers sign up to get notications when news happens. Its pretty basic: A reader signs up on a Web form, and he immediately gets an e-mail saying, Thanks for your subscription. Itd be inefcient and redundant to implement this signup-processing code twice, so the sites use the same code behind the scenes. But the thank you for signing up notice needs to be different for each site. By using Site objects, we can abstract the thank you notice to use the values of the current sites name and domain. Heres an example of what the form-handling view looks like:
from django.contrib.sites.models import Site from django.core.mail import send_mail def register_for_newsletter(request): # Check form values, etc., and subscribe the user. # ...
628
current_site = Site.objects.get_current() send_mail(Thanks for subscribing to %s alerts % current_site.name, Thanks for your subscription. We appreciate it.\n\n-The %s team. % current_site.name, editor@%s % current_site.domain, [user.email]) # ...
On Lawrence.com, this e-mail has the subject line Thanks for subscribing to lawrence.com alerts. On LJWorld.com, the e-mail has the subject Thanks for subscribing to LJWorld.com alerts. Same goes for the e-mails message body. Note that an even more exible (but more heavyweight) way of doing this would be to use Djangos template system. Assuming Lawrence.com and LJWorld.com have different template directories (TEMPLATE_DIRS), you could simply farm out to the template system like so:
from django.core.mail import send_mail from django.template import loader, Context def register_for_newsletter(request): # Check form values, etc., and subscribe the user. # ... subject = loader.get_template(alerts/subject.txt).render(Context({})) message = loader.get_template(alerts/message.txt).render(Context({})) send_mail(subject, message, [email protected], [user.email]) # ...
In this case, youd have to create subject.txt and message.txt template les for both the LJWorld.com and Lawrence.com template directories. That gives you more exibility, but its also more complex. Its a good idea to exploit the Site objects as much as possible, to remove unneeded complexity and redundancy. Getting the current domain for full URLs Djangos get_absolute_url() convention is nice for getting your objects URL without the domain name, but in some cases you might want to display the full URL with http:// and the domain and everything for an object. To do this, you can use the sites framework. A simple example:
>>> from django.contrib.sites.models import Site >>> obj = MyModel.objects.get(id=3) >>> obj.get_absolute_url() /mymodel/objects/3/ >>> Site.objects.get_current().domain example.com >>> http://%s%s % (Site.objects.get_current().domain, obj.get_absolute_url()) http://example.com/mymodel/objects/3/
629
If for any reason you want to force a database query, you can tell Django to clear the cache using Site.objects.clear_cache():
# First call; current site fetched from database. current_site = Site.objects.get_current() # ... # Second call; current site fetched from cache. current_site = Site.objects.get_current() # ... # Force a database query for the third call. Site.objects.clear_cache() current_site = Site.objects.get_current()
With this model, Photo.objects.all() will return all Photo objects in the database, but Photo.on_site.all() will return only the Photo objects associated with the current site, according to the SITE_ID setting. Put another way, these two statements are equivalent:
Photo.objects.filter(site=settings.SITE_ID) Photo.on_site.all()
How did CurrentSiteManager know which eld of Photo was the Site? By default, CurrentSiteManager looks for a either a ForeignKey called site or a ManyToManyField called sites to lter on. If you use a eld named something other than site or sites to identify which Site objects your object is related to, then you need to explicitly pass the custom eld name as a parameter to CurrentSiteManager on your model. The following model, which has a eld called publish_on, demonstrates this:
from django.db import models from django.contrib.sites.models import Site from django.contrib.sites.managers import CurrentSiteManager class Photo(models.Model):
630
photo = models.FileField(upload_to=/home/photos) photographer_name = models.CharField(max_length=100) pub_date = models.DateField() publish_on = models.ForeignKey(Site) objects = models.Manager() on_site = CurrentSiteManager(publish_on)
If you attempt to use CurrentSiteManager and pass a eld name that doesnt exist, Django will raise a ValueError. Finally, note that youll probably want to keep a normal (non-site-specic) Manager on your model, even if you use CurrentSiteManager. As explained in the manager documentation, if you dene a manager manually, then Django wont create the automatic objects = models.Manager() manager for you. Also note that certain parts of Django namely, the Django admin site and generic views use whichever manager is dened rst in the model, so if you want your admin site to have access to all objects (not just site-specic ones), put objects = models.Manager() in your model, before you dene CurrentSiteManager.
631
A RequestSite object has a similar interface to a normal Site object, except its __init__() method takes an HttpRequest object. Its able to deduce the domain and name by looking at the requests domain. It has save() and delete() methods to match the interface of Site, but the methods raise NotImplementedError.
632
def item_title(self, item): return item.title def item_description(self, item): return item.description
To connect a URL to this feed, put an instance of the Feed object in your URLconf . For example:
from django.conf.urls.defaults import * from myproject.feeds import LatestEntriesFeed urlpatterns = patterns(, # ... (r^latest/feed/$, LatestEntriesFeed()), # ... )
Note: The Feed class subclasses django.contrib.syndication.views.Feed. title, link and description correspond to the standard RSS <title>, <description> elements, respectively. <link> and
items() is, simply, a method that returns a list of objects that should be included in the feed as <item> elements. Although this example returns NewsItem objects using Djangos object-relational mapper, items() doesnt have to return model instances. Although you get a few bits of functionality for free by using Django models, items() can return any type of object you want. If youre creating an Atom feed, rather than an RSS feed, set the subtitle attribute instead of the description attribute. See Publishing Atom and RSS feeds in tandem, later, for an example. One thing is left to do. In an RSS feed, each <item> has a <title>, <link> and <description>. We need to tell the framework what data to put into those elements. For the contents of <title> and <description>, Django tries calling the methods item_title() and item_description() on the Feed class. They are passed a single parameter, item, which is the object itself. These are optional; by default, the unicode representation of the object is used for both. If you want to do any special formatting for either the title or description, Django templates can be used instead. Their paths can be specied with the title_template and description_template attributes on the Feed class. The templates are rendered for each item and are passed two template context variables: {{ obj }} The current object (one of whichever objects you returned in items()). {{ site }} A django.contrib.sites.models.Site object representing the current site. This is useful for {{ site.domain }} or {{ site.name }}. If you do not have the Django sites framework installed, this will be set to a django.contrib.sites.models.RequestSite object. See the RequestSite section of the sites framework documentation for more. See a complex example below that uses a description template. To specify the contents of <link>, you have two options. For each item in items(), Django rst tries calling the item_link() method on the Feed class. In a similar way to the title and description, it is passed it a single parameter, item. If that method doesnt exist, Django tries executing a get_absolute_url() method on that object. Both get_absolute_url() and item_link() should return the items URL as a normal Python string. As with get_absolute_url(), the result of item_link() will be included directly in the URL, so you are responsible for doing all necessary URL quoting and conversion to ASCII inside the method itself.
633
A complex example The framework also supports more complex feeds, via arguments. For example, chicagocrime.org offers an RSS feed of recent crimes for every police beat in Chicago. Itd be silly to create a separate Feed class for each police beat; that would violate the DRY principle and would couple data to programming logic. Instead, the syndication framework lets you access the arguments passed from your URLconf so feeds can output items based on information in the feeds URL. On chicagocrime.org, the police-beat feeds are accessible via URLs like this: /beats/613/rss/ Returns recent crimes for beat 613. /beats/1424/rss/ Returns recent crimes for beat 1424. These can be matched with a URLconf line such as:
(r^beats/(?P<beat_id>\d+)/rss/$, BeatFeed()),
Like a view, the arguments in the URL are passed to the get_object() method along with the request object. Changed in version 1.2: Prior to version 1.2, get_object() only accepted a bits argument. Heres the code for these beat-specic feeds:
from django.contrib.syndication.views import FeedDoesNotExist from django.shortcuts import get_object_or_404 class BeatFeed(Feed): description_template = feeds/beat_description.html def get_object(self, request, beat_id): return get_object_or_404(Beat, pk=beat_id) def title(self, obj): return "Chicagocrime.org: Crimes for beat %s" % obj.beat def link(self, obj): return obj.get_absolute_url() def description(self, obj): return "Crimes recently reported in police beat %s" % obj.beat def items(self, obj): return Crime.objects.filter(beat=obj).order_by(-crime_date)[:30]
To generate the feeds <title>, <link> and <description>, Django uses the title(), link() and description() methods. In the previous example, they were simple string class attributes, but this example illustrates that they can be either strings or methods. For each of title, link and description, Django follows this algorithm: First, it tries to call a method, passing the obj argument, where obj is the object returned by get_object(). Failing that, it tries to call a method with no arguments. Failing that, it uses the class attribute. Also note that items() also follows the same algorithm rst, it tries items(obj)(), then items(), then nally an items class attribute (which should be a list). We are using a template for the item descriptions. It can be very simple:
634
{{ obj.description }}
However, you are free to add formatting as desired. The ExampleFeed class below gives full documentation on methods and attributes of Feed classes. Specifying the type of feed By default, feeds produced in this framework use RSS 2.0. To change that, add a feed_type attribute to your Feed class, like so:
from django.utils.feedgenerator import Atom1Feed class MyFeed(Feed): feed_type = Atom1Feed
Note that you set feed_type to a class object, not an instance. Currently available feed types are: django.utils.feedgenerator.Rss201rev2Feed (RSS 2.01. Default.) django.utils.feedgenerator.RssUserland091Feed (RSS 0.91.) django.utils.feedgenerator.Atom1Feed (Atom 1.0.) Enclosures To specify enclosures, such as those used in creating podcast feeds, use the item_enclosure_url, item_enclosure_length and item_enclosure_mime_type hooks. See the ExampleFeed class below for usage examples. Language Feeds created by the syndication framework automatically include the appropriate <language> tag (RSS 2.0) or xml:lang attribute (Atom). This comes directly from your LANGUAGE_CODE setting. URLs The link method/attribute can return either an absolute URL (e.g. "/blog/") or a URL with the fully-qualied domain and protocol (e.g. "http://www.example.com/blog/"). If link doesnt return the domain, the syndication framework will insert the domain of the current site, according to your SITE_ID setting. Atom feeds require a <link rel="self"> that denes the feeds current location. The syndication framework populates this automatically, using the domain of the current site according to the SITE_ID setting. Publishing Atom and RSS feeds in tandem Some developers like to make available both Atom and RSS versions of their feeds. Thats easy to do with Django: Just create a subclass of your Feed class and set the feed_type to something different. Then update your URLconf to add the extra versions. Heres a full example: 49.16. The syndication feed framework 635
from django.contrib.syndication.views import Feed from chicagocrime.models import NewsItem from django.utils.feedgenerator import Atom1Feed class RssSiteNewsFeed(Feed): title = "Chicagocrime.org site news" link = "/sitenews/" description = "Updates on changes and additions to chicagocrime.org." def items(self): return NewsItem.objects.order_by(-pub_date)[:5] class AtomSiteNewsFeed(RssSiteNewsFeed): feed_type = Atom1Feed subtitle = RssSiteNewsFeed.description
Note: In this example, the RSS feed uses a description while the Atom feed uses a subtitle. Thats because Atom feeds dont provide for a feed-level description, but they do provide for a subtitle. If you provide a description in your Feed class, Django will not automatically put that into the subtitle element, because a subtitle and description are not necessarily the same thing. Instead, you should dene a subtitle attribute. In the above example, we simply set the Atom feeds subtitle to the RSS feeds description, because its quite short already. And the accompanying URLconf:
from django.conf.urls.defaults import * from myproject.feeds import RssSiteNewsFeed, AtomSiteNewsFeed urlpatterns = patterns(, # ... (r^sitenews/rss/$, RssSiteNewsFeed()), (r^sitenews/atom/$, AtomSiteNewsFeed()), # ... )
Feed class reference class Feed() This example illustrates all possible attributes and methods for a Feed class:
from django.contrib.syndication.views import Feed from django.utils import feedgenerator class ExampleFeed(Feed): # # # # # FEED TYPE -- Optional. This should be a class that subclasses django.utils.feedgenerator.SyndicationFeed. This designates which type of feed this should be: RSS 2.0, Atom 1.0, etc. If you dont specify feed_type, your feed will be RSS 2.0. This should be a class, not an instance of the class.
feed_type = feedgenerator.Rss201rev2Feed
636
# # # # #
TEMPLATE NAMES -- Optional. These should be strings representing names of Django templates that the system should use in rendering the title and description of your feed items. Both are optional. If a template is not specified, the item_title() or item_description() methods are used instead.
title_template = None description_template = None # TITLE -- One of the following three is required. The framework # looks for them in this order. def title(self, obj): """ Takes the object returned by get_object() and returns the feeds title as a normal Python string. """ def title(self): """ Returns the feeds title as a normal Python string. """ title = foo # Hard-coded title. # LINK -- One of the following three is required. The framework # looks for them in this order. def link(self, obj): """ # Takes the object returned by get_object() and returns the feeds # link as a normal Python string. """ def link(self): """ Returns the feeds link as a normal Python string. """ link = /foo/bar/ # Hard-coded link. # # # # GUID -- One of the following three is optional. The framework looks for them in this order. This property is only used for Atom feeds (where it is the feed-level ID element). If not provided, the feed link is used as the ID.
def feed_guid(self, obj): """ Takes the object returned by get_object() and returns the globally unique ID for the feed as a normal Python string. """ def feed_guid(self): """ Returns the feeds globally unique ID as a normal Python string. """
637
feed_guid = /foo/bar/1234 # Hard-coded guid. # DESCRIPTION -- One of the following three is required. The framework # looks for them in this order. def description(self, obj): """ Takes the object returned by get_object() and returns the feeds description as a normal Python string. """ def description(self): """ Returns the feeds description as a normal Python string. """ description = Foo bar baz. # Hard-coded description. # AUTHOR NAME --One of the following three is optional. The framework # looks for them in this order. def author_name(self, obj): """ Takes the object returned by get_object() and returns the feeds authors name as a normal Python string. """ def author_name(self): """ Returns the feeds authors name as a normal Python string. """ author_name = Sally Smith # Hard-coded author name. # AUTHOR E-MAIL --One of the following three is optional. The framework # looks for them in this order. def author_email(self, obj): """ Takes the object returned by get_object() and returns the feeds authors e-mail as a normal Python string. """ def author_email(self): """ Returns the feeds authors e-mail as a normal Python string. """ author_email = [email protected] # Hard-coded author e-mail. # AUTHOR LINK --One of the following three is optional. The framework # looks for them in this order. In each case, the URL should include # the "http://" and domain name. def author_link(self, obj): """ Takes the object returned by get_object() and returns the feeds authors URL as a normal Python string.
638
""" def author_link(self): """ Returns the feeds authors URL as a normal Python string. """ author_link = http://www.example.com/ # Hard-coded author URL. # CATEGORIES -- One of the following three is optional. The framework # looks for them in this order. In each case, the method/attribute # should return an iterable object that returns strings. def categories(self, obj): """ Takes the object returned by get_object() and returns the feeds categories as iterable over strings. """ def categories(self): """ Returns the feeds categories as iterable over strings. """ categories = ("python", "django") # Hard-coded list of categories. # COPYRIGHT NOTICE -- One of the following three is optional. The # framework looks for them in this order. def feed_copyright(self, obj): """ Takes the object returned by get_object() and returns the feeds copyright notice as a normal Python string. """ def feed_copyright(self): """ Returns the feeds copyright notice as a normal Python string. """ feed_copyright = Copyright (c) 2007, Sally Smith # Hard-coded copyright notice. # TTL -- One of the following three is optional. The framework looks # for them in this order. Ignored for Atom feeds. def ttl(self, obj): """ Takes the object returned by get_object() and returns the feeds TTL (Time To Live) as a normal Python string. """ def ttl(self): """ Returns the feeds TTL as a normal Python string. """ ttl = 600 # Hard-coded Time To Live.
639
# ITEMS -- One of the following three is required. The framework looks # for them in this order. def items(self, obj): """ Takes the object returned by get_object() and returns a list of items to publish in this feed. """ def items(self): """ Returns a list of items to publish in this feed. """ items = (Item 1, Item 2) # Hard-coded items. # GET_OBJECT -- This is required for feeds that publish different data # for different URL parameters. (See "A complex example" above.) def get_object(self, request, *args, **kwargs): """ Takes the current request and the arguments from the URL, and returns an object represented by this feed. Raises django.core.exceptions.ObjectDoesNotExist on error. """ # # # # ITEM TITLE AND DESCRIPTION -- If title_template or description_template are not defined, these are used instead. Both are optional, by default they will use the unicode representation of the item.
def item_title(self, item): """ Takes an item, as returned by items(), and returns the items title as a normal Python string. """ def item_title(self): """ Returns the title for every item in the feed. """ item_title = Breaking News: Nothing Happening # Hard-coded title. def item_description(self, item): """ Takes an item, as returned by items(), and returns the items description as a normal Python string. """ def item_description(self): """ Returns the description for every item in the feed. """ item_description = A description of the item. # Hard-coded description. # ITEM LINK -- One of these three is required. The framework looks for
640
# them in this order. # First, the framework tries the two methods below, in # order. Failing that, it falls back to the get_absolute_url() # method on each item returned by items(). def item_link(self, item): """ Takes an item, as returned by items(), and returns the items URL. """ def item_link(self): """ Returns the URL for every item in the feed. """ # ITEM_GUID -- The following method is optional. If not provided, the # items link is used by default. def item_guid(self, obj): """ Takes an item, as return by items(), and returns the items ID. """ # ITEM AUTHOR NAME -- One of the following three is optional. The # framework looks for them in this order. def item_author_name(self, item): """ Takes an item, as returned by items(), and returns the items authors name as a normal Python string. """ def item_author_name(self): """ Returns the author name for every item in the feed. """ item_author_name = Sally Smith # Hard-coded author name. # ITEM AUTHOR E-MAIL --One of the following three is optional. The # framework looks for them in this order. # # If you specify this, you must specify item_author_name. def item_author_email(self, obj): """ Takes an item, as returned by items(), and returns the items authors e-mail as a normal Python string. """ def item_author_email(self): """ Returns the author e-mail for every item in the feed. """ item_author_email = [email protected] # Hard-coded author e-mail.
641
# # # # #
ITEM AUTHOR LINK -- One of the following three is optional. The framework looks for them in this order. In each case, the URL should include the "http://" and domain name. If you specify this, you must specify item_author_name.
def item_author_link(self, obj): """ Takes an item, as returned by items(), and returns the items authors URL as a normal Python string. """ def item_author_link(self): """ Returns the author URL for every item in the feed. """ item_author_link = http://www.example.com/ # Hard-coded author URL. # ITEM ENCLOSURE URL -- One of these three is required if youre # publishing enclosures. The framework looks for them in this order. def item_enclosure_url(self, item): """ Takes an item, as returned by items(), and returns the items enclosure URL. """ def item_enclosure_url(self): """ Returns the enclosure URL for every item in the feed. """ item_enclosure_url = "/foo/bar.mp3" # Hard-coded enclosure link. # # # # ITEM ENCLOSURE LENGTH -- One of these three is required if youre publishing enclosures. The framework looks for them in this order. In each case, the returned value should be either an integer, or a string representation of the integer, in bytes.
def item_enclosure_length(self, item): """ Takes an item, as returned by items(), and returns the items enclosure length. """ def item_enclosure_length(self): """ Returns the enclosure length for every item in the feed. """ item_enclosure_length = 32000 # Hard-coded enclosure length. # ITEM ENCLOSURE MIME TYPE -- One of these three is required if youre # publishing enclosures. The framework looks for them in this order. def item_enclosure_mime_type(self, item): """
642
Takes an item, as returned by items(), and returns the items enclosure MIME type. """ def item_enclosure_mime_type(self): """ Returns the enclosure MIME type for every item in the feed. """ item_enclosure_mime_type = "audio/mpeg" # Hard-coded enclosure MIME type. # # # # ITEM PUBDATE -- Its optional to use one of these three. This is a hook that specifies how to get the pubdate for a given item. In each case, the method/attribute should return a Python datetime.datetime object.
def item_pubdate(self, item): """ Takes an item, as returned by items(), and returns the items pubdate. """ def item_pubdate(self): """ Returns the pubdate for every item in the feed. """ item_pubdate = datetime.datetime(2005, 5, 3) # Hard-coded pubdate. # # # # ITEM CATEGORIES -- Its optional to use one of these three. This is a hook that specifies how to get the list of categories for a given item. In each case, the method/attribute should return an iterable object that returns strings.
def item_categories(self, item): """ Takes an item, as returned by items(), and returns the items categories. """ def item_categories(self): """ Returns the categories for every item in the feed. """ item_categories = ("python", "django") # Hard-coded categories. # ITEM COPYRIGHT NOTICE (only applicable to Atom feeds) -- One of the # following three is optional. The framework looks for them in this # order. def item_copyright(self, obj): """ Takes an item, as returned by items(), and returns the items copyright notice as a normal Python string. """ def item_copyright(self):
643
""" Returns the copyright notice for every item in the feed. """ item_copyright = Copyright (c) 2007, Sally Smith # Hard-coded copyright notice.
644
Any extra keyword arguments you pass to __init__ will be stored in self.feed for use with custom feed generators. All parameters should be Unicode objects, except categories, which should be a sequence of Unicode objects. add_item(**kwargs) Add an item to the feed with the given parameters. Required keyword arguments are: title link description Optional keyword arguments are: author_email author_name author_link pubdate comments unique_id enclosure categories item_copyright ttl Extra keyword arguments will be stored for custom feed generators. All parameters, if given, should be Unicode objects, except: pubdate should be a Python datetime object. enclosure should be an instance of feedgenerator.Enclosure. categories should be a sequence of Unicode objects. write(outle, encoding) Outputs the feed in the given encoding to outle, which is a le-like object. writeString(encoding) Returns the feed as a string in the given encoding. For example, to create an Atom 1.0 feed and print it to standard output:
>>> >>> >>> ... ... ... ... ... ... >>> from django.utils import feedgenerator from datetime import datetime f = feedgenerator.Atom1Feed( title=u"My Weblog", link=u"http://www.example.com/", description=u"In which I write about what I ate today.", language=u"en", author_name=u"Myself", feed_url=u"http://example.com/atom.xml") f.add_item(title=u"Hot dog today",
645
... link=u"http://www.example.com/entries/1/", ... pubdate=datetime.now(), ... description=u"<p>Today I had a Vienna Beef hot dog. It was pink, plump and perfect.</p>") >>> print f.writeString(UTF-8) <?xml version="1.0" encoding="UTF-8"?> <feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"> ... </feed>
Custom feed generators If you need to produce a custom feed format, youve got a couple of options. If the feed format is totally custom, youll want to subclass SyndicationFeed and completely replace the write() and writeString() methods. However, if the feed format is a spin-off of RSS or Atom (i.e. GeoRSS, Apples iTunes podcast format, etc.), youve got a better choice. These types of feeds typically add extra elements and/or attributes to the underlying format, and there are a set of methods that SyndicationFeed calls to get these extra attributes. Thus, you can subclass the appropriate feed generator class (Atom1Feed or Rss201rev2Feed) and extend these callbacks. They are: SyndicationFeed.root_attributes(self, ) Return a dict of attributes to add to the root feed element (feed/channel). SyndicationFeed.add_root_elements(self, handler) Callback to add elements inside the root feed element (feed/channel). handler is an XMLGenerator from Pythons built-in SAX library; youll call methods on it to add to the XML document in process. SyndicationFeed.item_attributes(self, item) Return a dict of attributes to add to each item (item/entry) element. The argument, item, is a dictionary of all the data passed to SyndicationFeed.add_item(). SyndicationFeed.add_item_elements(self, handler, item) Callback to add elements to each item (item/entry) element. handler and item are as above. Warning: If you override any of these methods, be sure to call the superclass methods since they add the required elements for each feed format. For example, you might start implementing an iTunes RSS feed generator like so:
class iTunesFeed(Rss201rev2Feed): def root_attributes(self): attrs = super(iTunesFeed, self).root_attributes() attrs[xmlns:itunes] = http://www.itunes.com/dtds/podcast-1.0.dtd return attrs def add_root_elements(self, handler): super(iTunesFeed, self).add_root_elements(handler) handler.addQuickElement(itunes:explicit, clean)
Obviously theres a lot more work to be done for a complete custom feed class, but the above example should demonstrate the basic idea.
49.17 django.contrib.webdesign
646
The django.contrib.webdesign package, part of the django.contrib add-ons, provides various Django helpers that are particularly useful to Web designers (as opposed to developers). At present, the package contains only a single template tag. If you have ideas for Web-designer-friendly functionality in Django, please suggest them.
49.17.2 lorem
Displays random lorem ipsum Latin text. This is useful for providing sample data in templates. Usage:
{% lorem [count] [method] [random] %}
The {% lorem %} tag can be used with zero, one, two or three arguments. The arguments are: Argument count method random Examples: {% lorem %} will output the common lorem ipsum paragraph. {% lorem 3 p %} will output the common lorem ipsum paragraph and two random paragraphs each wrapped in HTML <p> tags. {% lorem 2 w random %} will output two random Latin words. Description A number (or variable) containing the number of paragraphs or words to generate (default is 1). Either w for words, p for HTML paragraphs or b for plain-text paragraph blocks (default is b). The word random, which if given, does not use the common paragraph (Lorem ipsum dolor sit amet...) when generating text.
49.18 admin
The automatic Django administrative interface. For more information, see Tutorial 2 and the admin documentation. Requires the auth and contenttypes contrib packages to be installed.
49.19 auth
Djangos authentication framework. See User authentication in Django.
49.18. admin
647
49.20 comments
Changed in version 1.0: The comments application has been rewriten. See Upgrading from Djangos previous comment system for information on howto upgrade. A simple yet exible comments system. See Djangos comments framework.
49.21 contenttypes
A light framework for hooking into types of content, where each installed Django model is a separate content type. See the contenttypes documentation.
49.22 csrf
A middleware for preventing Cross Site Request Forgeries See the csrf documentation.
49.23 atpages
A framework for managing simple at HTML content in a database. See the atpages documentation. Requires the sites contrib package to be installed as well.
49.24 formtools
A set of high-level abstractions for Django forms (django.forms).
49.24.1 django.contrib.formtools.preview
An abstraction of the following workow: Display an HTML form, force a preview, then do something with the submission. See the form preview documentation.
49.24.2 django.contrib.formtools.wizard
Splits forms across multiple Web pages. See the form wizard documentation.
648
49.25 gis
A world-class geospatial framework built on top of Django, that enables storage, manipulation and display of spatial data. See the GeoDjango documentation for more.
49.26 humanize
A set of Django template lters useful for adding a human touch to data. See the humanize documentation.
49.27 localavor
A collection of various Django snippets that are useful only for a particular country or culture. For example, django.contrib.localflavor.us.forms contains a USZipCodeField that you can use to validate U.S. zip codes. See the localavor documentation.
49.28 markup
A collection of template lters that implement common markup languages: textile implements Textile requires PyTextile markdown implements Markdown requires Python-markdown restructuredtext implements ReST (ReStructured Text) requires doc-utils In each case, the lter expects formatted markup as a string and returns a string representing the marked-up text. For example, the textile lter converts text that is marked-up in Textile format to HTML. To activate these lters, add django.contrib.markup to your INSTALLED_APPS setting. Once youve done that, use {% load markup %} in a template, and youll have access to these lters. For more documentation, read the source code in django/contrib/markup/templatetags/markup.py.
49.29 messages
Changed in version 1.2: The messages framework was added. A framework for storing and retrieving temporary cookie- or session-based messages See the messages documentation.
49.25. gis
649
49.30 redirects
A framework for managing redirects. See the redirects documentation.
49.31 sessions
A framework for storing data in anonymous sessions. See the sessions documentation.
49.32 sites
A light framework that lets you operate multiple Web sites off of the same database and Django installation. It gives you hooks for associating objects to one or more sites. See the sites documentation.
49.33 sitemaps
A framework for generating Google sitemap XML les. See the sitemaps documentation.
49.34 syndication
A framework for generating syndication feeds, in RSS and Atom, quite easily. See the syndication documentation.
49.35 webdesign
Helpers and utilities targeted primarily at Web designers rather than Web developers. See the Web design helpers documentation.
650
CHAPTER
FIFTY
DATABASES
Django attempts to support as many features as possible on all database backends. However, not all database backends are alike, and weve had to make design decisions on which features to support and which assumptions we can make safely. This le describes some of the features that might be relevant to Django usage. Of course, it is not intended as a replacement for server-specic documentation or reference manuals.
651
In this conguration, Django still ensures that delete() and update() queries run inside a single transaction, so that either all the affected objects are changed or none of them are. This is database-level autocommit This functionality is not the same as the django.db.transaction.autocommit decorator. That decorator is a Django-level implementation that commits automatically after data changing operations. The feature enabled using the OPTIONS option provides autocommit behavior at the database adapter level. It commits after every operation. If you are using this feature and performing an operation akin to delete or updating that requires multiple operations, you are strongly recommended to wrap you operations in manual transaction handling to ensure data consistency. You should also audit your existing code for any instances of this behavior before enabling this feature. Its faster, but it provides less automatic protection for multi-call operations. Indexes for varchar and text columns New in version 1.1.2: Please, see the release notes When specifying db_index=True on your model elds, Django typically outputs a single CREATE INDEX statement. However, if the database type for the eld is either varchar or text (e.g., used by CharField, FileField, and TextField), then Django will create an additional index that uses an appropriate PostgreSQL operator class for the column. The extra index is necessary to correctly perfrom lookups that use the LIKE operator in their SQL, as is done with the contains and startswith lookup types.
652
The InnoDB engine is fully transactional and supports foreign key references. The BDB engine, like InnoDB, is also fully transactional and supports foreign key references. However, its use seems to be deprecated. Other storage engines, including SolidDB and Falcon, are on the horizon. For now, InnoDB is probably your best choice.
50.2.4 MySQLdb
MySQLdb is the Python interface to MySQL. Version 1.2.1p2 or later is required for full MySQL support in Django. Note: If you see ImportError: cannot import name ImmutableSet when trying to use Django, your MySQLdb installation may contain an outdated sets.py le that conicts with the built-in module of the same name from Python 2.4 and later. To x this, verify that you have installed MySQLdb version 1.2.1p2 or newer, then delete the sets.py le in the MySQLdb directory that was left by an earlier version.
This ensures all tables and columns will use UTF-8 by default. Collation settings The collation setting for a column controls the order in which data is sorted as well as what strings compare as equal. It can be set on a database-wide level and also per-table and per-column. This is documented thoroughly in the MySQL documentation. In all cases, you set the collation by directly manipulating the database tables; Django doesnt provide a way to set this on the model denition. By default, with a UTF-8 database, MySQL will use the utf8_general_ci_swedish collation. This results in all string equality comparisons being done in a case-insensitive manner. That is, "Fred" and "freD" are considered equal at the database level. If you have a unique constraint on a eld, it would be illegal to try to insert both "aa" and "AA" into the same column, since they compare as equal (and, hence, non-unique) with the default collation. In many cases, this default will not be a problem. However, if you really want case-sensitive comparisons on a particular column or table, you would change the column or table to use the utf8_bin collation. The main thing to be aware of in this case is that if you are using MySQLdb 1.2.2, the database backend in Django will then return bytestrings (instead of unicode strings) for any character elds it returns receive from the database. This is a strong variation from Djangos normal practice of always returning unicode strings. It is up to you, the developer, to handle the fact that you will receive bytestrings if you congure your table(s) to use utf8_bin collation. Django itself should work smoothly with such columns, but if your code must be prepared to call django.utils.encoding.smart_unicode() at times if it really wants to work with consistent data Django will not do this for you (the database backend layer and the model population layer are separated internally so the database layer doesnt know it needs to make this conversion in this one particular case). If youre using MySQLdb 1.2.1p2, Djangos standard CharField class will return unicode strings even with utf8_bin collation. However, TextField elds will be returned as an array.array instance (from Pythons standard array module). There isnt a lot Django can do about that, since, again, the information needed to make the necessary conversions isnt available when the data is read in from the database. This problem was xed in MySQLdb 1.2.2, so if you want to use TextField with utf8_bin collation, upgrading to version 1.2.2 and then dealing with the bytestrings (which shouldnt be too difcult) is the recommended solution.
653
Should you decide to use utf8_bin collation for some of your tables with MySQLdb 1.2.1p2, you should still use utf8_collation_ci_swedish (the default) collation for the django.contrib.sessions.models.Session table (usually called django_session) and the django.contrib.admin.models.LogEntry table (usually called django_admin_log). Those are the two standard tables that use TextField internally.
# my.cnf [client] database = NAME user = USER password = PASSWORD default-character-set = utf8
Several other MySQLdb connection options may be useful, such as ssl, use_unicode, init_command, and sql_mode. Consult the MySQLdb documentation for more details.
This can be tedious if you have a lot of tables. 654 Chapter 50. Databases
Another option is to use the init_command option for MySQLdb prior to creating your tables:
OPTIONS = { "init_command": "SET storage_engine=INNODB", }
This sets the default storage engine upon connecting to the database. After your tables have been created, you should remove this option. Another method for changing the storage engine is described in AlterModelOnSyncDB.
655
SQLite 3.3.6 was released in April 2006, so most current binary distributions for different platforms include newer version of SQLite usable from Python through either the pysqlite2 or the sqlite3 modules. However, some platform/Python version combinations include older versions of SQLite (e.g. the ofcial binary distribution of Python 2.5 for Windows, 2.5.4 as of this writing, includes SQLite 3.3.4). There are (as of Django 1.1) even some tests in the Django test suite that will fail when run under this setup. As described below, this can be solved by downloading and installing a newer version of pysqlite2 (pysqlite-2.x.x.win32-py2.5.exe in the described case) that includes and uses a newer version of SQLite. Python 2.6 for Windows ships with a version of SQLite that is not affected by these issues.
656
Increase the default timeout value by setting the timeout database option option:
OPTIONS = { # ... "timeout": 20, # ... }
This will simply make SQLite wait a bit longer before throwing database is locked errors; it wont really do anything to solve them.
657
} }
If you dont use a tnsnames.ora le or a similar naming method that recognizes the SID (xe in this example), then ll in both HOST and PORT like so:
DATABASES = { default: { ENGINE: django.db.backends.oracle, NAME: xe, USER: a_user, PASSWORD: a_password, HOST: dbprod01ned.mycompany.com, PORT: 1540, } }
You should supply both HOST and PORT, or leave both as empty strings.
In this example, the tables generated by the TablespaceExample model (i.e., the model table and the manyto-many table) would be stored in the tables tablespace. The index for the name eld and the indexes on the many-to-many table would be stored in the indexes tablespace. The data eld would also generate an index, but no tablespace for it is specied, so it would be stored in the model tablespace tables by default. New in version 1.0: Please, see the release notes Use the DEFAULT_TABLESPACE and DEFAULT_INDEX_TABLESPACE settings to specify default values for the db_tablespace options. These are useful for setting a tablespace for the built-in Django apps and other applications whose code you cannot control. Django does not create the tablespaces for you. Please refer to Oracles documentation for details on creating and managing tablespaces.
658
When running syncdb, an ORA-06552 error may be encountered if certain Oracle keywords are used as the name of a model eld or the value of a db_column option. Django quotes all identiers used in queries to prevent most such problems, but this error can still occur when an Oracle datatype is used as a column name. In particular, take care to avoid using the names date, timestamp, number or float as a eld name.
659
660
CHAPTER
FIFTYONE
51.1 Usage
django-admin.py <subcommand> [options] manage.py <subcommand> [options]
subcommand should be one of the subcommands listed in this document. options, which is optional, should be zero or more of the options available for the given subcommand.
661
51.2.2 compilemessages
django-admin.py compilemessages Changed in version 1.0: Before 1.0 this was the bin/compile-messages.py command. Compiles .po les created with makemessages to .mo les for use with the builtin gettext support. See Internationalization and localization. Use the --locale option to specify the locale to process. If not provided, all locales are processed. Example usage:
django-admin.py compilemessages --locale=br_PT
51.2.3 createcachetable
django-admin.py createcachetable Creates a cache table named tablename for use with the database cache backend. See Djangos cache framework for more information. New in version 1.2: Please, see the release notes The --database option can be used to specify the database onto which the cachetable will be installed.
662
51.2.4 createsuperuser
django-admin.py createsuperuser New in version 1.0: Please, see the release notes Creates a superuser account (a user who has all permissions). This is useful if you need to create an initial superuser account but did not do so during syncdb, or if you need to programmatically generate superuser accounts for your site(s). When run interactively, this command will prompt for a password for the new superuser account. When run noninteractively, no password will be set, and the superuser account will not be able to log in until a password has been manually set for it. -username -email The username and e-mail address for the new account can be supplied by using the --username and --email arguments on the command line. If either of those is not supplied, createsuperuser will prompt for it when running interactively. This command is only available if Djangos authentication system (django.contrib.auth) is installed.
51.2.5 dbshell
django-admin.py dbshell Runs the command-line client for the database engine specied in your ENGINE setting, with the connection parameters specied in your USER, PASSWORD, etc., settings. For PostgreSQL, this runs the psql command-line client. For MySQL, this runs the mysql command-line client. For SQLite, this runs the sqlite3 command-line client. This command assumes the programs are on your PATH so that a simple call to the program name (psql, mysql, sqlite3) will nd the program in the right place. Theres no way to specify the location of the program manually. New in version 1.2: Please, see the release notes The --database option can be used to specify the database onto which to open a shell.
51.2.6 diffsettings
django-admin.py diffsettings Displays differences between the current settings le and Djangos default settings. Settings that dont appear in the defaults are followed by "###". For example, the default settings dont dene ROOT_URLCONF, so ROOT_URLCONF is followed by "###" in the output of diffsettings. Note that Djangos default settings live in django/conf/global_settings.py, if youre ever curious to see the full list of defaults.
663
Outputs to standard output all data in the database associated with the named application(s). If no application name is provided, all installed applications will be dumped. The output of dumpdata can be used as input for loaddata. Note that dumpdata uses the default manager on the model for selecting the records to dump. If youre using a custom manager as the default manager and it lters some of the available records, not all of the objects will be dumped. -format <fmt> By default, dumpdata will format its output in JSON, but you can use the --format option to specify another format. Currently supported formats are listed in Serialization formats. -indent <num> By default, dumpdata will output all data on a single line. This isnt easy for humans to read, so you can use the --indent option to pretty-print the output with a number of indentation spaces. New in version 1.0: Please, see the release notes The --exclude option may be provided to prevent specic applications from being dumped. New in version 1.1: Please, see the release notes In addition to specifying application names, you can provide a list of individual models, in the form of appname.Model. If you specify a model name to dumpdata, the dumped output will be restricted to that model, rather than the entire application. You can also mix application names and model names. New in version 1.2: Please, see the release notes The --database option can be used to specify the database onto which the data will be loaded. -natural New in version 1.2: Please, see the release notes Use natural keys to represent any foreign key and many-to-many relationship with a model that provides a natural key denition. If you are dumping contrib.auth Permission objects or contrib.contenttypes ContentType objects, you should probably be using this ag.
51.2.8 ush
django-admin.py flush Returns the database to the state it was in immediately after syncdb was executed. This means that all data will be removed from the database, any post-synchronization handlers will be re-executed, and the initial_data xture will be re-installed. The --noinput option may be provided to suppress all user prompts. New in version 1.2: Please, see the release notes The --database option may be used to specify the database to ush.
51.2.9 inspectdb
django-admin.py inspectdb Introspects the database tables in the database pointed-to by the NAME setting and outputs a Django model module (a models.py le) to standard output. Use this if you have a legacy database with which youd like to use Django. The script will inspect the database and create a model for each table within it. As you might expect, the created models will have an attribute for every eld in the table. Note that inspectdb has a few special cases in its eld-name output: If inspectdb cannot map a columns type to a model eld type, itll use TextField and will insert the Python comment This field type is a guess. next to the eld in the generated model.
664
If the database column name is a Python reserved word (such as pass, class or for), inspectdb will append _field to the attribute name. For example, if a table has a column for, the generated model will have a eld for_field, with the db_column attribute set to for. inspectdb will insert the Python comment Field renamed because it was a Python reserved word. next to the eld. This feature is meant as a shortcut, not as denitive model generation. After you run it, youll want to look over the generated models yourself to make customizations. In particular, youll need to rearrange models order, so that models that refer to other models are ordered properly. Primary keys are automatically introspected for PostgreSQL, MySQL and SQLite, in which case Django puts in the primary_key=True where needed. inspectdb works with PostgreSQL, MySQL and SQLite. Foreign-key detection only works in PostgreSQL and with certain types of MySQL tables. New in version 1.2: Please, see the release notes The --database option may be used to specify the database to introspect.
would only load JSON xtures called mydata. The xture extension must correspond to the registered name of a serializer (e.g., json or xml). If you omit the extensions, Django will search all available xture types for a matching xture. For example:
django-admin.py loaddata mydata
would look for any xture of any xture type called mydata. If a xture directory contained mydata.json, that xture would be loaded as a JSON xture. The xtures that are named can include directory components. These directories will be included in the search path. For example:
django-admin.py loaddata foo/bar/mydata.json
665
would search <appname>/fixtures/foo/bar/mydata.json for each installed application, <dirname>/foo/bar/mydata.json for each directory in FIXTURE_DIRS, and the literal path foo/bar/mydata.json. When xture les are processed, the data is saved to the database as is. Model dened save methods and pre_save signals are not called. Note that the order in which xture les are processed is undened. However, all xture data is installed as a single transaction, so data in one xture can reference data in another xture. If the database backend supports row-level constraints, these constraints will be checked at the end of the transaction. The dumpdata command can be used to generate input for loaddata. Compressed xtures Fixtures may be compressed in zip, gz, or bz2 format. For example:
django-admin.py loaddata mydata.json
would look for any of mydata.json, mydata.json.zip, mydata.json.gz, or mydata.json.bz2. The rst le contained within a zip-compressed archive is used. Note that if two xtures with the same name but different xture type are discovered (for example, if mydata.json and mydata.xml.gz were found in the same xture directory), xture installation will be aborted, and any data installed in the call to loaddata will be removed from the database. MySQL and Fixtures Unfortunately, MySQL isnt capable of completely supporting all the features of Django xtures. If you use MyISAM tables, MySQL doesnt support transactions or constraints, so you wont get a rollback if multiple transaction les are found, or validation of xture data. If you use InnoDB tables, you wont be able to have any forward references in your data les - MySQL doesnt provide a mechanism to defer checking of row constraints until a transaction is committed. Database-specic xtures If you are in a multi-database setup, you may have xture data that you want to load onto one database, but not onto another. In this situation, you can add database identier into . If your DATABASES setting has a master database dened, you can dene the xture mydata.master.json or mydata.master.json.gz. This xture will only be loaded if you have specied that you want to load data onto the master database.
51.2.11 makemessages
django-admin.py makemessages Changed in version 1.0: Before 1.0 this was the bin/make-messages.py command. Runs over the entire source tree of the current directory and pulls out all strings marked for translation. It creates (or updates) a message le in the conf/locale (in the django tree) or locale (for project and application) directory. After making changes to the messages les you need to compile them with compilemessages for use with the builtin gettext support. See the i18n documentation for details. -all Use the --all or -a option to update the message les for all available languages. Example usage:
666
-extension Use the --extension or -e option to specify a list of le extensions to examine (default: .html). Example usage:
django-admin.py makemessages --locale=de --extension xhtml
Use the --locale option to specify the locale to process. Example usage:
django-admin.py makemessages --locale=br_PT
-domain Use the --domain or -d option to change the domain of the messages les. Currently supported: django for all *.py and *.html les (default) djangojs for *.js les -symlinks New in version 1.2: Please, see the release notes Use the --symlinks or -s option to follow symlinks to directories when looking for new translation strings. Example usage:
django-admin.py makemessages --locale=de --symlinks
-ignore Use the --ignore or -i option to ignore les or directories matching the given glob-style pattern. Use multiple times to ignore more. These patterns are used by default: CVS, .*, *~ Example usage:
django-admin.py makemessages --locale=en_US --ignore=apps/* --ignore=secret/*.html
-no-default-ignore Use the --no-default-ignore option to disable the default values of --ignore.
667
-noreload Use the --noreload option to disable the use of the auto-reloader. This means any Python code changes you make while the server is running will not take effect if the particular Python modules have already been loaded into memory. Example usage:
django-admin.py runserver --noreload
Examples of using different ports and addresses Port 8000 on IP address 127.0.0.1:
668
django-admin.py runserver
Serving static les with the development server By default, the development server doesnt serve any static les for your site (such as CSS les, images, things under MEDIA_URL and so forth). If you want to congure Django to serve static media, read How to serve static les.
51.2.15 shell
django-admin.py shell Starts the Python interactive interpreter. Django will use IPython, if its installed. If you have IPython installed and want to force use of the plain Python interpreter, use the --plain option, like so:
django-admin.py shell --plain
669
51.2.20 sqlush
django-admin.py sqlflush Prints the SQL statements that would be executed for the flush command. New in version 1.2: Please, see the release notes The --database option can be used to specify the database for which to print the SQL.
670
Use this command to generate SQL which will x cases where a sequence is out of sync with its automatically incremented eld data. New in version 1.2: Please, see the release notes The --database option can be used to specify the database for which to print the SQL.
51.2.26 syncdb
django-admin.py syncdb Creates the database tables for all apps in INSTALLED_APPS whose tables have not already been created. Use this command when youve added new applications to your project and want to install them in the database. This includes any apps shipped with Django that might be in INSTALLED_APPS by default. When you start a new project, run this command to install the default apps. Syncdb will not alter existing tables syncdb will only create tables for models which have not yet been installed. It will never issue ALTER TABLE statements to match changes made to a model class after installation. Changes to model classes and database schemas often involve some form of ambiguity and, in those cases, Django would have to guess at the correct changes to make. There is a risk that critical data would be lost in the process. If you have made changes to a model and wish to alter the database tables to match, use the sql command to display the new SQL structure and compare that to your existing table schema to work out the changes. If youre installing the django.contrib.auth application, syncdb will give you the option of creating a superuser immediately. syncdb will also search for and install any xture named initial_data with an appropriate extension (e.g. json or xml). See the documentation for loaddata for details on the specication of xture data les. noinput The --noinput option may be provided to suppress all user prompts. New in version 1.2: Please, see the release notes The --database option can be used to specify the database to synchronize.
671
...would perform the following steps: 1. Create a test database, as described in Testing Django applications. 2. Populate the test database with xture data from the given xtures. (For more on xtures, see the documentation for loaddata above.) 3. Runs the Django development server (as in runserver), pointed at this newly created test database instead of your production database. This is useful in a number of ways: When youre writing unit tests of how your views act with certain xture data, you can use testserver to interact with the views in a Web browser, manually. Lets say youre developing your Django application and have a pristine copy of a database that youd like to interact with. You can dump your database to a xture (using the dumpdata command, explained above), then use testserver to run your Web application with that data. With this arrangement, you have the exibility of messing up your data in any way, knowing that whatever data changes youre making are only being made to a test database. Note that this server does not automatically detect changes to your Python source code (as runserver does). It does, however, detect changes to templates. -addrport [port number or ipaddr:port] Use --addrport to specify a different port, or IP address and port, from the default of 127.0.0.1:8000. This value follows exactly the same format and serves exactly the same function as the argument to the runserver subcommand. Examples: To run the test server on port 7000 with fixture1 and fixture2:
django-admin.py testserver --addrport 7000 fixture1 fixture2 django-admin.py testserver fixture1 fixture2 --addrport 7000
672
(The above statements are equivalent. We include both of them to demonstrate that it doesnt matter whether the options come before or after the xture arguments.) To run on 1.2.3.4:7000 with a test xture:
django-admin.py testserver --addrport 1.2.3.4:7000 test
51.2.29 validate
django-admin.py validate Validates all installed models (according to the INSTALLED_APPS setting) and prints validation errors to standard output.
Adds the given lesystem path to the Python import search path. If this isnt provided, django-admin.py will use the PYTHONPATH environment variable. Note that this option is unnecessary in manage.py, because it takes care of setting the Python path for you. -settings Example usage:
django-admin.py syncdb --settings=mysite.settings
Explicitly species the settings module to use. The settings module should be in Python package syntax, e.g. mysite.settings. If this isnt provided, django-admin.py will use the DJANGO_SETTINGS_MODULE environment variable. Note that this option is unnecessary in manage.py, because it uses settings.py from the current project by default. -traceback Example usage:
django-admin.py syncdb --traceback
By default, django-admin.py will show a simple error message whenever an error occurs. If you specify --traceback, django-admin.py will output a full stack trace whenever an exception is raised. -verbosity Example usage:
673
Use --verbosity to specify the amount of notication and debug information that django-admin.py should print to the console. 0 means no output. 1 means normal output (default). 2 means verbose output.
-exclude Exclude a specic application from the applications whose contents is output. For example, to specically exclude the auth application from the output of dumpdata, you would call:
django-admin.py dumpdata --exclude=auth
-locale Use the --locale or -l option to specify the locale to process. If not provided all locales are processed. -noinput Use the --noinput option to suppress all user prompting, such as Are you sure? conrmation messages. This is useful if django-admin.py is being executed as an unattended, automated script.
674
nocolor, which disables syntax highlighting. You select a palette by setting a DJANGO_COLORS environment variable to specify the palette you want to use. For example, to specify the light palette under a Unix or OS/X BASH shell, you would run the following at a command prompt:
export DJANGO_COLORS="light"
You can also customize the colors that are used. Django species a number of roles in which color is used: error - A major error. notice - A minor error. sql_field - The name of a model eld in SQL. sql_coltype - The type of a model eld in SQL. sql_keyword - A SQL keyword. sql_table - The name of a model in SQL. http_info - A 1XX HTTP Informational server response. http_success - A 2XX HTTP Success server response. http_not_modified - A 304 HTTP Not Modied server response. http_redirect - A 3XX HTTP Redirect server response other than 304. http_not_found - A 404 HTTP Not Found server response. http_bad_request - A 4XX HTTP Bad Request server response other than 404. http_server_error - A 5XX HTTP Server Error response. Each of these roles can be assigned a specic foreground and background color, from the following list: black red green yellow blue magenta cyan white Each of these colors can then be modied by using the following display options: bold underscore blink reverse conceal A color specication follows one of the the following patterns: role=fg
675
role=fg/bg role=fg,option,option role=fg/bg,option,option where role is the name of a valid color role, fg is the foreground color, bg is the background color and each option is one of the color modifying options. Multiple color specications are then separated by semicolon. For example:
export DJANGO_COLORS="error=yellow/blue,blink;notice=magenta"
would specify that errors be displayed using blinking yellow on blue, and notices displayed using magenta. All other color roles would be left uncolored. Colors can also be specied by extending a base palette. If you put a palette name in a color specication, all the colors implied by that palette will be loaded. So:
export DJANGO_COLORS="light;error=yellow/blue,blink;notice=magenta"
would specify the use of all the colors in the light color palette, except for the colors for errors and notices which would be overridden as specied.
676
CHAPTER
FIFTYTWO
DJANGO EXCEPTIONS
Django raises some Django specic exceptions as well as many standard Python exceptions.
52.1.2 MultipleObjectsReturned
The MultipleObjectsReturned exception is raised by a query if only one object is expected, but multiple objects are returned. A base version of this exception is provided in django.core.exceptions; each model class contains a subclassed version that can be used to identify the specic object type that has returned multiple objects. See get() for further information.
52.1.3 SuspiciousOperation
The SuspiciousOperation exception is raised when a user has performed an operation that should be considered suspicious from a security perspective, such as tampering with a session cookie.
52.1.4 PermissionDenied
The PermissionDenied exception is raised when a user does not have permission to perform the action requested.
52.1.5 ViewDoesNotExist
The ViewDoesNotExist exception is raised by django.core.urlresolvers when a requested view does not exist.
677
52.1.6 MiddlewareNotUsed
The MiddlewareNotUsed exception is raised when a middleware is not used in the server conguration.
52.1.7 ImproperlyCongured
The ImproperlyConfigured exception is raised when Django is somehow improperly congured for example, if a value in settings.py is incorrect or unparseable.
52.1.8 FieldError
The FieldError exception is raised when there is a problem with a model eld. This can happen for several reasons: A eld in a model clashes with a eld of the same name from an abstract base class An innite loop is caused by ordering A keyword cannot be parsed from the lter parameters If a eld cannot be determined from a keyword in the query parameters If a join is not permitted on the specied eld If a eld name is invalid If a query contains invalid order_by arguments
678
CHAPTER
FIFTYTHREE
FILE HANDLING
53.1 The File object
class File(le_object)
size The size of the le in bytes. open(mode=None) Open or reopen the le (which by denition also does File.seek(0)). The mode argument allows the same values as Pythons standard open(). When reopening a le, mode will override whatever mode the le was originally opened with; None means to reopen with the original mode. read(num_bytes=None) Read content from the le. The optional size is the number of bytes to read; if not specied, the le will be read to the end. __iter__() Iterate over the le yielding one line at a time. chunks(chunk_size=None) Iterate over the le yielding chunks of a given size. chunk_size defaults to 64 KB.
679
This is especially useful with very large les since it allows them to be streamed off disk and avoids storing the whole le in memory. multiple_chunks(chunk_size=None) Returns True if the le is large enough to require multiple chunks to access all of its content give some chunk_size. write(content) Writes the specied content string to the le. Depending on the storage system behind the scenes, this content might not be fully committed until close() is called on the le. close() Close the le.
Note that the content argument must be an instance of File or of a subclass of File. delete(save=True) Remove the le from the model instance and delete the underlying le. The save argument works as above.
53.2.2 Storage.path(name)
The local lesystem path where the le can be opened using Pythons standard open(). For storage systems that arent accessible from the local lesystem, this will raise NotImplementedError instead. 680 Chapter 53. File handling
53.2.3 Storage.size(name)
Returns the total size, in bytes, of the le referenced by name.
53.2.4 Storage.url(name)
Returns the URL where the contents of the le referenced by name can be accessed.
53.2.7 Storage.delete(name)
Deletes the le referenced by name. This method wont raise an exception if the le doesnt exist.
681
682
CHAPTER
FIFTYFOUR
FORMS
Detailed form API reference. For introductory material, see Working with forms.
To bind data to a form, pass the data as a dictionary as the rst parameter to your Form class constructor:
>>> data = {subject: hello, ... message: Hi there, ... sender: [email protected], ... cc_myself: True} >>> f = ContactForm(data)
In this dictionary, the keys are the eld names, which correspond to the attributes in your Form class. The values are the data youre trying to validate. These will usually be strings, but theres no requirement that they be strings; the type of data you pass depends on the Field, as well see in a moment. is_bound If you need to distinguish between bound and unbound form instances at runtime, check the value of the forms is_bound attribute:
683
>>> f = ContactForm() >>> f.is_bound False >>> f = ContactForm({subject: hello}) >>> f.is_bound True
Note that passing an empty dictionary creates a bound form with empty data:
>>> f = ContactForm({}) >>> f.is_bound True
If you have a bound Form instance and want to change the data somehow, or if you want to bind an unbound Form instance to some data, create another Form instance. There is no way to change data in a Form instance. Once a Form instance has been created, you should consider its data immutable, whether it has data or not.
Lets try with some invalid data. In this case, subject is blank (an error, because all elds are required by default) and sender is not a valid e-mail address:
>>> data = {subject: , ... message: Hi there, ... sender: invalid e-mail address, ... cc_myself: True} >>> f = ContactForm(data) >>> f.is_valid() False
In this dictionary, the keys are the eld names, and the values are lists of Unicode strings representing the error messages. The error messages are stored in lists because a eld can have multiple error messages. You can access errors without having to call is_valid() rst. The forms data will be validated the rst time either you call is_valid() or access errors.
684
The validation routines will only get called once, regardless of how many times you access errors or call is_valid(). This means that if validation has side effects, those side effects will only be triggered once. Behavior of unbound forms Its meaningless to validate a form with no data, but, for the record, heres what happens with unbound forms:
>>> f = ContactForm() >>> f.is_valid() False >>> f.errors {}
These values are only displayed for unbound forms, and theyre not used as fallback values if a particular value isnt provided. Note that if a Field denes initial and you include initial when instantiating the Form, then the latter initial will have precedence. In this example, initial is provided both at the eld level and at the form instance level, and the latter gets precedence:
>>> class CommentForm(forms.Form): ... name = forms.CharField(initial=class) ... url = forms.URLField() ... comment = forms.CharField() >>> f = CommentForm(initial={name: instance}, auto_id=False) >>> print f <tr><th>Name:</th><td><input type="text" name="name" value="instance" /></td></tr> <tr><th>Url:</th><td><input type="text" name="url" /></td></tr> <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
685
Once youve created a Form instance with a set of data and validated it, you can access the clean data via its cleaned_data attribute:
>>> data = {subject: hello, ... message: Hi there, ... sender: [email protected], ... cc_myself: True} >>> f = ContactForm(data) >>> f.is_valid() True >>> f.cleaned_data {cc_myself: True, message: uHi there, sender: [email protected], subject: uhello}
Changed in version 1.0: The cleaned_data attribute was called clean_data in earlier releases. Note that any text-based eld such as CharField or EmailField always cleans the input into a Unicode string. Well cover the encoding implications later in this document. If your data does not validate, your Form instance will not have a cleaned_data attribute:
>>> data = {subject: , ... message: Hi there, ... sender: invalid e-mail address, ... cc_myself: True} >>> f = ContactForm(data) >>> f.is_valid() False >>> f.cleaned_data Traceback (most recent call last): ... AttributeError: ContactForm object has no attribute cleaned_data
cleaned_data will always only contain a key for elds dened in the Form, even if you pass extra data when you dene the Form. In this example, we pass a bunch of extra elds to the ContactForm constructor, but cleaned_data contains only the forms elds:
>>> data = {subject: hello, ... message: Hi there, ... sender: [email protected], ... cc_myself: True, ... extra_field_1: foo, ... extra_field_2: bar, ... extra_field_3: baz} >>> f = ContactForm(data) >>> f.is_valid() True >>> f.cleaned_data # Doesnt contain extra_field_1, etc. {cc_myself: True, message: uHi there, sender: [email protected], subject: uhello}
cleaned_data will include a key and value for all elds dened in the Form, even if the data didnt include a value for elds that are not required. In this example, the data dictionary doesnt include a value for the nick_name eld, but cleaned_data includes it, with an empty value:
>>> class OptionalPersonForm(Form): ... first_name = CharField() ... last_name = CharField() ... nick_name = CharField(required=False) >>> data = {first_name: uJohn, last_name: uLennon}
686
>>> f = OptionalPersonForm(data) >>> f.is_valid() True >>> f.cleaned_data {nick_name: u, first_name: uJohn, last_name: uLennon}
In this above example, the cleaned_data value for nick_name is set to an empty string, because nick_name is CharField, and CharFields treat empty values as an empty string. Each eld type knows what its blank value is e.g., for DateField, its None instead of the empty string. For full details on each elds behavior in this case, see the Empty value note for each eld in the Built-in Field classes section below. You can write code to perform validation for particular form elds (based on their name) or for the form as a whole (considering combinations of various elds). More information about this is in Form and eld validation.
>>> f = ContactForm() >>> print f <tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="sub <tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_mes <tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender <tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself"
If the form is bound to data, the HTML output will include that data appropriately. For example, if a eld is represented by an <input type="text">, the data will be in the value attribute. If a eld is represented by an <input type="checkbox">, then that HTML will include checked="checked" if appropriate:
>>> data = {subject: hello, ... message: Hi there, ... sender: [email protected], ... cc_myself: True} >>> f = ContactForm(data) >>> print f <tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="sub <tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_mes <tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender <tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself"
This default output is a two-column HTML table, with a <tr> for each eld. Notice the following: For exibility, the output does not include the <table> and </table> tags, nor does it include the <form> and </form> tags or an <input type="submit"> tag. Its your job to do that. Each eld type has a default HTML representation. CharField and EmailField are represented by an <input type="text">. BooleanField is represented by an <input type="checkbox">. Note these are merely sensible defaults; you can specify which HTML to use for a given eld by using widgets, which well explain shortly. The HTML name for each tag is taken directly from its attribute name in the ContactForm class. The text label for each eld e.g. Subject:, Message: and Cc myself: is generated from the eld name by converting all underscores to spaces and upper-casing the rst letter. Again, note these are merely sensible defaults; you can also specify labels manually.
687
Each text label is surrounded in an HTML <label> tag, which points to the appropriate form eld via its id. Its id, in turn, is generated by prepending id_ to the eld name. The id attributes and <label> tags are included in the output by default, to follow best practices, but you can change that behavior. Although <table> output is the default output style when you print a form, other output styles are available. Each style is available as a method on a form object, and each rendering method returns a Unicode object. as_p() as_p() as_p() renders the form as a series of <p> tags, with each <p> containing one eld:
>>> f = ContactForm() >>> f.as_p() u<p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" >>> print f.as_p() <p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" ma <p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /> <p><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></p> <p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_c
as_ul() as_ul() as_ul() renders the form as a series of <li> tags, with each <li> containing one eld. It does not include the <ul> or </ul>, so that you can specify any HTML attributes on the <ul> for exibility:
>>> f = ContactForm() >>> f.as_ul() u<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" >>> print f.as_ul() <li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" m <li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" / <li><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></l <li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_
as_table() as_table() Finally, as_table() outputs the form as an HTML <table>. This is exactly the same as print. In fact, when you print a form object, it calls its as_table() method behind the scenes:
>>> f = ContactForm() >>> f.as_table() u<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" na >>> print f.as_table() <tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name <tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="i <tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_s <tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_mys
688
Styling required or erroneous form rows New in version 1.2: Please, see the release notes Its pretty common to style form rows and elds that are required or have errors. For example, you might want to present required form rows in bold and highlight errors in red. The Form class has a couple of hooks you can use to add class attributes to required rows or to rows with errors: simple set the Form.error_css_class and/or Form.required_css_class attributes:
class ContactForm(Form): error_css_class = error required_css_class = required # ... and the rest of your fields here
Once youve done that, rows will be given "error" and/or "required" classes, as needed. The HTML will look something like:
>>> f = ContactForm(data) >>> print f.as_table() <tr class="required"><th><label for="id_subject">Subject:</label> ... <tr class="required"><th><label for="id_message">Message:</label> ... <tr class="required error"><th><label for="id_sender">Sender:</label> <tr><th><label for="id_cc_myself">Cc myself:<label> ...
...
Conguring HTML <label> tags An HTML <label> tag designates which label text is associated with which form element. This small enhancement makes forms more usable and more accessible to assistive devices. Its always a good idea to use <label> tags. By default, the form rendering methods include HTML id attributes on the form elements and corresponding <label> tags around the labels. The id attribute values are generated by prepending id_ to the form eld names. This behavior is congurable, though, if you want to change the id convention or remove HTML id attributes and <label> tags entirely. Use the auto_id argument to the Form constructor to control the label and id behavior. This argument must be True, False or a string. If auto_id is False, then the form output will not include <label> tags nor id attributes:
>>> f = ContactForm(auto_id=False) >>> print f.as_table() <tr><th>Subject:</th><td><input type="text" name="subject" maxlength="100" /></td></tr> <tr><th>Message:</th><td><input type="text" name="message" /></td></tr> <tr><th>Sender:</th><td><input type="text" name="sender" /></td></tr> <tr><th>Cc myself:</th><td><input type="checkbox" name="cc_myself" /></td></tr> >>> print f.as_ul() <li>Subject: <input type="text" name="subject" maxlength="100" /></li> <li>Message: <input type="text" name="message" /></li> <li>Sender: <input type="text" name="sender" /></li> <li>Cc myself: <input type="checkbox" name="cc_myself" /></li> >>> print f.as_p() <p>Subject: <input type="text" name="subject" maxlength="100" /></p> <p>Message: <input type="text" name="message" /></p> <p>Sender: <input type="text" name="sender" /></p> <p>Cc myself: <input type="checkbox" name="cc_myself" /></p>
689
If auto_id is set to True, then the form output will include <label> tags and will simply use the eld name as its id for each form eld:
>>> f = ContactForm(auto_id=True) >>> print f.as_table() <tr><th><label for="subject">Subject:</label></th><td><input id="subject" type="text" name="subject" <tr><th><label for="message">Message:</label></th><td><input type="text" name="message" id="message" <tr><th><label for="sender">Sender:</label></th><td><input type="text" name="sender" id="sender" /></ <tr><th><label for="cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id= >>> print f.as_ul() <li><label for="subject">Subject:</label> <input id="subject" type="text" name="subject" maxlength="1 <li><label for="message">Message:</label> <input type="text" name="message" id="message" /></li> <li><label for="sender">Sender:</label> <input type="text" name="sender" id="sender" /></li> <li><label for="cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="cc_myself" >>> print f.as_p() <p><label for="subject">Subject:</label> <input id="subject" type="text" name="subject" maxlength="10 <p><label for="message">Message:</label> <input type="text" name="message" id="message" /></p> <p><label for="sender">Sender:</label> <input type="text" name="sender" id="sender" /></p> <p><label for="cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="cc_myself" /
If auto_id is set to a string containing the format character %s, then the form output will include <label> tags, and will generate id attributes based on the format string. For example, for a format string field_%s, a eld named subject will get the id value field_subject. Continuing our example:
>>> f = ContactForm(auto_id=id_for_%s) >>> print f.as_table() <tr><th><label for="id_for_subject">Subject:</label></th><td><input id="id_for_subject" type="text" n <tr><th><label for="id_for_message">Message:</label></th><td><input type="text" name="message" id="id <tr><th><label for="id_for_sender">Sender:</label></th><td><input type="text" name="sender" id="id_fo <tr><th><label for="id_for_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myse >>> print f.as_ul() <li><label for="id_for_subject">Subject:</label> <input id="id_for_subject" type="text" name="subject <li><label for="id_for_message">Message:</label> <input type="text" name="message" id="id_for_message <li><label for="id_for_sender">Sender:</label> <input type="text" name="sender" id="id_for_sender" /> <li><label for="id_for_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_f >>> print f.as_p() <p><label for="id_for_subject">Subject:</label> <input id="id_for_subject" type="text" name="subject" <p><label for="id_for_message">Message:</label> <input type="text" name="message" id="id_for_message" <p><label for="id_for_sender">Sender:</label> <input type="text" name="sender" id="id_for_sender" />< <p><label for="id_for_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_fo
If auto_id is set to any other true value such as a string that doesnt include %s then the library will act as if auto_id is True. By default, auto_id is set to the string id_%s. Normally, a colon (:) will be appended after any label name when a form is rendered. Its possible to change the colon to another character, or omit it entirely, using the label_suffix parameter:
>>> f = ContactForm(auto_id=id_for_%s, label_suffix=) >>> print f.as_ul() <li><label for="id_for_subject">Subject</label> <input id="id_for_subject" type="text" name="subject" <li><label for="id_for_message">Message</label> <input type="text" name="message" id="id_for_message" <li><label for="id_for_sender">Sender</label> <input type="text" name="sender" id="id_for_sender" />< <li><label for="id_for_cc_myself">Cc myself</label> <input type="checkbox" name="cc_myself" id="id_fo >>> f = ContactForm(auto_id=id_for_%s, label_suffix= ->) >>> print f.as_ul() <li><label for="id_for_subject">Subject -></label> <input id="id_for_subject" type="text" name="subje
690
<li><label for="id_for_message">Message -></label> <input type="text" name="message" id="id_for_messa <li><label for="id_for_sender">Sender -></label> <input type="text" name="sender" id="id_for_sender" <li><label for="id_for_cc_myself">Cc myself -></label> <input type="checkbox" name="cc_myself" id="id
Note that the label sufx is added only if the last character of the label isnt a punctuation character (., !, ? or :) Notes on eld ordering In the as_p(), as_ul() and as_table() shortcuts, the elds are displayed in the order in which you dene them in your form class. For example, in the ContactForm example, the elds are dened in the order subject, message, sender, cc_myself. To reorder the HTML output, just change the order in which those elds are listed in the class. How errors are displayed If you render a bound Form object, the act of rendering will automatically run the forms validation if it hasnt already happened, and the HTML output will include the validation errors as a <ul class="errorlist"> near the eld. The particular positioning of the error messages depends on the output method youre using:
>>> data = {subject: , ... message: Hi there, ... sender: invalid e-mail address, ... cc_myself: True} >>> f = ContactForm(data, auto_id=False) >>> print f.as_table() <tr><th>Subject:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text <tr><th>Message:</th><td><input type="text" name="message" value="Hi there" /></td></tr> <tr><th>Sender:</th><td><ul class="errorlist"><li>Enter a valid e-mail address.</li></ul><input type= <tr><th>Cc myself:</th><td><input checked="checked" type="checkbox" name="cc_myself" /></td></tr> >>> print f.as_ul() <li><ul class="errorlist"><li>This field is required.</li></ul>Subject: <input type="text" name="subj <li>Message: <input type="text" name="message" value="Hi there" /></li> <li><ul class="errorlist"><li>Enter a valid e-mail address.</li></ul>Sender: <input type="text" name= <li>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></li> >>> print f.as_p() <p><ul class="errorlist"><li>This field is required.</li></ul></p> <p>Subject: <input type="text" name="subject" maxlength="100" /></p> <p>Message: <input type="text" name="message" value="Hi there" /></p> <p><ul class="errorlist"><li>Enter a valid e-mail address.</li></ul></p> <p>Sender: <input type="text" name="sender" value="invalid e-mail address" /></p> <p>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></p>
Customizing the error list format By default, forms use django.forms.util.ErrorList to format validation errors. If youd like to use an alternate class for displaying errors, you can pass that in at construction time:
>>> from django.forms.util import ErrorList >>> class DivErrorList(ErrorList): ... def __unicode__(self): ... return self.as_divs() ... def as_divs(self): ... if not self: return u
691
... return u<div class="errorlist">%s</div> % .join([u<div class="error">%s</div> % e f >>> f = ContactForm(data, auto_id=False, error_class=DivErrorList) >>> f.as_p() <div class="errorlist"><div class="error">This field is required.</div></div> <p>Subject: <input type="text" name="subject" maxlength="100" /></p> <p>Message: <input type="text" name="message" value="Hi there" /></p> <div class="errorlist"><div class="error">Enter a valid e-mail address.</div></div> <p>Sender: <input type="text" name="sender" value="invalid e-mail address" /></p> <p>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></p>
More granular output The as_p(), as_ul() and as_table() methods are simply shortcuts for lazy developers theyre not the only way a form object can be displayed. To display the HTML for a single eld in your form, use dictionary lookup syntax using the elds name as the key, and print the resulting object:
>>> f = ContactForm() >>> print f[subject] <input id="id_subject" type="text" name="subject" maxlength="100" /> >>> print f[message] <input type="text" name="message" id="id_message" /> >>> print f[sender] <input type="text" name="sender" id="id_sender" /> >>> print f[cc_myself] <input type="checkbox" name="cc_myself" id="id_cc_myself" />
Call str() or unicode() on the eld to get its rendered HTML as a string or Unicode object, respectively:
>>> str(f[subject]) <input id="id_subject" type="text" name="subject" maxlength="100" /> >>> unicode(f[subject]) u<input id="id_subject" type="text" name="subject" maxlength="100" />
Form objects dene a custom __iter__() method, which allows you to loop through their elds:
>>> f = ContactForm() >>> for field in f: print field <input id="id_subject" type="text" name="subject" maxlength="100" /> <input type="text" name="message" id="id_message" /> <input type="text" name="sender" id="id_sender" /> <input type="checkbox" name="cc_myself" id="id_cc_myself" />
For a elds list of errors, access the elds errors attribute. This is a list-like object that is displayed as an HTML <ul class="errorlist"> when printed:
692
>>> data = {subject: hi, message: , sender: , cc_myself: } >>> f = ContactForm(data, auto_id=False) >>> print f[message] <input type="text" name="message" /> >>> f[message].errors [uThis field is required.] >>> print f[message].errors <ul class="errorlist"><li>This field is required.</li></ul> >>> f[subject].errors [] >>> print f[subject].errors >>> str(f[subject].errors)
New in version 1.2: Please, see the release notes When you use Djangos rendering shortcuts, CSS classes are used to indicate required form elds or elds that contain errors. If youre manually rendering a form, you can access these CSS classes using the css_classes method:
>>> f = ContactForm(data) >>> f[message].css_classes() required
If you want to provide some additional classes in addition to the error and required classes that may be required, you can provide those classes as an argument:
>>> f = ContactForm(data) >>> f[message].css_classes(foo bar) foo bar required
Secondly, when you use the form, you need to bind the le data. File data is handled separately to normal form data, so when your form contains a FileField and ImageField, you will need to specify a second argument when you bind your form. So if we extend our ContactForm to include an ImageField called mugshot, we need to bind the le data containing the mugshot image:
# Bound form with an image field >>> from django.core.files.uploadedfile import SimpleUploadedFile >>> data = {subject: hello, ... message: Hi there, ... sender: [email protected], ... cc_myself: True} >>> file_data = {mugshot: SimpleUploadedFile(face.jpg, <file data>)} >>> f = ContactFormWithMugshot(data, file_data)
693
In practice, you will usually specify request.FILES as the source of le data (just like you use request.POST as the source of form data):
# Bound form with an image field, data from the request >>> f = ContactFormWithMugshot(request.POST, request.FILES)
Constructing an unbound form is the same as always just omit both form data and le data:
# Unbound form with a image field >>> f = ContactFormWithMugshot()
Testing for multipart forms If youre writing reusable views or templates, you may not know ahead of time whether your form is a multipart form or not. The is_multipart() method tells you whether the form requires multipart encoding for submission:
>>> f = ContactFormWithMugshot() >>> f.is_multipart() True
Its possible to subclass multiple forms, treating forms as mix-ins. In this example, BeatleForm subclasses both PersonForm and InstrumentForm (in that order), and its eld list includes the elds from the parent classes:
694
>>> class PersonForm(Form): ... first_name = CharField() ... last_name = CharField() >>> class InstrumentForm(Form): ... instrument = CharField() >>> class BeatleForm(PersonForm, InstrumentForm): ... haircut_type = CharField() >>> b = BeatleForm(auto_id=False) >>> print b.as_ul() <li>First name: <input type="text" name="first_name" /></li> <li>Last name: <input type="text" name="last_name" /></li> <li>Instrument: <input type="text" name="instrument" /></li> <li>Haircut type: <input type="text" name="haircut_type" /></li>
>>> mother = PersonForm(prefix="mother") >>> father = PersonForm(prefix="father") >>> print mother.as_ul() <li><label for="id_mother-first_name">First name:</label> <input type="text" name="mother-first_name" <li><label for="id_mother-last_name">Last name:</label> <input type="text" name="mother-last_name" id >>> print father.as_ul() <li><label for="id_father-first_name">First name:</label> <input type="text" name="father-first_name" <li><label for="id_father-last_name">Last name:</label> <input type="text" name="father-last_name" id
695
To specify that a eld is not required, pass required=False to the Field constructor:
>>> f = forms.CharField(required=False) >>> f.clean(foo) ufoo >>> f.clean() u >>> f.clean(None) u >>> f.clean(0) u0 >>> f.clean(True) uTrue >>> f.clean(False) uFalse
If a Field has required=False and you pass clean() an empty value, then clean() will return a normalized empty value rather than raising ValidationError. For CharField, this will be a Unicode empty string. For other Field classes, it might be None. (This varies from eld to eld.) label label
696
The label argument lets you specify the human-friendly label for this eld. This is used when the Field is displayed in a Form. As explained in Outputting forms as HTML above, the default label for a Field is generated from the eld name by converting all underscores to spaces and upper-casing the rst letter. Specify label if that default behavior doesnt result in an adequate label. Heres a full example Form that implements label for two of its elds. Weve specied auto_id=False to simplify the output:
>>> class CommentForm(forms.Form): ... name = forms.CharField(label=Your name) ... url = forms.URLField(label=Your Web site, required=False) ... comment = forms.CharField() >>> f = CommentForm(auto_id=False) >>> print f <tr><th>Your name:</th><td><input type="text" name="name" /></td></tr> <tr><th>Your Web site:</th><td><input type="text" name="url" /></td></tr> <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
initial initial The initial argument lets you specify the initial value to use when rendering this Field in an unbound Form. To specify dynamic initial data, see the Form.initial parameter. The use-case for this is when you want to display an empty form in which a eld is initialized to a particular value. For example:
>>> class CommentForm(forms.Form): ... name = forms.CharField(initial=Your name) ... url = forms.URLField(initial=http://) ... comment = forms.CharField() >>> f = CommentForm(auto_id=False) >>> print f <tr><th>Name:</th><td><input type="text" name="name" value="Your name" /></td></tr> <tr><th>Url:</th><td><input type="text" name="url" value="http://" /></td></tr> <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
You may be thinking, why not just pass a dictionary of the initial values as data when displaying the form? Well, if you do that, youll trigger validation, and the HTML output will include any validation errors:
>>> class CommentForm(forms.Form): ... name = forms.CharField() ... url = forms.URLField() ... comment = forms.CharField() >>> default_data = {name: Your name, url: http://} >>> f = CommentForm(default_data, auto_id=False) >>> print f <tr><th>Name:</th><td><input type="text" name="name" value="Your name" /></td></tr> <tr><th>Url:</th><td><ul class="errorlist"><li>Enter a valid URL.</li></ul><input type="text" name="u <tr><th>Comment:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text
This is why initial values are only displayed for unbound forms. For bound forms, the HTML output will use the bound data.
697
Also note that initial values are not used as fallback data in validation if a particular elds value is not given. initial values are only intended for initial form display:
>>> class CommentForm(forms.Form): ... name = forms.CharField(initial=Your name) ... url = forms.URLField(initial=http://) ... comment = forms.CharField() >>> data = {name: , url: , comment: Foo} >>> f = CommentForm(data) >>> f.is_valid() False # The form does *not* fall back to using the initial values. >>> f.errors {url: [uThis field is required.], name: [uThis field is required.]}
The callable will be evaluated only when the unbound form is displayed, not when it is dened. widget widget The widget argument lets you specify a Widget class to use when rendering this Field. See Widgets for more information. help_text help_text The help_text argument lets you specify descriptive text for this Field. If you provide help_text, it will be displayed next to the Field when the Field is rendered by one of the convenience Form methods (e.g., as_ul()). Heres a full example Form that implements help_text for two of its elds. Weve specied auto_id=False to simplify the output:
>>> class HelpTextContactForm(forms.Form): ... subject = forms.CharField(max_length=100, help_text=100 characters max.) ... message = forms.CharField() ... sender = forms.EmailField(help_text=A valid e-mail address, please.) ... cc_myself = forms.BooleanField(required=False) >>> f = HelpTextContactForm(auto_id=False) >>> print f.as_table() <tr><th>Subject:</th><td><input type="text" name="subject" maxlength="100" /><br />100 characters max <tr><th>Message:</th><td><input type="text" name="message" /></td></tr> <tr><th>Sender:</th><td><input type="text" name="sender" /><br />A valid e-mail address, please.</td> <tr><th>Cc myself:</th><td><input type="checkbox" name="cc_myself" /></td></tr> >>> print f.as_ul() <li>Subject: <input type="text" name="subject" maxlength="100" /> 100 characters max.</li> <li>Message: <input type="text" name="message" /></li>
698
<li>Sender: <input type="text" name="sender" /> A valid e-mail address, please.</li> <li>Cc myself: <input type="checkbox" name="cc_myself" /></li> >>> print f.as_p() <p>Subject: <input type="text" name="subject" maxlength="100" /> 100 characters max.</p> <p>Message: <input type="text" name="message" /></p> <p>Sender: <input type="text" name="sender" /> A valid e-mail address, please.</p> <p>Cc myself: <input type="checkbox" name="cc_myself" /></p>
error_messages New in version 1.0: Please, see the release notes error_messages The error_messages argument lets you override the default messages that the eld will raise. Pass in a dictionary with keys matching the error messages you want to override. For example, here is the default error message:
>>> generic = forms.CharField() >>> generic.clean() Traceback (most recent call last): ... ValidationError: [uThis field is required.]
In the built-in Field classes section below, each Field denes the error message keys it uses. validators New in version 1.2: Please, see the release notes validators The validators argument lets you provide a list of validation functions for this eld. See the validators documentation for more information. localize New in version 1.2: Please, see the release notes localize The localize argument enables the localization of form data, input as well as the rendered output. See the format localization documentation for more information.
699
700
Error message keys: required, invalid_choice Takes one extra required argument: choices An iterable (e.g., a list or tuple) of 2-tuples to use as choices for this eld. TypedChoiceField class TypedChoiceField(**kwargs) Just like a ChoiceField, except TypedChoiceField takes an extra coerce argument. Default widget: Select Empty value: Whatever youve given as empty_value Normalizes to: the value returned by the coerce argument. Validates that the given value exists in the list of choices. Error message keys: required, invalid_choice Takes extra arguments: coerce A function that takes one argument and returns a coerced value. Examples include the built-in int, float, bool and other types. Defaults to an identity function. empty_value The value to use to represent empty. Defaults to the empty string; None is another common choice here. DateField class DateField(**kwargs) Default widget: DateInput Empty value: None Normalizes to: A Python datetime.date object. Validates that the given value is either a datetime.date, datetime.datetime or string formatted in a particular date format. Error message keys: required, invalid Takes one optional argument: input_formats A list of formats used to attempt to convert a string to a valid datetime.date object. If no input_formats argument is provided, the default input formats are:
%Y-%m-%d, %b %d %Y, %d %b %Y, %B %d %Y, %d %B %Y, %m/%d/%Y, %m/%d/%y, %b %d, %Y, %d %b, %Y, %B %d, %Y, %d %B, %Y, # # # # # 2006-10-25, 10/25/2006, 10/25/06 Oct 25 2006, Oct 25, 2006 25 Oct 2006, 25 Oct, 2006 October 25 2006, October 25, 2006 25 October 2006, 25 October, 2006
Changed in version 1.1: The DateField previously used a TextInput widget by default. It now uses a DateInput widget.
701
DateTimeField class DateTimeField(**kwargs) Default widget: DateTimeInput Empty value: None Normalizes to: A Python datetime.datetime object. Validates that the given value is either a datetime.datetime, datetime.date or string formatted in a particular datetime format. Error message keys: required, invalid Takes one optional argument: input_formats A list of formats used to attempt to convert a string to a valid datetime.datetime object. If no input_formats argument is provided, the default input formats are:
%Y-%m-%d %H:%M:%S, %Y-%m-%d %H:%M, %Y-%m-%d, %m/%d/%Y %H:%M:%S, %m/%d/%Y %H:%M, %m/%d/%Y, %m/%d/%y %H:%M:%S, %m/%d/%y %H:%M, %m/%d/%y, # # # # # # # # # 2006-10-25 14:30:59 2006-10-25 14:30 2006-10-25 10/25/2006 14:30:59 10/25/2006 14:30 10/25/2006 10/25/06 14:30:59 10/25/06 14:30 10/25/06
Changed in version 1.0: The DateTimeField used to use a TextInput widget by default. This has now changed. DecimalField New in version 1.0: Please, see the release notes class DecimalField(**kwargs) Default widget: TextInput Empty value: None Normalizes to: A Python decimal. Validates that the given value is a decimal. Leading and trailing whitespace is ignored. Error message keys: required, invalid, max_decimal_places, max_whole_digits Takes four optional arguments: max_value min_value These attributes dene the limits for the elds value. max_digits The maximum number of digits (those before the decimal point plus those after the decimal point, with leading zeros stripped) permitted in the value. max_value, min_value, max_digits,
702
decimal_places The maximum number of decimal places permitted. EmailField class EmailField(**kwargs) Default widget: TextInput Empty value: (an empty string) Normalizes to: A Unicode object. Validates that the given value is a valid e-mail address, using a moderately complex regular expression. Error message keys: required, invalid Has two optional arguments for validation, max_length and min_length. If provided, these arguments ensure that the string is at most or at least the given length. Changed in version 1.2: The EmailField previously did not recognize e-mail addresses as valid that contained an IDN (Internationalized Domain Name; a domain containing unicode characters) domain part. This has now been corrected. FileField New in version 1.0: Please, see the release notes class FileField(**kwargs) Default widget: FileInput Empty value: None Normalizes to: An UploadedFile object that wraps the le content and le name into a single object. Validates that non-empty le data has been bound to the form. Error message keys: required, invalid, missing, empty To learn more about the UploadedFile object, see the le uploads documentation. When you use a FileField in a form, you must also remember to bind the le data to the form. FilePathField New in version 1.0: Please, see the release notes class FilePathField(**kwargs) Default widget: Select Empty value: None Normalizes to: A unicode object Validates that the selected choice exists in the list of choices. Error message keys: required, invalid_choice The eld allows choosing from les inside a certain directory. It takes three extra arguments; only path is required: path The absolute path to the directory whose contents you want listed. This directory must exist.
703
recursive If False (the default) only the direct contents of path will be offered as choices. If True, the directory will be descended into recursively and all descendants will be listed as choices. match A regular expression pattern; only les with names matching this expression will be allowed as choices. FloatField Default widget: TextInput Empty value: None Normalizes to: A Python oat. Validates that the given value is an oat. Leading and trailing whitespace is allowed, as in Pythons float() function. Error message keys: required, invalid, max_value, min_value Takes two optional arguments for validation, max_value and min_value. These control the range of values permitted in the eld. ImageField New in version 1.0: Please, see the release notes class ImageField(**kwargs) Default widget: FileInput Empty value: None Normalizes to: An UploadedFile object that wraps the le content and le name into a single object. Validates that le data has been bound to the form, and that the le is of an image format understood by PIL. Error message keys: required, invalid, missing, empty, invalid_image Using an ImageField requires that the Python Imaging Library is installed. When you use an ImageField on a form, you must also remember to bind the le data to the form. IntegerField class IntegerField(**kwargs) Default widget: TextInput Empty value: None Normalizes to: A Python integer or long integer. Validates that the given value is an integer. Leading and trailing whitespace is allowed, as in Pythons int() function. Error message keys: required, invalid, max_value, min_value Takes two optional arguments for validation: max_value
704
min_value These control the range of values permitted in the eld. IPAddressField class IPAddressField(**kwargs) Default widget: TextInput Empty value: (an empty string) Normalizes to: A Unicode object. Validates that the given value is a valid IPv4 address, using a regular expression. Error message keys: required, invalid MultipleChoiceField class MultipleChoiceField(**kwargs) Default widget: SelectMultiple Empty value: [] (an empty list) Normalizes to: A list of Unicode objects. Validates that every value in the given list of values exists in the list of choices. Error message keys: required, invalid_choice, invalid_list Takes one extra argument, choices, as for ChoiceField. NullBooleanField class NullBooleanField(**kwargs) Default widget: NullBooleanSelect Empty value: None Normalizes to: A Python True, False or None value. Validates nothing (i.e., it never raises a ValidationError). RegexField class RegexField(**kwargs) Default widget: TextInput Empty value: (an empty string) Normalizes to: A Unicode object. Validates that the given value matches against a certain regular expression. Error message keys: required, invalid Takes one required argument:
705
regex A regular expression specied either as a string or a compiled regular expression object. Also takes max_length and min_length, which work just as they do for CharField. The optional argument error_message is also accepted for backwards compatibility. The preferred way to provide an error message is to use the error_messages argument, passing a dictionary with invalid as a key and the error message as the value. SlugField class SlugField(**kwargs) Default widget: TextInput Empty value: (an empty string) Normalizes to: A Unicode object. Validates that the given value contains only letters, numbers and hyphens. Error messages: required, invalid This eld is intended for use in representing a model SlugField in forms. TimeField class TimeField(**kwargs) Default widget: TextInput Empty value: None Normalizes to: A Python datetime.time object. Validates that the given value is either a datetime.time or string formatted in a particular time format. Error message keys: required, invalid Takes one optional argument: input_formats A list of formats used to attempt to convert a string to a valid datetime.time object. If no input_formats argument is provided, the default input formats are:
%H:%M:%S, %H:%M, # 14:30:59 # 14:30
URLField class URLField(**kwargs) Default widget: TextInput Empty value: (an empty string) Normalizes to: A Unicode object. Validates that the given value is a valid URL. Error message keys: required, invalid, invalid_link
706
Takes the following optional arguments: max_length min_length Same as CharField.max_length and CharField.min_length. verify_exists If True, the validator will attempt to load the given URL, raising ValidationError if the page gives a 404. Defaults to False. validator_user_agent String used as the user-agent used when checking for a URLs existence. Defaults to the value of the URL_VALIDATOR_USER_AGENT setting. Changed in version 1.2: The URLField previously did not recognize URLs as valid that contained an IDN (Internationalized Domain Name; a domain name containing unicode characters) domain name. This has now been corrected.
MultiValuefield class MultiValueField(**kwargs) Default widget: TextInput Empty value: (an empty string) Normalizes to: the type returned by the compress method of the subclass. Validates that the given value against each of the elds specied as an argument to the MultiValueField. Error message keys: required, invalid 54.2. Form elds 707
This abstract eld (must be subclassed) aggregates the logic of multiple elds. Subclasses should not have to implement clean(). Instead, they must implement compress(), which takes a list of valid values and returns a compressed version of those values a single value. For example, SplitDateTimeField is a subclass which combines a time eld and a date eld into a datetime object. Takes one extra required argument: fields A list of elds which are cleaned into a single eld. Each value in clean is cleaned by the corresponding eld in fields the rst value is cleaned by the rst eld, the second value is cleaned by the second eld, etc. Once all elds are cleaned, the list of clean values is compressed into a single value. SplitDateTimeField class SplitDateTimeField(**kwargs) Default widget: SplitDateTimeWidget Empty value: None Normalizes to: A Python datetime.datetime object. Validates that the given value is a datetime.datetime or string formatted in a particular datetime format. Error message keys: required, invalid Takes two optional arguments: input_date_formats A list of formats used to attempt to convert a string to a valid datetime.date object. If no input_date_formats argument is provided, the default input formats for DateField are used. input_time_formats A list of formats used to attempt to convert a string to a valid datetime.time object. If no input_time_formats argument is provided, the default input formats for TimeField are used. Changed in version 1.1: The SplitDateTimeField previously used two TextInput widgets by default. The input_date_formats and input_time_formats arguments are also new.
708
ModelChoiceField also takes one optional argument: empty_label By default the <select> widget used by ModelChoiceField will have a an empty choice at the top of the list. You can change the text of this label (which is "---------" by default) with the empty_label attribute, or you can disable the empty label entirely by setting empty_label to None:
# A custom empty label field1 = forms.ModelChoiceField(queryset=..., empty_label="(Nothing)") # No empty label field2 = forms.ModelChoiceField(queryset=..., empty_label=None)
Note that if a ModelChoiceField is required and has a default initial value, no empty choice is created (regardless of the value of empty_label). The __unicode__ method of the model will be called to generate string representations of the objects for use in the elds choices; to provide customized representations, subclass ModelChoiceField and override label_from_instance. This method will receive a model object, and should return a string suitable for representing it. For example:
class MyModelChoiceField(ModelChoiceField): def label_from_instance(self, obj): return "My Object #%i" % obj.id
ModelMultipleChoiceField class ModelMultipleChoiceField(**kwargs) Allows the selection of one or more model objects, suitable for representing a many-to-many relation. As with ModelChoiceField, you can use label_from_instance to customize the object representations, and queryset is a required parameter: queryset A QuerySet of model objects from which the choices for the eld will be derived, and which will be used to validate the users selection.
54.3 Widgets
A widget is Djangos representation of a HTML input element. The widget handles the rendering of the HTML, and the extraction of data from a GET/POST dictionary that corresponds to the widget. Django provides a representation of all the basic HTML widgets, plus some commonly used groups of widgets: class TextInput() Text input: <input type=text ...>
54.3. Widgets
709
class PasswordInput() Password input: <input type=password ...> Takes one optional argument: render_value Determines whether the widget will have a value lled in when the form is re-displayed after a validation error (default is True). class HiddenInput() Hidden input: <input type=hidden ...> class MultipleHiddenInput() Multiple <input type=hidden ...> widgets. class FileInput() File upload input: <input type=file ...> class DateInput() New in version 1.1: Please, see the release notes Date input as a simple text box: <input type=text ...> Takes one optional argument: format The format in which this elds initial value will be displayed. If no format argument is provided, the default format is %Y-%m-%d. class DateTimeInput() New in version 1.0: Please, see the release notes Date/time input as a simple text box: <input type=text ...> Takes one optional argument: format The format in which this elds initial value will be displayed. If no format argument is provided, the default format is %Y-%m-%d %H:%M:%S. class TimeInput() Time input as a simple text box: <input type=text ...> Takes one optional argument: format The format in which this elds initial value will be displayed. If no format argument is provided, the default format is %H:%M:%S. Changed in version 1.1: The format argument was not supported in Django 1.0. class Textarea() Text area: <textarea>...</textarea> class CheckboxInput() Checkbox: <input type=checkbox ...> Takes one optional argument: check_test A callable that takes the value of the CheckBoxInput and returns True if the checkbox should be checked for that value. class Select() Select widget: <select><option ...>...</select>
710
Requires that your eld provides choices. class NullBooleanSelect() Select widget with options Unknown, Yes and No class SelectMultiple() Select widget allowing multiple selection: <select multiple=multiple>...</select> Requires that your eld provides choices. class RadioSelect() A list of radio buttons:
<ul> <li><input type=radio ...></li> ... </ul>
Requires that your eld provides choices. class CheckboxSelectMultiple() A list of checkboxes:
<ul> <li><input type=checkbox ...></li> ... </ul>
class MultiWidget() Wrapper around multiple other widgets class SplitDateTimeWidget() Wrapper around two widgets: DateInput for the date, and TimeInput for the time. Takes two optional arguments, date_format and time_format, which work just like the format argument for DateInput and TimeInput. Changed in version 1.1: The date_format and time_format arguments were not supported in Django 1.0. class SelectDateWidget() Wrapper around three select widgets: one each for month, day, and year. Note that this widget lives in a separate le from the standard widgets.
from django.forms.extras.widgets import SelectDateWidget date = forms.DateField(widget=SelectDateWidget())
54.3. Widgets
711
from django import forms class CommentForm(forms.Form): name = forms.CharField() url = forms.URLField() comment = forms.CharField(widget=forms.Textarea)
This would specify a form with a comment that uses a larger Textarea widget, rather than the default TextInput widget.
This form will include three default TextInput widgets, with default rendering - no CSS class, no extra attributes. This means that the input boxes provided for each widget will be rendered exactly the same:
>>> f = CommentForm(auto_id=False) >>> f.as_table() <tr><th>Name:</th><td><input type="text" name="name" /></td></tr> <tr><th>Url:</th><td><input type="text" name="url"/></td></tr> <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
On a real web page, you probably dont want every widget to look the same. You might want a larger input element for the comment, and you might want the name widget to have some special CSS class. To do this, you use the attrs argument when creating the widget: attrs For example:
class CommentForm(forms.Form): name = forms.CharField( widget=forms.TextInput(attrs={class:special})) url = forms.URLField() comment = forms.CharField( widget=forms.TextInput(attrs={size:40}))
Django will then include the extra attributes in the rendered output:
>>> f = CommentForm(auto_id=False) >>> f.as_table() <tr><th>Name:</th><td><input type="text" name="name" class="special"/></td></tr> <tr><th>Url:</th><td><input type="text" name="url"/></td></tr> <tr><th>Comment:</th><td><input type="text" name="comment" size="40"/></td></tr>
712
713
Note that any errors raised by your Form.clean() override will not be associated with any eld in particular. They go into a special eld (called __all__), which you can access via the non_field_errors() method if you need to. If you want to attach errors to a specic eld in the form, you will need to access the _errors attribute on the form, which is described later. Also note that there are special considerations when overriding the clean() method of a ModelForm subclass. (see the ModelForm documentation for more information) These methods are run in the order given above, one eld at a time. That is, for each eld in the form (in the order they are declared in the form denition), the Field.clean() method (or its override) is run, then clean_<fieldname>(). Finally, once those two methods are run for every eld, the Form.clean() method, or its override, is executed. Examples of each of these methods are provided below. As mentioned, any of these methods can raise a ValidationError. For any eld, if the Field.clean() method raises a ValidationError, any eld-specic cleaning method is not called. However, the cleaning methods for all remaining elds are still executed. The clean() method for the Form class or subclass is always run. If that method raises a ValidationError, cleaned_data will be an empty dictionary. The previous paragraph means that if you are overriding Form.clean(), you should iterate through self.cleaned_data.items(), possibly considering the _errors dictionary attribute on the form as well. In this way, you will already know which elds have passed their individual validation requirements.
714
As you can see, EmailField is just a CharField with customized error message and a validator that validates e-mail addresses. This can also be done on eld denition so:
email = forms.EmailField()
is equivalent to:
email = forms.CharField(validators=[validators.validate_email], error_messages={invalid: _(uEnter a valid e-mail address.)})
Form eld default cleaning Lets rstly create a custom form eld that validates its input is a string containing comma-separated e-mail addresses. The full class looks like this:
from django import forms from django.core.validators import validate_email class MultiEmailField(forms.Field): def to_python(self, value): "Normalize data to a list of strings." # Return an empty list if no input was given. if not value: return [] return value.split(,) def validate(self, value): "Check if value consists only of valid emails." # Use the parents handling of required fields, etc. super(MultiEmailField, self).validate(value) for email in value: validate_email(email)
715
Every form that uses this eld will have these methods run before anything else can be done with the elds data. This is cleaning that is specic to this type of eld, regardless of how it is subsequently used. Lets create a simple ContactForm to demonstrate how youd use this eld:
class ContactForm(forms.Form): subject = forms.CharField(max_length=100) message = forms.CharField() sender = forms.EmailField() recipients = MultiEmailField() cc_myself = forms.BooleanField(required=False)
Simply use MultiEmailField like any other form eld. When the is_valid() method is called on the form, the MultiEmailField.clean() method will be run as part of the cleaning process and it will, in turn, call the custom to_python() and validate() methods. Cleaning a specic eld attribute Continuing on from the previous example, suppose that in our ContactForm, we want to make sure that the recipients eld always contains the address "[email protected]". This is validation that is specic to our form, so we dont want to put it into the general MultiEmailField class. Instead, we write a cleaning method that operates on the recipients eld, like so:
class ContactForm(forms.Form): # Everything as before. ... def clean_recipients(self): data = self.cleaned_data[recipients] if "[email protected]" not in data: raise forms.ValidationError("You have forgotten about Fred!") # Always return the cleaned data, whether you have changed it or # not. return data
Cleaning and validating elds that depend on each other Suppose we add another requirement to our contact form: if the cc_myself eld is True, the subject must contain the word "help". We are performing validation on more than one eld at a time, so the forms clean() method is a good spot to do this. Notice that we are talking about the clean() method on the form here, whereas earlier we were writing a clean() method on a eld. Its important to keep the eld and form difference clear when working out where to validate things. Fields are single data points, forms are a collection of elds. By the time the forms clean() method is called, all the individual eld clean methods will have been run (the previous two sections), so self.cleaned_data will be populated with any data that has survived so far. So you also need to remember to allow for the fact that the elds you are wanting to validate might not have survived the initial individual eld checks. There are two way to report any errors from this step. Probably the most common method is to display the error at the top of the form. To create such an error, you can raise a ValidationError from the clean() method. For example:
716
class ContactForm(forms.Form): # Everything as before. ... def clean(self): cleaned_data = self.cleaned_data cc_myself = cleaned_data.get("cc_myself") subject = cleaned_data.get("subject") if cc_myself and subject: # Only do something if both fields are valid so far. if "help" not in subject: raise forms.ValidationError("Did not send for help in " "the subject despite CCing yourself.") # Always return the full collection of cleaned data. return cleaned_data
In this code, if the validation error is raised, the form will display an error message at the top of the form (normally) describing the problem. The second approach might involve assigning the error message to one of the elds. In this case, lets assign an error message to both the subject and cc_myself rows in the form display. Be careful when doing this in practice, since it can lead to confusing form output. Were showing what is possible here and leaving it up to you and your designers to work out what works effectively in your particular situation. Our new code (replacing the previous sample) looks like this:
class ContactForm(forms.Form): # Everything as before. ... def clean(self): cleaned_data = self.cleaned_data cc_myself = cleaned_data.get("cc_myself") subject = cleaned_data.get("subject") if cc_myself and subject and "help" not in subject: # We know these are not in self._errors now (see discussion # below). msg = u"Must put help in subject when ccing yourself." self._errors["cc_myself"] = self.error_class([msg]) self._errors["subject"] = self.error_class([msg]) # These fields are no longer valid. Remove them from the # cleaned data. del cleaned_data["cc_myself"] del cleaned_data["subject"] # Always return the full collection of cleaned data. return cleaned_data
As you can see, this approach requires a bit more effort, not withstanding the extra design effort to create a sensible form display. The details are worth noting, however. Firstly, earlier we mentioned that you might need to check if the eld name keys already exist in the _errors dictionary. In this case, since we know the elds exist in self.cleaned_data, they must have been valid when cleaned as individual elds, so there will be no corresponding entries in _errors.
717
Secondly, once we have decided that the combined data in the two elds we are considering arent valid, we must remember to remove them from the cleaned_data. In fact, Django will currently completely wipe out the cleaned_data dictionary if there are any errors in the form. However, this behaviour may change in the future, so its not a bad idea to clean up after yourself in the rst place.
718
CHAPTER
FIFTYFIVE
GENERIC VIEWS
Writing Web applications can be monotonous, because we repeat certain patterns again and again. In Django, the most common of these patterns have been abstracted into generic views that let you quickly provide common views of an object without actually needing to write any Python code. A general introduction to generic views can be found in the topic guide. This reference contains details of Djangos built-in generic views, along with a list of all keyword arguments that a generic view expects. Remember that arguments may either come from the URL pattern or from the extra_context additional-information dictionary. Most generic views require the queryset key, which is a QuerySet instance; see Making queries for more information about QuerySet objects.
55.1.1 django.views.generic.simple.direct_to_template
Description: Renders a given template, passing it a {{ params }} template variable, which is a dictionary of the parameters captured in the URL. Required arguments: template: The full name of a template to use. Optional arguments: extra_context: A dictionary of values to add to the template context. By default, this is an empty dictionary. If a value in the dictionary is callable, the generic view will call it just before rendering the template. mimetype: The MIME type to use for the resulting document. DEFAULT_CONTENT_TYPE setting. Example: Given the following URL patterns: Defaults to the value of the
719
urlpatterns = patterns(django.views.generic.simple, (r^foo/$, direct_to_template, {template: foo_index.html}), (r^foo/(?P<id>\d+)/$, direct_to_template, {template: foo_detail.html}), )
... a request to /foo/ would render the template foo_index.html, and a request to /foo/15/ would render the foo_detail.html with a context variable {{ params.id }} that is set to 15.
55.1.2 django.views.generic.simple.redirect_to
Description: Redirects to a given URL. The given URL may contain dictionary-style string formatting, which will be interpolated against the parameters captured in the URL. Because keyword interpolation is always done (even if no arguments are passed in), any "%" characters in the URL must be written as "%%" so that Python will convert them to a single percent sign on output. If the given URL is None, Django will return an HttpResponseGone (410). Required arguments: url: The URL to redirect to, as a string. Or None to raise a 410 (Gone) HTTP error. Optional arguments: permanent: Whether the redirect should be permanent. The only difference here is the HTTP status code returned. If True, then the redirect will use status code 301. If False, then the redirect will use status code 302. By default, permanent is True. New in version 1.1: The permanent keyword argument is new in Django 1.1. Example: This example issues a permanent redirect (HTTP status code 301) from /foo/<id>/ to /bar/<id>/:
urlpatterns = patterns(django.views.generic.simple, (^foo/(?P<id>\d+)/$, redirect_to, {url: /bar/%(id)s/}), )
This example issues a non-permanent redirect (HTTP status code 302) from /foo/<id>/ to /bar/<id>/:
urlpatterns = patterns(django.views.generic.simple, (^foo/(?P<id>\d+)/$, redirect_to, {url: /bar/%(id)s/, permanent: False}), )
This example shows how "%" characters must be written in the URL in order to avoid confusion with Pythons string formatting markers. If the redirect string is written as "%7Ejacob/" (with only a single %), an exception would be raised:
urlpatterns = patterns(django.views.generic.simple, (^bar/$, redirect_to, {url: %%7Ejacob.}), )
720
55.2.1 django.views.generic.date_based.archive_index
Description: A top-level index page showing the latest objects, by date. Objects with a date in the future are not included unless you set allow_future to True. Required arguments: queryset: A QuerySet of objects for which the archive serves. date_field: The name of the DateField or DateTimeField in the QuerySets model that the datebased archive should use to determine the objects on the page. Optional arguments: num_latest: The number of latest objects to send to the template context. By default, its 15. template_name: The full name of a template to use in rendering the page. This lets you override the default template name (see below). template_loader: The template loader to use when loading the template. By default, its django.template.loader. extra_context: A dictionary of values to add to the template context. By default, this is an empty dictionary. If a value in the dictionary is callable, the generic view will call it just before rendering the template. allow_empty: A boolean specifying whether to display the page if no objects are available. If this is False and no objects are available, the view will raise a 404 instead of displaying an empty page. By default, this is True. context_processors: A list of template-context processors to apply to the views template. mimetype: The MIME type to use for the resulting document. Defaults to the value of the DEFAULT_CONTENT_TYPE setting. allow_future: A boolean specifying whether to include future objects on this page, where future means objects in which the eld specied in date_field is greater than the current date/time. By default, this is False. New in version 1.0: Please, see the release notes template_object_name: Designates the name of the template variable to use in the template context. By default, this is latest. Template name: If template_name isnt specied, this view will use the template <app_label>/<model_name>_archive.html by default, where: <model_name> is your models name in all lowercase. staffmember. For a model StaffMember, thatd be
<app_label> is the right-most part of the full Python path to your models app. For example, if your model lives in apps/blog/models.py, thatd be blog.
721
Template context: In addition to extra_context, the templates context will be: date_list: A list of datetime.date objects representing all years that have objects available according to queryset. These are ordered in reverse. This is equivalent to queryset.dates(date_field, year)[::-1]. Changed in version 1.0: The behaviour depending on template_object_name is new in this version. latest: The num_latest objects in the system, ordered descending by date_field. For example, if num_latest is 10, then latest will be a list of the latest 10 objects in queryset. This variables name depends on the template_object_name parameter, which is latest by default. If template_object_name is foo, this variables name will be foo.
55.2.2 django.views.generic.date_based.archive_year
Description: A yearly archive page showing all available months in a given year. Objects with a date in the future are not displayed unless you set allow_future to True. Required arguments: year: The four-digit year for which the archive serves. queryset: A QuerySet of objects for which the archive serves. date_field: The name of the DateField or DateTimeField in the QuerySets model that the datebased archive should use to determine the objects on the page. Optional arguments: template_name: The full name of a template to use in rendering the page. This lets you override the default template name (see below). template_loader: The template loader to use when loading the template. django.template.loader. By default, its
extra_context: A dictionary of values to add to the template context. By default, this is an empty dictionary. If a value in the dictionary is callable, the generic view will call it just before rendering the template. allow_empty: A boolean specifying whether to display the page if no objects are available. If this is False and no objects are available, the view will raise a 404 instead of displaying an empty page. By default, this is False. context_processors: A list of template-context processors to apply to the views template. template_object_name: Designates the name of the template variable to use in the template context. By default, this is object. The view will append _list to the value of this parameter in determining the variables name. make_object_list: A boolean specifying whether to retrieve the full list of objects for this year and pass those to the template. If True, this list of objects will be made available to the template as object_list. (The name object_list may be different; see the docs for object_list in the Template context section below.) By default, this is False. mimetype: The MIME type to use for the resulting document. DEFAULT_CONTENT_TYPE setting. Defaults to the value of the
722
allow_future: A boolean specifying whether to include future objects on this page, where future means objects in which the eld specied in date_field is greater than the current date/time. By default, this is False. Template name: If template_name isnt specied, this view will use the template <app_label>/<model_name>_archive_year.html by default. Template context: In addition to extra_context, the templates context will be: date_list: A list of datetime.date objects representing all months that have objects available in the given year, according to queryset, in ascending order. year: The given year, as a four-character string. object_list: If the make_object_list parameter is True, this will be set to a list of objects available for the given year, ordered by the date eld. This variables name depends on the template_object_name parameter, which is object by default. If template_object_name is foo, this variables name will be foo_list. If make_object_list is False, object_list will be passed to the template as an empty list.
55.2.3 django.views.generic.date_based.archive_month
Description: A monthly archive page showing all objects in a given month. Objects with a date in the future are not displayed unless you set allow_future to True. Required arguments: year: The four-digit year for which the archive serves (a string). month: The month for which the archive serves, formatted according to the month_format argument. queryset: A QuerySet of objects for which the archive serves. date_field: The name of the DateField or DateTimeField in the QuerySets model that the datebased archive should use to determine the objects on the page. Optional arguments: month_format: A format string that regulates what format the month parameter uses. This should be in the syntax accepted by Pythons time.strftime. (See the strftime docs.) Its set to "%b" by default, which is a three-letter month abbreviation. To change it to use numbers, use "%m". template_name: The full name of a template to use in rendering the page. This lets you override the default template name (see below). template_loader: The template loader to use when loading the template. django.template.loader. By default, its
extra_context: A dictionary of values to add to the template context. By default, this is an empty dictionary. If a value in the dictionary is callable, the generic view will call it just before rendering the template. allow_empty: A boolean specifying whether to display the page if no objects are available. If this is False and no objects are available, the view will raise a 404 instead of displaying an empty page. By default, this is False. context_processors: A list of template-context processors to apply to the views template.
723
template_object_name: Designates the name of the template variable to use in the template context. By default, this is object. The view will append _list to the value of this parameter in determining the variables name. mimetype: The MIME type to use for the resulting document. DEFAULT_CONTENT_TYPE setting. Defaults to the value of the
allow_future: A boolean specifying whether to include future objects on this page, where future means objects in which the eld specied in date_field is greater than the current date/time. By default, this is False. Template name: If template_name isnt specied, this view will use the template <app_label>/<model_name>_archive_month.html by default. Template context: New in version 1.2: The inclusion of date_list in the templates context is new. In addition to extra_context, the templates context will be: date_list: A list of datetime.date objects representing all days that have objects available in the given month, according to queryset, in ascending order. month: A datetime.date object representing the given month. next_month: A datetime.date object representing the rst day of the next month. If the next month is in the future, this will be None. previous_month: A datetime.date object representing the rst day of the previous month. Unlike next_month, this will never be None. object_list: A list of objects available for the given month. This variables name depends on the template_object_name parameter, which is object by default. If template_object_name is foo, this variables name will be foo_list.
55.2.4 django.views.generic.date_based.archive_week
Description: A weekly archive page showing all objects in a given week. Objects with a date in the future are not displayed unless you set allow_future to True. Required arguments: year: The four-digit year for which the archive serves (a string). week: The week of the year for which the archive serves (a string). Weeks start with Sunday. queryset: A QuerySet of objects for which the archive serves. date_field: The name of the DateField or DateTimeField in the QuerySets model that the datebased archive should use to determine the objects on the page. Optional arguments: template_name: The full name of a template to use in rendering the page. This lets you override the default template name (see below). template_loader: The template loader to use when loading the template. django.template.loader. By default, its
extra_context: A dictionary of values to add to the template context. By default, this is an empty dictionary. If a value in the dictionary is callable, the generic view will call it just before rendering the template.
724
allow_empty: A boolean specifying whether to display the page if no objects are available. If this is False and no objects are available, the view will raise a 404 instead of displaying an empty page. By default, this is True. context_processors: A list of template-context processors to apply to the views template. template_object_name: Designates the name of the template variable to use in the template context. By default, this is object. The view will append _list to the value of this parameter in determining the variables name. mimetype: The MIME type to use for the resulting document. DEFAULT_CONTENT_TYPE setting. Defaults to the value of the
allow_future: A boolean specifying whether to include future objects on this page, where future means objects in which the eld specied in date_field is greater than the current date/time. By default, this is False. Template name: If template_name isnt specied, this view will use the template <app_label>/<model_name>_archive_week.html by default. Template context: In addition to extra_context, the templates context will be: week: A datetime.date object representing the rst day of the given week. object_list: A list of objects available for the given week. This variables name depends on the template_object_name parameter, which is object by default. If template_object_name is foo, this variables name will be foo_list.
55.2.5 django.views.generic.date_based.archive_day
Description: A day archive page showing all objects in a given day. Days in the future throw a 404 error, regardless of whether any objects exist for future days, unless you set allow_future to True. Required arguments: year: The four-digit year for which the archive serves (a string). month: The month for which the archive serves, formatted according to the month_format argument. day: The day for which the archive serves, formatted according to the day_format argument. queryset: A QuerySet of objects for which the archive serves. date_field: The name of the DateField or DateTimeField in the QuerySets model that the datebased archive should use to determine the objects on the page. Optional arguments: month_format: A format string that regulates what format the month parameter uses. This should be in the syntax accepted by Pythons time.strftime. (See the strftime docs.) Its set to "%b" by default, which is a three-letter month abbreviation. To change it to use numbers, use "%m". day_format: Like month_format, but for the day parameter. It defaults to "%d" (day of the month as a decimal number, 01-31). template_name: The full name of a template to use in rendering the page. This lets you override the default template name (see below).
725
template_loader: The template loader to use when loading the template. django.template.loader.
By default, its
extra_context: A dictionary of values to add to the template context. By default, this is an empty dictionary. If a value in the dictionary is callable, the generic view will call it just before rendering the template. allow_empty: A boolean specifying whether to display the page if no objects are available. If this is False and no objects are available, the view will raise a 404 instead of displaying an empty page. By default, this is False. context_processors: A list of template-context processors to apply to the views template. template_object_name: Designates the name of the template variable to use in the template context. By default, this is object. The view will append _list to the value of this parameter in determining the variables name. mimetype: The MIME type to use for the resulting document. DEFAULT_CONTENT_TYPE setting. Defaults to the value of the
allow_future: A boolean specifying whether to include future objects on this page, where future means objects in which the eld specied in date_field is greater than the current date/time. By default, this is False. Template name: If template_name isnt specied, this view will use the template <app_label>/<model_name>_archive_day.html by default. Template context: In addition to extra_context, the templates context will be: day: A datetime.date object representing the given day. next_day: A datetime.date object representing the next day. If the next day is in the future, this will be None. previous_day: A datetime.date object representing the previous day. Unlike next_day, this will never be None. object_list: A list of objects available for the given day. This variables name depends on the template_object_name parameter, which is object by default. If template_object_name is foo, this variables name will be foo_list.
55.2.6 django.views.generic.date_based.archive_today
Description: A day archive page showing all objects for today. This is exactly the same as archive_day, except the year/month/day arguments are not used, and todays date is used instead.
55.2.7 django.views.generic.date_based.object_detail
Description: A page representing an individual object. If the object has a date value in the future, the view will throw a 404 error by default, unless you set allow_future to True. Required arguments: year: The objects four-digit year (a string).
726
month: The objects month , formatted according to the month_format argument. day: The objects day , formatted according to the day_format argument. queryset: A QuerySet that contains the object. date_field: The name of the DateField or DateTimeField in the QuerySets model that the generic view should use to look up the object according to year, month and day. Either object_id or (slug and slug_field) is required. If you provide object_id, it should be the value of the primary-key eld for the object being displayed on this page. Otherwise, slug should be the slug of the given object, and slug_field should be the name of the slug eld in the QuerySets model. By default, slug_field is slug. Optional arguments: month_format: A format string that regulates what format the month parameter uses. This should be in the syntax accepted by Pythons time.strftime. (See the strftime docs.) Its set to "%b" by default, which is a three-letter month abbreviation. To change it to use numbers, use "%m". day_format: Like month_format, but for the day parameter. It defaults to "%d" (day of the month as a decimal number, 01-31). template_name: The full name of a template to use in rendering the page. This lets you override the default template name (see below). template_name_field: The name of a eld on the object whose value is the template name to use. This lets you store template names in the data. In other words, if your object has a eld the_template that contains a string foo.html, and you set template_name_field to the_template, then the generic view for this object will use the template foo.html. Its a bit of a brain-bender, but its useful in some cases. template_loader: The template loader to use when loading the template. django.template.loader. By default, its
extra_context: A dictionary of values to add to the template context. By default, this is an empty dictionary. If a value in the dictionary is callable, the generic view will call it just before rendering the template. context_processors: A list of template-context processors to apply to the views template. template_object_name: Designates the name of the template variable to use in the template context. By default, this is object. mimetype: The MIME type to use for the resulting document. DEFAULT_CONTENT_TYPE setting. Defaults to the value of the
allow_future: A boolean specifying whether to include future objects on this page, where future means objects in which the eld specied in date_field is greater than the current date/time. By default, this is False. Template name: If template_name isnt specied, this view will use the template <app_label>/<model_name>_detail.html by default. Template context: In addition to extra_context, the templates context will be: object: The object. This variables name depends on the template_object_name parameter, which is object by default. If template_object_name is foo, this variables name will be foo.
727
55.3.1 django.views.generic.list_detail.object_list
Description: A page representing a list of objects. Required arguments: queryset: A QuerySet that represents the objects. Optional arguments: paginate_by: An integer specifying how many objects should be displayed per page. If this is given, the view will paginate objects with paginate_by objects per page. The view will expect either a page query string parameter (via GET) or a page variable specied in the URLconf. See Notes on pagination below. page: The current page number, as an integer, or the string last. This is 1-based. See Notes on pagination below. template_name: The full name of a template to use in rendering the page. This lets you override the default template name (see below). template_loader: The template loader to use when loading the template. django.template.loader. By default, its
extra_context: A dictionary of values to add to the template context. By default, this is an empty dictionary. If a value in the dictionary is callable, the generic view will call it just before rendering the template. allow_empty: A boolean specifying whether to display the page if no objects are available. If this is False and no objects are available, the view will raise a 404 instead of displaying an empty page. By default, this is True. context_processors: A list of template-context processors to apply to the views template. template_object_name: Designates the name of the template variable to use in the template context. By default, this is object. The view will append _list to the value of this parameter in determining the variables name. mimetype: The MIME type to use for the resulting document. DEFAULT_CONTENT_TYPE setting. Template name: If template_name isnt specied, this view will use the template <app_label>/<model_name>_list.html by default. Template context: New in version 1.0: The paginator and page_obj context variables are new. In addition to extra_context, the templates context will be: object_list: The list of objects. This variables name depends on the template_object_name parameter, which is object by default. If template_object_name is foo, this variables name will be foo_list. is_paginated: A boolean representing whether the results are paginated. Specically, this is set to False if the number of available objects is less than or equal to paginate_by. If the results are paginated, the context will contain these extra variables: 728 Chapter 55. Generic views Defaults to the value of the
paginator: An instance of django.core.paginator.Paginator. page_obj: An instance of django.core.paginator.Page. Notes on pagination If paginate_by is specied, Django will paginate the results. You can specify the page number in the URL in one of two ways: Use the page parameter in the URLconf. For example, this is what your URLconf might look like:
(r^objects/page(?P<page>[0-9]+)/$, object_list, dict(info_dict))
Pass the page number via the page query-string parameter. For example, a URL would look like this:
/objects/?page=3
To loop over all the available page numbers, use the page_range variable. You can iterate over the list provided by page_range to create a link to every page of results. These values and lists are 1-based, not 0-based, so the rst page would be represented as page 1. For more on pagination, read the pagination documentation. New in version 1.0: Please, see the release notes As a special case, you are also permitted to use last as a value for page:
/objects/?page=last
This allows you to access the nal page of results without rst having to determine how many pages there are. Note that page must be either a valid page number or the value last; any other value for page will result in a 404 error.
55.3.2 django.views.generic.list_detail.object_detail
A page representing an individual object. Description: A page representing an individual object. Required arguments: queryset: A QuerySet that contains the object. Either object_id or (slug and slug_field) is required. If you provide object_id, it should be the value of the primary-key eld for the object being displayed on this page. Otherwise, slug should be the slug of the given object, and slug_field should be the name of the slug eld in the QuerySets model. By default, slug_field is slug. Optional arguments: template_name: The full name of a template to use in rendering the page. This lets you override the default template name (see below).
729
template_name_field: The name of a eld on the object whose value is the template name to use. This lets you store template names in the data. In other words, if your object has a eld the_template that contains a string foo.html, and you set template_name_field to the_template, then the generic view for this object will use the template foo.html. Its a bit of a brain-bender, but its useful in some cases. template_loader: The template loader to use when loading the template. django.template.loader. By default, its
extra_context: A dictionary of values to add to the template context. By default, this is an empty dictionary. If a value in the dictionary is callable, the generic view will call it just before rendering the template. context_processors: A list of template-context processors to apply to the views template. template_object_name: Designates the name of the template variable to use in the template context. By default, this is object. mimetype: The MIME type to use for the resulting document. DEFAULT_CONTENT_TYPE setting. Template name: If template_name isnt specied, this view will use the template <app_label>/<model_name>_detail.html by default. Template context: In addition to extra_context, the templates context will be: object: The object. This variables name depends on the template_object_name parameter, which is object by default. If template_object_name is foo, this variables name will be foo. Defaults to the value of the
55.4.1 django.views.generic.create_update.create_object
Description: A page that displays a form for creating an object, redisplaying the form with validation errors (if there are any) and saving the object. Required arguments: Either form_class or model is required. If you provide form_class, it should be a django.forms.ModelForm subclass. Use this argument when you need to customize the models form. See the ModelForm docs for more information. Otherwise, model should be a Django model class and the form used will be a standard ModelForm for model. Optional arguments:
730
post_save_redirect: A URL to which the view will redirect after saving the object. By default, its object.get_absolute_url(). post_save_redirect may contain dictionary string formatting, which will be interpolated against the objects eld attributes. For example, you could use post_save_redirect="/polls/%(slug)s/". login_required: A boolean that designates whether a user must be logged in, in order to see the page and save changes. This hooks into the Django authentication system. By default, this is False. If this is True, and a non-logged-in user attempts to visit this page or save the form, Django will redirect the request to /accounts/login/. template_name: The full name of a template to use in rendering the page. This lets you override the default template name (see below). template_loader: The template loader to use when loading the template. django.template.loader. By default, its
extra_context: A dictionary of values to add to the template context. By default, this is an empty dictionary. If a value in the dictionary is callable, the generic view will call it just before rendering the template. context_processors: A list of template-context processors to apply to the views template. Template name: If template_name isnt specied, this view will use the template <app_label>/<model_name>_form.html by default. Template context: In addition to extra_context, the templates context will be: form: A django.forms.ModelForm instance representing the form for creating the object. This lets you refer to form elds easily in the template system. For example, if the model has two elds, name and address:
<form action="" method="post"> <p>{{ form.name.label_tag }} {{ form.name }}</p> <p>{{ form.address.label_tag }} {{ form.address }}</p> </form>
See the forms documentation for more information about using Form objects in templates.
55.4.2 django.views.generic.create_update.update_object
Description: A page that displays a form for editing an existing object, redisplaying the form with validation errors (if there are any) and saving changes to the object. This uses a form automatically generated from the objects model class. Required arguments: Either form_class or model is required. If you provide form_class, it should be a django.forms.ModelForm subclass. Use this argument when you need to customize the models form. See the ModelForm docs for more information. Otherwise, model should be a Django model class and the form used will be a standard ModelForm for model.
731
Either object_id or (slug and slug_field) is required. If you provide object_id, it should be the value of the primary-key eld for the object being displayed on this page. Otherwise, slug should be the slug of the given object, and slug_field should be the name of the slug eld in the QuerySets model. By default, slug_field is slug. Optional arguments: post_save_redirect: A URL to which the view will redirect after saving the object. By default, its object.get_absolute_url(). post_save_redirect may contain dictionary string formatting, which will be interpolated against the objects eld attributes. For example, you could use post_save_redirect="/polls/%(slug)s/". login_required: A boolean that designates whether a user must be logged in, in order to see the page and save changes. This hooks into the Django authentication system. By default, this is False. If this is True, and a non-logged-in user attempts to visit this page or save the form, Django will redirect the request to /accounts/login/. template_name: The full name of a template to use in rendering the page. This lets you override the default template name (see below). template_loader: The template loader to use when loading the template. django.template.loader. By default, its
extra_context: A dictionary of values to add to the template context. By default, this is an empty dictionary. If a value in the dictionary is callable, the generic view will call it just before rendering the template. context_processors: A list of template-context processors to apply to the views template. template_object_name: Designates the name of the template variable to use in the template context. By default, this is object. Template name: If template_name isnt specied, this view will use the template <app_label>/<model_name>_form.html by default. Template context: In addition to extra_context, the templates context will be: form: A django.forms.ModelForm instance representing the form for editing the object. This lets you refer to form elds easily in the template system. For example, if the model has two elds, name and address:
<form action="" method="post"> <p>{{ form.name.label_tag }} {{ form.name }}</p> <p>{{ form.address.label_tag }} {{ form.address }}</p> </form>
See the forms documentation for more information about using Form objects in templates. object: The original object being edited. This variables name depends on the template_object_name parameter, which is object by default. If template_object_name is foo, this variables name will be foo.
732
55.4.3 django.views.generic.create_update.delete_object
Description: A view that displays a conrmation page and deletes an existing object. The given object will only be deleted if the request method is POST. If this view is fetched via GET, it will display a conrmation page that should contain a form that POSTs to the same URL. Required arguments: model: The Django model class of the object that the form will create. Either object_id or (slug and slug_field) is required. If you provide object_id, it should be the value of the primary-key eld for the object being displayed on this page. Otherwise, slug should be the slug of the given object, and slug_field should be the name of the slug eld in the QuerySets model. By default, slug_field is slug. post_delete_redirect: A URL to which the view will redirect after deleting the object. Optional arguments: login_required: A boolean that designates whether a user must be logged in, in order to see the page and save changes. This hooks into the Django authentication system. By default, this is False. If this is True, and a non-logged-in user attempts to visit this page or save the form, Django will redirect the request to /accounts/login/. template_name: The full name of a template to use in rendering the page. This lets you override the default template name (see below). template_loader: The template loader to use when loading the template. django.template.loader. By default, its
extra_context: A dictionary of values to add to the template context. By default, this is an empty dictionary. If a value in the dictionary is callable, the generic view will call it just before rendering the template. context_processors: A list of template-context processors to apply to the views template. template_object_name: Designates the name of the template variable to use in the template context. By default, this is object. Template name: If template_name isnt specied, this view will use the template <app_label>/<model_name>_confirm_delete.html by default. Template context: In addition to extra_context, the templates context will be: object: The original object thats about to be deleted. This variables name depends on the template_object_name parameter, which is object by default. If template_object_name is foo, this variables name will be foo.
733
734
CHAPTER
FIFTYSIX
MIDDLEWARE
This document explains all middleware components that come with Django. For information on how how to use them and how to write your own middleware, see the middleware usage guide.
735
736
737
738
CHAPTER
FIFTYSEVEN
MODELS
Model API reference. For introductory material, see Models.
739
blank blank If True, the eld is allowed to be blank. Default is False. Note that this is different than null. null is purely database-related, whereas blank is validation-related. If a eld has blank=True, validation on Djangos admin site will allow entry of an empty value. If a eld has blank=False, the eld will be required. choices choices An iterable (e.g., a list or tuple) of 2-tuples to use as choices for this eld. If this is given, Djangos admin will use a select box instead of the standard text eld and will limit choices to the choices given. A choices list looks like this:
YEAR_IN_SCHOOL_CHOICES = ( (FR, Freshman), (SO, Sophomore), (JR, Junior), (SR, Senior), (GR, Graduate), )
The rst element in each tuple is the actual value to be stored. The second element is the human-readable name for the option. The choices list can be dened either as part of your model class:
class Foo(models.Model): GENDER_CHOICES = ( (M, Male), (F, Female), ) gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
You can also collect your available choices into named groups that can be used for organizational purposes:
MEDIA_CHOICES = ( (Audio, ( (vinyl, Vinyl), (cd, CD), ) ),
740
The rst element in each tuple is the name to apply to the group. The second element is an iterable of 2-tuples, with each 2-tuple containing a value and a human-readable name for an option. Grouped options may be combined with ungrouped options within a single list (such as the unknown option in this example). For each model eld that has choices set, Django will add a method to retrieve the human-readable name for the elds current value. See get_FOO_display() in the database API documentation. Finally, note that choices can be any iterable object not necessarily a list or tuple. This lets you construct choices dynamically. But if you nd yourself hacking choices to be dynamic, youre probably better off using a proper database table with a ForeignKey. choices is meant for static data that doesnt change much, if ever. db_column db_column The name of the database column to use for this eld. If this isnt given, Django will use the elds name. If your database column name is an SQL reserved word, or contains characters that arent allowed in Python variable names notably, the hyphen thats OK. Django quotes column and table names behind the scenes. db_index db_index If True, djadmin:django-admin.py sqlindexes <sqlindexes> will output a CREATE INDEX statement for this eld. db_tablespace db_tablespace New in version 1.0: Please, see the release notes The name of the database tablespace to use for this elds index, if this eld is indexed. The default is the projects DEFAULT_INDEX_TABLESPACE setting, if set, or the db_tablespace of the model, if any. If the backend doesnt support tablespaces, this option is ignored. default default The default value for the eld. This can be a value or a callable object. If callable it will be called every time a new object is created. editable editable If False, the eld will not be editable in the admin or via forms automatically generated from the model class. Default is True. 57.1. Model eld reference 741
error_messages New in version 1.2: Please, see the release notes error_messages The error_messages argument lets you override the default messages that the eld will raise. Pass in a dictionary with keys matching the error messages you want to override. help_text help_text Extra help text to be displayed under the eld on the objects admin form. Its useful for documentation even if your object doesnt have an admin form. Note that this value is not HTML-escaped when its displayed in the admin interface. This lets you include HTML in help_text if you so desire. For example:
help_text="Please use the following format: <em>YYYY-MM-DD</em>."
Alternatively you can use plain text and django.utils.html.escape() to escape any HTML special characters. primary_key primary_key If True, this eld is the primary key for the model. If you dont specify primary_key=True for any elds in your model, Django will automatically add an IntegerField to hold the primary key, so you dont need to set primary_key=True on any of your elds unless you want to override the default primary-key behavior. For more, see Automatic primary key elds. primary_key=True implies null=False and unique=True. Only one primary key is allowed on an object. unique unique If True, this eld must be unique throughout the table. This is enforced at the database level and at the Django admin-form level. If you try to save a model with a duplicate value in a unique eld, a django.db.IntegrityError will be raised by the models save() method. This option is valid on all eld types except ManyToManyField and FileField. unique_for_date unique_for_date Set this to the name of a DateField or DateTimeField to require that this eld be unique for the value of the date eld. For example, if you have a eld title that has unique_for_date="pub_date", then Django wouldnt allow the entry of two records with the same title and pub_date. This is enforced at the Django admin-form level but not at the database level. 742 Chapter 57. Models
unique_for_month unique_for_month Like unique_for_date, but requires the eld to be unique with respect to the month. unique_for_year unique_for_year Like unique_for_date and unique_for_month. verbose_name verbose_name A human-readable name for the eld. If the verbose name isnt given, Django will automatically create it using the elds attribute name, converting underscores to spaces. See Verbose eld names. validators New in version 1.2: Please, see the release notes validators A list of validators to run for this eld.See the validators documentation for more information.
743
CharField class CharField(max_length=None, [**options]) A string eld, for small- to large-sized strings. For large amounts of text, use TextField. The admin represents this as an <input type="text"> (a single-line input). CharField has one extra required argument: max_length The maximum length (in characters) of the eld. The max_length is enforced at the database level and in Djangos validation. Note: If you are writing an application that must be portable to multiple database backends, you should be aware that there are restrictions on max_length for some backends. Refer to the database backend notes for details. MySQL users If you are using this eld with MySQLdb 1.2.2 and the utf8_bin collation (which is not the default), there are some issues to be aware of. Refer to the MySQL database notes for details. CommaSeparatedIntegerField class CommaSeparatedIntegerField(max_length=None, [**options]) A eld of integers separated by commas. As in CharField, the max_length argument is required and the note about database portability mentioned there should be heeded. DateField class DateField([auto_now=False, auto_now_add=False, **options]) A date, represented in Python by a datetime.date instance. Has a few extra, optional arguments: auto_now Automatically set the eld to now every time the object is saved. Useful for last-modied timestamps. Note that the current date is always used; its not just a default value that you can override. auto_now_add Automatically set the eld to now when the object is rst created. Useful for creation of timestamps. Note that the current date is always used; its not just a default value that you can override. The admin represents this as an <input type="text"> with a JavaScript calendar, and a shortcut for Today. The JavaScript calendar will always start the week on a Sunday. DateTimeField class DateTimeField([auto_now=False, auto_now_add=False, **options]) A date and time, represented in Python by a datetime.datetime instance. Takes the same extra arguments as DateField. The admin represents this as two <input type="text"> elds, with JavaScript shortcuts.
744
DecimalField New in version 1.0: Please, see the release notes class DecimalField(max_digits=None, decimal_places=None, [**options]) A xed-precision decimal number, represented in Python by a Decimal instance. Has two required arguments: max_digits The maximum number of digits allowed in the number decimal_places The number of decimal places to store with the number For example, to store numbers up to 999 with a resolution of 2 decimal places, youd use:
models.DecimalField(..., max_digits=5, decimal_places=2)
And to store numbers up to approximately one billion with a resolution of 10 decimal places:
models.DecimalField(..., max_digits=19, decimal_places=10)
The admin represents this as an <input type="text"> (a single-line input). EmailField class EmailField([max_length=75, **options]) A CharField that checks that the value is a valid e-mail address. FileField class FileField(upload_to=None, [max_length=100, **options]) A le-upload eld. Note: The primary_key and unique arguments are not supported, and will raise a TypeError if used. Has one required argument: upload_to A local lesystem path that will be appended to your MEDIA_ROOT setting to determine the value of the url attribute. This path may contain strftime formatting, which will be replaced by the date/time of the le upload (so that uploaded les dont ll up the given directory). Changed in version 1.0: Please, see the release notes This may also be a callable, such as a function, which will be called to obtain the upload path, including the lename. This callable must be able to accept two arguments, and return a Unix-style path (with forward slashes) to be passed along to the storage system. The two arguments that will be passed are: ArguDescription ment instance An instance of the model where the FileField is dened. More specically, this is the particular instance where the current le is being attached. In most cases, this object will not have been saved to the database yet, so if it uses the default AutoField, it might not yet have a value for its primary key eld. filename The lename that was originally given to the le. This may or may not be taken into account when determining the nal destination path.
745
Also has one optional argument: storage New in version 1.0: Please, see the release notes Optional. A storage object, which handles the storage and retrieval of your les. See Managing les for details on how to provide this object. The admin represents this eld as an <input type="file"> (a le-upload widget). Using a FileField or an ImageField (see below) in a model takes a few steps: 1. In your settings le, youll need to dene MEDIA_ROOT as the full path to a directory where youd like Django to store uploaded les. (For performance, these les are not stored in the database.) Dene MEDIA_URL as the base public URL of that directory. Make sure that this directory is writable by the Web servers user account. 2. Add the FileField or ImageField to your model, making sure to dene the upload_to option to tell Django to which subdirectory of MEDIA_ROOT it should upload les. 3. All that will be stored in your database is a path to the le (relative to MEDIA_ROOT). Youll most likely want to use the convenience url function provided by Django. For example, if your ImageField is called mug_shot, you can get the absolute URL to your image in a template with {{ object.mug_shot.url }}. For example, say your MEDIA_ROOT is set to /home/media, and upload_to is set to photos/%Y/%m/%d. The %Y/%m/%d part of upload_to is strftime formatting; %Y is the fourdigit year, %m is the two-digit month and %d is the two-digit day. If you upload a le on Jan. 15, 2007, it will be saved in the directory /home/media/photos/2007/01/15. If you want to retrieve the upload les on-disk lename, or a URL that refers to that le, or the les size, you can use the name, url and size attributes; see Managing les. Note that whenever you deal with uploaded les, you should pay close attention to where youre uploading them and what type of les they are, to avoid security holes. Validate all uploaded les so that youre sure the les are what you think they are. For example, if you blindly let somebody upload les, without validation, to a directory thats within your Web servers document root, then somebody could upload a CGI or PHP script and execute that script by visiting its URL on your site. Dont allow that. New in version 1.0: The max_length argument was added in this version. By default, FileField instances are created as varchar(100) columns in your database. As with other elds, you can change the maximum length using the max_length argument.
delete(save=True) Deletes the le associated with this instance and clears all attributes on the eld. Note: This method will close the le if it happens to be open when delete() is called. The optional save argument controls whether or not the instance is saved after the le has been deleted. Defaults to True. FilePathField class FilePathField(path=None, [match=None, recursive=False, max_length=100, **options]) A CharField whose choices are limited to the lenames in a certain directory on the lesystem. Has three special arguments, of which the rst is required: path Required. The absolute lesystem path to a directory from which this FilePathField should get its choices. Example: "/home/images". match Optional. A regular expression, as a string, that FilePathField will use to lter lenames. Note that the regex will be applied to the base lename, not the full path. Example: "foo.*\.txt$", which will match a le called foo23.txt but not bar.txt or foo23.gif. recursive Optional. Either True or False. Default is False. Species whether all subdirectories of path should be included Of course, these arguments can be used together. The one potential gotcha is that match applies to the base lename, not the full path. So, this example:
FilePathField(path="/home/images", match="foo.*", recursive=True)
...will match /home/images/foo.gif but not /home/images/foo/bar.gif because the match applies to the base lename (foo.gif and bar.gif). New in version 1.0: The max_length argument was added in this version. By default, FilePathField instances are created as varchar(100) columns in your database. As with other elds, you can change the maximum length using the max_length argument. FloatField class FloatField([**options]) Changed in version 1.0: Please, see the release notes A oating-point number represented in Python by a float instance. The admin represents this as an <input type="text"> (a single-line input). ImageField class ImageField(upload_to=None, [height_eld=None, width_eld=None, max_length=100, **options]) Inherits all attributes and methods from FileField, but also validates that the uploaded object is a valid image. In addition to the special attributes that are available for FileField, an ImageField also has height and width attributes. To facilitate querying on those attributes, ImageField has two extra optional arguments:
747
height_field Name of a model eld which will be auto-populated with the height of the image each time the model instance is saved. width_field Name of a model eld which will be auto-populated with the width of the image each time the model instance is saved. Requires the Python Imaging Library. New in version 1.0: The max_length argument was added in this version. By default, ImageField instances are created as varchar(100) columns in your database. As with other elds, you can change the maximum length using the max_length argument. IntegerField class IntegerField([**options]) An integer. The admin represents this as an <input type="text"> (a single-line input). IPAddressField class IPAddressField([**options]) An IP address, in string format (e.g. 192.0.2.30). The admin represents this as an <input type="text"> (a single-line input). NullBooleanField class NullBooleanField([**options]) Like a BooleanField, but allows NULL as one of the options. Use this instead of a BooleanField with null=True. The admin represents this as a <select> box with Unknown, Yes and No choices. PositiveIntegerField class PositiveIntegerField([**options]) Like an IntegerField, but must be positive. PositiveSmallIntegerField class PositiveSmallIntegerField([**options]) Like a PositiveIntegerField, but only allows values under a certain (database-dependent) point. SlugField class SlugField([max_length=50, **options]) Slug is a newspaper term. A slug is a short label for something, containing only letters, numbers, underscores or hyphens. Theyre generally used in URLs. Like a CharField, you can specify max_length (read the note about database portability and max_length in that section, too). If max_length is not specied, Django will use a default length of 50. Implies setting Field.db_index to True. 748 Chapter 57. Models
It is often useful to automatically prepopulate a SlugField based on the value of some other value. You can do this automatically in the admin using prepopulated_fields. SmallIntegerField class SmallIntegerField([**options]) Like an IntegerField, but only allows values under a certain (database-dependent) point. TextField class TextField([**options]) A large text eld. The admin represents this as a <textarea> (a multi-line input). MySQL users If you are using this eld with MySQLdb 1.2.1p2 and the utf8_bin collation (which is not the default), there are some issues to be aware of. Refer to the MySQL database notes for details. TimeField class TimeField([auto_now=False, auto_now_add=False, **options]) A time, represented in Python by a datetime.time instance. Accepts the same auto-population options as DateField. The admin represents this as an <input type="text"> with some JavaScript shortcuts. URLField class URLField([verify_exists=True, max_length=200, **options]) A CharField for a URL. Has one extra optional argument: verify_exists If True (the default), the URL given will be checked for existence (i.e., the URL actually loads and doesnt give a 404 response). Note that when youre using the single-threaded development server, validating a URL being served by the same server will hang. This should not be a problem for multithreaded servers. The admin represents this as an <input type="text"> (a single-line input). Like all CharField subclasses, URLField takes the optional max_length, a default of 200 is used. XMLField class XMLField(schema_path=None, [**options]) A TextField that checks that the value is valid XML that matches a given schema. Takes one required argument: schema_path The lesystem path to a RelaxNG schema against which to validate the eld.
749
New in version 1.0: Please, see the release notes To refer to models dened in another application, you can explicitly specify a model with the full application label. For example, if the Manufacturer model above is dened in another application called production, youd need to use:
class Car(models.Model): manufacturer = models.ForeignKey(production.Manufacturer)
This sort of reference can be useful when resolving circular import dependencies between two applications.
Database Representation
Behind the scenes, Django appends "_id" to the eld name to create its database column name. In the above example, the database table for the Car model will have a manufacturer_id column. (You can change this explicitly by specifying db_column) However, your code should never have to deal with the database column name, unless you write custom SQL. Youll always deal with the eld names of your model object.
Arguments
ForeignKey accepts an extra set of arguments all optional that dene the details of how the relation works. limit_choices_to A dictionary of lookup arguments and values (see Making queries) that limit the available admin choices for this object. Use this with functions from the Python datetime module to limit choices of objects by date. For example:
limit_choices_to = {pub_date__lte: datetime.now}
only allows the choice of related objects with a pub_date before the current date/time to be chosen. Instead of a dictionary this can also be a Q object for more complex queries. However, if limit_choices_to is a Q object then it will only have an effect on the choices available in the admin when the eld is not listed in raw_id_fields in the ModelAdmin for the model.
750
related_name The name to use for the relation from the related object back to this one. See the related objects documentation for a full explanation and example. Note that you must set this value when dening relations on abstract models; and when you do so some special syntax is available. to_field The eld on the related object that the relation is to. By default, Django uses the primary key of the related object. ManyToManyField class ManyToManyField(othermodel, [**options]) A many-to-many relationship. Requires a positional argument: the class to which the model is related. This works exactly the same as it does for ForeignKey, including all the options regarding recursive and lazy relationships.
Database Representation
Behind the scenes, Django creates an intermediary join table to represent the many-to-many relationship. By default, this table name is generated using the name of the many-to-many eld and the model that contains it. Since some databases dont support table names above a certain length, these table names will be automatically truncated to 64 characters and a uniqueness hash will be used. This means you might see table names like author_books_9cdf4; this is perfectly normal. You can manually provide the name of the join table using the db_table option.
Arguments
ManyToManyField accepts an extra set of arguments all optional that control how the relationship functions. related_name Same as ForeignKey.related_name. limit_choices_to Same as ForeignKey.limit_choices_to. limit_choices_to has no effect when used on a ManyToManyField with a custom intermediate table specied using the through parameter. symmetrical Only used in the denition of ManyToManyFields on self. Consider the following model:
class Person(models.Model): friends = models.ManyToManyField("self")
When Django processes this model, it identies that it has a ManyToManyField on itself, and as a result, it doesnt add a person_set attribute to the Person class. Instead, the ManyToManyField is assumed to be symmetrical that is, if I am your friend, then you are my friend. If you do not want symmetry in many-to-many relationships with self, set symmetrical to False. This will force Django to add the descriptor for the reverse relationship, allowing ManyToManyField relationships to be non-symmetrical. through Django will automatically generate a table to manage many-to-many relationships. However, if you want to manually specify the intermediary table, you can use the through option to specify the Django model that represents the intermediate table that you want to use.
751
The most common use for this option is when you want to associate extra data with a many-to-many relationship. db_table The name of the table to create for storing the many-to-many data. If this is not provided, Django will assume a default name based upon the names of the two tables being joined. OneToOneField class OneToOneField(othermodel, [parent_link=False, **options]) A one-to-one relationship. Conceptually, this is similar to a ForeignKey with unique=True, but the reverse side of the relation will directly return a single object. This is most useful as the primary key of a model which extends another model in some way; Multi-table inheritance is implemented by adding an implicit one-to-one relation from the child model to the parent model, for example. One positional argument is required: the class to which the model will be related. This works exactly the same as it does for ForeignKey, including all the options regarding recursive and lazy relationships. Additionally, OneToOneField accepts all of the extra arguments accepted by ForeignKey, plus one extra argument: parent_link When True and used in a model which inherits from another (concrete) model, indicates that this eld should be used as the link back to the parent class, rather than the extra OneToOneField which would normally be implicitly created by subclassing.
In the above example, the methods below will be available on the manager reporter.article_set. Both sides of a ManyToManyField relation:
class Topping(models.Model): ... class Pizza(models.Model): toppings = models.ManyToManyField(Topping)
In this example, the methods below will be available both on topping.pizza_set and on pizza.toppings. These related managers have some extra methods: add(obj1, [obj2, ...]) Adds the specied model objects to the related object set.
752
Example:
>>> b = Blog.objects.get(id=1) >>> e = Entry.objects.get(id=234) >>> b.entry_set.add(e) # Associates Entry e with Blog b.
create(**kwargs) Creates a new object, saves it and puts it in the related object set. Returns the newly created object:
>>> b = Blog.objects.get(id=1) >>> e = b.entry_set.create( ... headline=Hello, ... body_text=Hi, ... pub_date=datetime.date(2005, 1, 1) ... ) # No need to call e.save() at this point -- its already been saved.
Note that theres no need to specify the keyword argument of the model that denes the relationship. In the above example, we dont pass the parameter blog to create(). Django gures out that the new Entry objects blog eld should be set to b. remove(obj1, [obj2, ...]) Removes the specied model objects from the related object set:
>>> b = Blog.objects.get(id=1) >>> e = Entry.objects.get(id=234) >>> b.entry_set.remove(e) # Disassociates Entry e from Blog b.
In order to prevent database inconsistency, this method only exists on ForeignKey objects where null=True. If the related eld cant be set to None (NULL), then an object cant be removed from a relation without being added to another. In the above example, removing e from b.entry_set() is equivalent to doing e.blog = None, and because the blog ForeignKey doesnt have null=True, this is invalid. clear() Removes all objects from the related object set:
>>> b = Blog.objects.get(id=1) >>> b.entry_set.clear()
Note this doesnt delete the related objects it just disassociates them. Just like remove(), clear() is only available on ForeignKeys where null=True.
753
db_table db_table The name of the database table to use for the model:
db_table = music_album
Table names
To save you time, Django automatically derives the name of the database table from the name of your model class and the app that contains it. A models database table name is constructed by joining the models app label the name you used in manage.py startapp to the models class name, with an underscore between them. For example, if you have an app bookstore (as created by manage.py startapp bookstore), a model dened as class Book will have a database table named bookstore_book. To override the database table name, use the db_table parameter in class Meta. If your database table name is an SQL reserved word, or contains characters that arent allowed in Python variable names notably, the hyphen thats OK. Django quotes column and table names behind the scenes. db_tablespace db_tablespace New in version 1.0: Please, see the release notes The name of the database tablespace to use for the model. If the backend doesnt support tablespaces, this option is ignored.
754
get_latest_by get_latest_by The name of a DateField or DateTimeField in the model. This species the default eld to use in your model Managers latest method. Example:
get_latest_by = "order_date"
See the docs for latest() for more. managed managed New in version 1.1: Please, see the release notes Defaults to True, meaning Django will create the appropriate database tables in syncdb and remove them as part of a reset management command. That is, Django manages the database tables lifecycles. If False, no database table creation or deletion operations will be performed for this model. This is useful if the model represents an existing table or a database view that has been created by some other means. This is the only difference when managed is False. All other aspects of model handling are exactly the same as normal. This includes 1. Adding an automatic primary key eld to the model if you dont declare it. To avoid confusion for later code readers, its recommended to specify all the columns from the database table you are modeling when using unmanaged models. 2. If a model with managed=False contains a ManyToManyField that points to another unmanaged model, then the intermediate table for the many-to-many join will also not be created. However, a the intermediary table between one managed and one unmanaged model will be created. If you need to change this default behavior, create the intermediary table as an explicit model (with managed set as needed) and use the ManyToManyField.through attribute to make the relation use your custom model. For tests involving models with managed=False, its up to you to ensure the correct tables are created as part of the test setup. If youre interested in changing the Python-level behavior of a model class, you could use managed=False and create a copy of an existing model. However, theres a better approach for that situation: Proxy models. order_with_respect_to order_with_respect_to Marks this object as orderable with respect to the given eld. This is almost always used with related objects to allow them to be ordered with respect to a parent object. For example, if an Answer relates to a Question object, and a question has more than one answer, and the order of answers matters, youd do this:
class Answer(models.Model): question = models.ForeignKey(Question) # ... class Meta: order_with_respect_to = question
755
ordering ordering The default ordering for the object, for use when obtaining lists of objects:
ordering = [-order_date]
This is a tuple or list of strings. Each string is a eld name with an optional - prex, which indicates descending order. Fields without a leading - will be ordered ascending. Use the string ? to order randomly. Note: Regardless of how many elds are in ordering, the admin site uses only the rst eld. For example, to order by a pub_date eld ascending, use this:
ordering = [pub_date]
permissions permissions Extra permissions to enter into the permissions table when creating this object. Add, delete and change permissions are automatically created for each object that has admin set. This example species an extra permission, can_deliver_pizzas:
permissions = (("can_deliver_pizzas", "Can deliver pizzas"),)
2-tuples
in
the
format
(permission_code,
New in version 1.1: Please, see the release notes If set to True, a model which subclasses another model will be treated as a proxy model. unique_together unique_together Sets of eld names that, taken together, must be unique:
unique_together = (("driver", "restaurant"),)
756
This is a list of lists of elds that must be unique when considered together. Its used in the Django admin and is enforced at the database level (i.e., the appropriate UNIQUE statements are included in the CREATE TABLE statement). New in version 1.0: Please, see the release notes For convenience, unique_together can be a single list when dealing with a single set of elds:
unique_together = ("driver", "restaurant")
If this isnt given, Django will use a munged version of the class name: CamelCase becomes camel case. verbose_name_plural verbose_name_plural The plural name for the object:
verbose_name_plural = "stories"
757
All three steps are performed when you call by a models full_clean() method. When you use a ModelForm, the call to is_valid() will perform these validation steps for all the elds that are included on the form. (See the ModelForm documentation for more information.) You should only need to call a models full_clean() method if you plan to handle validation errors yourself, or if you have excluded elds from the ModelForm that require validation. full_clean(exclude=None) This method calls Model.clean_fields(), Model.clean(), and Model.validate_unique(), in that order and raises a ValidationError that has a message_dict attribute containing errors from all three stages. The optional exclude argument can be used to provide a list of eld names that can be excluded from validation and cleaning. ModelForm uses this argument to exclude elds that arent present on your form from being validated since any errors raised could not be corrected by the user. Note that full_clean() will not be called automatically when you call your models save() method, nor as a result of ModelForm validation. Youll need to call it manually when you want to run model validation outside of a ModelForm. Example:
try: article.full_clean() except ValidationError, e: # Do something based on the errors contained in e.error_dict. # Display them to a user, or handle them programatically.
The rst step full_clean() performs is to clean each individual eld. clean_fields(exclude=None) This method will validate all elds on your model. The optional exclude argument lets you provide a list of eld names to exclude from validation. It will raise a ValidationError if any elds fail validation. The second step full_clean() performs is to call Model.clean(). This method should be overridden to perform custom validation on your model. clean() This method should be used to provide custom model validation, and to modify attributes on your model if desired. For instance, you could use it to automatically provide a value for a eld, or to do validation that requires access to more than a single eld:
def clean(self): from django.core.exceptions import ValidationError # Dont allow draft entries to have a pub_date. if self.status == draft and self.pub_date is not None: raise ValidationError(Draft entries may not have a publication date.) # Set the pub_date for published items if it hasnt been set already. if self.status == published and self.pub_date is None: self.pub_date = datetime.datetime.now()
Any ValidationError raised by Model.clean() will be stored under a special key that is used for errors that are tied to the entire model instead of to a specic eld. You can access these errors with NON_FIELD_ERRORS:
from django.core.validators import ValidationError, NON_FIELD_ERRORS try: article.full_clean(): except ValidationError, e: non_field_errors = e.message_dict[NON_FIELD_ERRORS]
758
Finally, full_clean() will check any unique constraints on your model. validate_unique(exclude=None) This method is similar to clean_fields, but validates all uniqueness constraints on your model instead of individual eld values. The optional exclude argument allows you to provide a list of eld names to exclude from validation. It will raise a ValidationError if any elds fail validation. Note that if you provide an exclude argument to validate_unique, any unique_together constraint that contains one of the elds you provided will not be checked.
Theres no way to tell what the value of an ID will be before you call save(), because that value is calculated by your database, not by Django. (For convenience, each model has an AutoField named id by default unless you explicitly specify primary_key=True on a eld. See the documentation for AutoField for more details.
The pk property
New in version 1.0: Please, see the release notes pk Regardless of whether you dene a primary key eld yourself, or let Django supply one for you, each model will have a property called pk. It behaves like a normal attribute on the model, but is actually an alias for whichever attribute is the primary key eld for the model. You can read and set this value, just as you would for any other attribute, and it will update the correct eld in the model.
759
If you assign auto-primary-key values manually, make sure not to use an already-existing primary-key value! If you create a new object with an explicit primary-key value that already exists in the database, Django will assume youre changing the existing record rather than creating a new one. Given the above Cheddar Talk blog example, this example would override the previous record in the database:
b4 = Blog(id=3, name=Not Cheddar, tagline=Anything but cheese.) b4.save() # Overrides the previous blog with ID=3!
See How Django knows to UPDATE vs. INSERT, below, for the reason this happens. Explicitly specifying auto-primary-key values is mostly useful for bulk-saving objects, when youre condent you wont have primary-key collision. What happens when you save? When you save an object, Django performs the following steps: 1. Emit a pre-save signal. The signal django.db.models.signals.pre_save is sent, allowing any functions listening for that signal to take some customized action. 2. Pre-process the data. Each eld on the object is asked to perform any automated data modication that the eld may need to perform. Most elds do no pre-processing the eld data is kept as-is. Pre-processing is only used on elds that have special behavior. For example, if your model has a DateField with auto_now=True, the pre-save phase will alter the data in the object to ensure that the date eld contains the current date stamp. (Our documentation doesnt yet include a list of all the elds with this special behavior.) 3. Prepare the data for the database. Each eld is asked to provide its current value in a data type that can be written to the database. Most elds require no data preparation. Simple data types, such as integers and strings, are ready to write as a Python object. However, more complex data types often require some modication. For example, DateFields use a Python datetime object to store data. Databases dont store datetime objects, so the eld value must be converted into an ISO-compliant date string for insertion into the database. 4. Insert the data into the database. The pre-processed, prepared data is then composed into an SQL statement for insertion into the database. 5. Emit a post-save signal. The signal django.db.models.signals.post_save is sent, allowing any functions listening for that signal to take some customized action.
760
How Django knows to UPDATE vs. INSERT You may have noticed Django database objects use the same save() method for creating and changing objects. Django abstracts the need to use INSERT or UPDATE SQL statements. Specically, when you call save(), Django follows this algorithm: If the objects primary key attribute is set to a value that evaluates to True (i.e., a value other than None or the empty string), Django executes a SELECT query to determine whether a record with the given primary key already exists. If the record with the given primary key does already exist, Django executes an UPDATE query. If the objects primary key attribute is not set, or if its set but a record doesnt exist, Django executes an INSERT. The one gotcha here is that you should be careful not to specify a primary-key value explicitly when saving new objects, if you cannot guarantee the primary-key value is unused. For more on this nuance, see Explicitly specifying auto-primary-key values above and Forcing an INSERT or UPDATE below.
If the old number_sold value retrieved from the database was 10, then the value of 11 will be written back to the database. This can be optimized slightly by expressing the update relative to the original eld value, rather than as an explicit assignment of a new value. Django provides F() expressions as a way of performing this kind of relative update. Using F() expressions, the previous example would be expressed as:
>>> >>> >>> >>> from django.db.models import F product = Product.objects.get(name=Venezuelan Beaver Cheese) product.number_sold = F(number_sold) + 1 product.save()
This approach doesnt use the initial value from the database. Instead, it makes the database do the update based on whatever value is current at the time that the save() is executed. Once the object has been saved, you must reload the object in order to access the actual value that was applied to the updated eld:
761
For more details, see the documentation on F() expressions and their use in update queries.
__unicode__ __unicode__() The __unicode__() method is called whenever you call unicode() on an object. Since Djangos database backends will return Unicode strings in your models attributes, you would normally want to write a __unicode__() method for your model. The example in the previous section could be written more simply as:
762
class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) def __unicode__(self): return u%s %s % (self.first_name, self.last_name)
If you dene a __unicode__() method on your model and not a __str__() method, Django will automatically provide you with a __str__() that calls __unicode__() and then converts the result correctly to a UTF-8 encoded string object. This is recommended development practice: dene only __unicode__() and let Django take care of the conversion to string objects when required. get_absolute_url get_absolute_url() Dene a get_absolute_url() method to tell Django how to calculate the URL for an object. For example:
def get_absolute_url(self): return "/people/%i/" % self.id
Django uses this in its admin interface. If an object denes get_absolute_url(), the object-editing page will have a View on site link that will jump you directly to the objects public view, according to get_absolute_url(). Also, a couple of other bits of Django, such as the syndication feed framework, use get_absolute_url() as a convenience to reward people whove dened the method. Its good practice to use get_absolute_url() in templates, instead of hard-coding your objects URLs. For example, this template code is bad:
<a href="/people/{{ object.id }}/">{{ object.name }}</a>
Note: The string you return from get_absolute_url() must contain only ASCII characters (required by the URI spec, RFC 2396) that have been URL-encoded, if necessary. Code and templates using get_absolute_url() should be able to use the result directly without needing to do any further processing. You may wish to use the django.utils.encoding.iri_to_uri() function to help with this if you are using unicode strings a lot.
763
(r^people/(\d+)/$, people.views.details),
...your model could have a get_absolute_url method that looked like this:
from django.db import models @models.permalink def get_absolute_url(self): return (people.views.details, [str(self.id)])
Notice that we specify an empty sequence for the second parameter in this case, because we only want to pass keyword parameters, not positional ones. In this way, youre tying the models absolute URL to the view that is used to display it, without repeating the URL information anywhere. You can still use the get_absolute_url method in templates, as before. In some cases, such as the use of generic views or the re-use of custom views for multiple models, specifying the view function may confuse the reverse URL matcher (because multiple patterns point to the same view). For that problem, Django has named URL patterns. Using a named URL pattern, its possible to give a name to a pattern, and then reference the name rather than the view function. A named URL pattern is dened by replacing the pattern tuple by a call to the url function):
from django.conf.urls.defaults import * url(r^people/(\d+)/$, django.views.generic.list_detail.object_detail, name=people_view),
...and then using that name to perform the reverse URL resolution instead of the view name:
from django.db.models import permalink @models.permalink def get_absolute_url(self): return (people_view, [str(self.id)])
More details on named URL patterns are in the URL dispatch documentation.
764
get_next_by_FOO(**kwargs) get_previous_by_FOO(**kwargs) For every DateField and DateTimeField that does not have null=True, the object will have get_next_by_FOO() and get_previous_by_FOO() methods, where FOO is the name of the eld. This returns the next and previous object with respect to the date eld, raising the appropriate DoesNotExist exception when appropriate. Both methods accept optional keyword arguments, which should be in the format described in Field lookups. Note that in the case of identical date values, these methods will use the ID as a fallback check. This guarantees that no records are skipped or duplicated.
765
Slicing. As explained in Limiting QuerySets, a QuerySet can be sliced, using Pythons array-slicing syntax. Usually slicing a QuerySet returns another (unevaluated) QuerySet, but Django will execute the database query if you use the step parameter of slice syntax. Pickling/Caching. See the following section for details of what is involved when pickling QuerySets. The important thing for the purposes of this section is that the results are read from the database. repr(). A QuerySet is evaluated when you call repr() on it. This is for convenience in the Python interactive interpreter, so you can immediately see your results when using the API interactively. len(). A QuerySet is evaluated when you call len() on it. This, as you might expect, returns the length of the result list. Note: Dont use len() on QuerySets if all you want to do is determine the number of records in the set. Its much more efcient to handle a count at the database level, using SQLs SELECT COUNT(*), and Django provides a count() method for precisely this reason. See count() below. list(). Force evaluation of a QuerySet by calling list() on it. For example:
entry_list = list(Entry.objects.all())
Be warned, though, that this could have a large memory overhead, because Django will load each element of the list into memory. In contrast, iterating over a QuerySet will take advantage of your database to load data and instantiate objects only as you need them. bool(). Testing a QuerySet in a boolean context, such as using bool(), or, and or an if statement, will cause the query to be executed. If there is at least one result, the QuerySet is True, otherwise False. For example:
if Entry.objects.filter(headline="Test"): print "There is at least one Entry with the headline Test"
Note: Dont use this if all you want to do is determine if at least one result exists, and dont need the actual objects. Its more efcient to use exists() (see below). Pickling QuerySets If you pickle a QuerySet, this will force all the results to be loaded into memory prior to pickling. Pickling is usually used as a precursor to caching and when the cached queryset is reloaded, you want the results to already be present and ready for use (reading from the database can take some time, defeating the purpose of caching). This means that when you unpickle a QuerySet, it contains the results at the moment it was pickled, rather than the results that are currently in the database. If you only want to pickle the necessary information to recreate the QuerySet from the database at a later time, pickle the query attribute of the QuerySet. You can then recreate the original QuerySet (without any results loaded) using some code like this:
>>> >>> >>> >>> import pickle query = pickle.loads(s) qs = MyModel.objects.all() qs.query = query
766
The query attribute is an opaque object. It represents the internals of the query construction and is not part of the public API. However, it is safe (and fully supported) to pickle and unpickle the attributes contents as described here. You cant share pickles between versions Pickles of QuerySets are only valid for the version of Django that was used to generate them. If you generate a pickle using Django version N, there is no guarantee that pickle will be readable with Django version N+1. Pickles should not be used as part of a long-term archival strategy.
filter(**kwargs)
filter(**kwargs) Returns a new QuerySet containing objects that match the given lookup parameters. The lookup parameters (**kwargs) should be in the format described in Field lookups below. Multiple parameters are joined via AND in the underlying SQL statement.
exclude(**kwargs)
exclude(**kwargs) Returns a new QuerySet containing objects that do not match the given lookup parameters. The lookup parameters (**kwargs) should be in the format described in Field lookups below. Multiple parameters are joined via AND in the underlying SQL statement, and the whole thing is enclosed in a NOT(). This example excludes all entries whose pub_date is later than 2005-1-3 AND whose headline is Hello:
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline=Hello)
This example excludes all entries whose pub_date is later than 2005-1-3 OR whose headline is Hello:
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline=Hello)
767
annotate(*args, **kwargs)
annotate(*args, **kwargs) New in version 1.1: Please, see the release notes Annotates each object in the QuerySet with the provided list of aggregate values (averages, sums, etc) that have been computed over the objects that are related to the objects in the QuerySet. Each argument to annotate() is an annotation that will be added to each object in the QuerySet that is returned. The aggregation functions that are provided by Django are described in Aggregation Functions below. Annotations specied using keyword arguments will use the keyword as the alias for the annotation. Anonymous arguments will have an alias generated for them based upon the name of the aggregate function and the model eld that is being aggregated. For example, if you were manipulating a list of blogs, you may want to determine how many entries have been made in each blog:
>>> q = Blog.objects.annotate(Count(entry)) # The name of the first blog >>> q[0].name Blogasaurus # The number of entries on the first blog >>> q[0].entry__count 42
The Blog model doesnt dene an entry__count attribute by itself, but by using a keyword argument to specify the aggregate function, you can control the name of the annotation:
>>> q = Blog.objects.annotate(number_of_entries=Count(entry)) # The number of entries on the first blog, using the name provided >>> q[0].number_of_entries 42
order_by(*fields)
order_by(*elds) By default, results returned by a QuerySet are ordered by the ordering tuple given by the ordering option in the models Meta. You can override this on a per-QuerySet basis by using the order_by method. Example:
Entry.objects.filter(pub_date__year=2005).order_by(-pub_date, headline)
768
The result above will be ordered by pub_date descending, then by headline ascending. The negative sign in front of "-pub_date" indicates descending order. Ascending order is implied. To order randomly, use "?", like so:
Entry.objects.order_by(?)
Note: order_by(?) queries may be expensive and slow, depending on the database backend youre using. To order by a eld in a different model, use the same syntax as when you are querying across model relations. That is, the name of the eld, followed by a double underscore (__), followed by the name of the eld in the new model, and so on for as many models as you want to join. For example:
Entry.objects.order_by(blog__name, headline)
If you try to order by a eld that is a relation to another model, Django will use the default ordering on the related model (or order by the related models primary key if there is no Meta.ordering specied. For example:
Entry.objects.order_by(blog)
...since the Blog model has no default ordering specied. Be cautious when ordering by elds in related models if you are also using distinct(). See the note in the distinct() section for an explanation of how related model ordering can change the expected results. It is permissible to specify a multi-valued eld to order the results by (for example, a ManyToMany eld). Normally this wont be a sensible thing to do and its really an advanced usage feature. However, if you know that your querysets ltering or available data implies that there will only be one ordering piece of data for each of the main items you are selecting, the ordering may well be exactly what you want to do. Use ordering on multi-valued elds with care and make sure the results are what you expect. New in version 1.0: Please, see the release notes If you dont want any ordering to be applied to a query, not even the default ordering, call order_by() with no parameters. New in version 1.0: Please, see the release notes The syntax for ordering across related models has changed. See the Django 0.96 documentation for the old behaviour. Theres no way to specify whether ordering should be case sensitive. With respect to case-sensitivity, Django will order results however your database backend normally orders them. New in version 1.1: Please, see the release notes You can tell if a query is ordered or not by checking the QuerySet.ordered attribute, which will be True if the QuerySet has been ordered in any way.
reverse()
reverse() New in version 1.0: Please, see the release notes Use the reverse() method to reverse the order in which a querysets elements are returned. Calling reverse() a second time restores the ordering back to the normal direction. To retrieve the last ve items in a queryset, you could do this:
my_queryset.reverse()[:5]
769
Note that this is not quite the same as slicing from the end of a sequence in Python. The above example will return the last item rst, then the penultimate item and so on. If we had a Python sequence and looked at seq[-5:], we would see the fth-last item rst. Django doesnt support that mode of access (slicing from the end), because its not possible to do it efciently in SQL. Also, note that reverse() should generally only be called on a QuerySet which has a dened ordering (e.g., when querying against a model which denes a default ordering, or when using order_by()). If no such ordering is dened for a given QuerySet, calling reverse() on it has no real effect (the ordering was undened prior to calling reverse(), and will remain undened afterward).
distinct()
distinct() Returns a new QuerySet that uses SELECT DISTINCT in its SQL query. This eliminates duplicate rows from the query results. By default, a QuerySet will not eliminate duplicate rows. In practice, this is rarely a problem, because simple queries such as Blog.objects.all() dont introduce the possibility of duplicate result rows. However, if your query spans multiple tables, its possible to get duplicate results when a QuerySet is evaluated. Thats when youd use distinct(). Note: Any elds used in an order_by(*elds) call are included in the SQL SELECT columns. This can sometimes lead to unexpected results when used in conjunction with distinct(). If you order by elds from a related model, those elds will be added to the selected columns and they may make otherwise duplicate rows appear to be distinct. Since the extra columns dont appear in the returned results (they are only there to support ordering), it sometimes looks like non-distinct results are being returned. Similarly, if you use a values() query to restrict the columns selected, the columns used in any order_by() (or default model ordering) will still be involved and may affect uniqueness of the results. The moral here is that if you are using distinct() be careful about ordering by related models. Similarly, when using distinct() and values() together, be careful when ordering by elds not in the values() call.
values(*fields)
values(*elds) Returns a ValuesQuerySet a QuerySet that returns dictionaries when used as an iterable, rather than modelinstance objects. Each of those dictionaries represents an object, with the keys corresponding to the attribute names of model objects. This example compares the dictionaries of values() with the normal model objects:
# This list contains a Blog object. >>> Blog.objects.filter(name__startswith=Beatles) [<Blog: Beatles Blog>] # This list contains a dictionary. >>> Blog.objects.filter(name__startswith=Beatles).values() [{id: 1, name: Beatles Blog, tagline: All the latest Beatles news.}]
values() takes optional positional arguments, *fields, which specify eld names to which the SELECT should be limited. If you specify the elds, each dictionary will contain only the eld keys/values for the elds you specify. If you dont specify the elds, each dictionary will contain a key and value for every eld in the database table.
770
Example:
>>> Blog.objects.values() [{id: 1, name: Beatles Blog, tagline: All the latest Beatles news.}], >>> Blog.objects.values(id, name) [{id: 1, name: Beatles Blog}]
A couple of subtleties that are worth mentioning: The values() method does not return anything for ManyToManyField attributes and will raise an error if you try to pass in this type of eld to it. If you have a eld called foo that is a ForeignKey, the default values() call will return a dictionary key called foo_id, since this is the name of the hidden model attribute that stores the actual value (the foo attribute refers to the related model). When you are calling values() and passing in eld names, you can pass in either foo or foo_id and you will get back the same thing (the dictionary key will match the eld name you passed in). For example:
>>> Entry.objects.values() [{blog_id: 1, headline: uFirst Entry, ...}, ...] >>> Entry.objects.values(blog) [{blog: 1}, ...] >>> Entry.objects.values(blog_id) [{blog_id: 1}, ...]
When using values() together with distinct(), be aware that ordering can affect the results. See the note in the distinct() section, above, for details. If you use a values() clause after an extra() clause, any elds dened by a select argument in the extra() must be explicitly included in the values() clause. However, if the extra() clause is used after the values(), the elds added by the select will be included automatically. New in version 1.0: Please, see the release notes Previously, it was not possible to pass blog_id to values() in the above example, only blog. A ValuesQuerySet is useful when you know youre only going to need values from a small number of the available elds and you wont need the functionality of a model instance object. Its more efcient to select only the elds you need to use. Finally, note a ValuesQuerySet is a subclass of QuerySet, so it has all methods of QuerySet. You can call filter() on it, or order_by(), or whatever. Yes, that means these two calls are identical:
Blog.objects.values().order_by(id) Blog.objects.order_by(id).values()
The people who made Django prefer to put all the SQL-affecting methods rst, followed (optionally) by any outputaffecting methods (such as values()), but it doesnt really matter. This is your chance to really aunt your individualism.
values_list(*fields)
values_list(*elds)
771
New in version 1.0: Please, see the release notes This is similar to values() except that instead of returning dictionaries, it returns tuples when iterated over. Each tuple contains the value from the respective eld passed into the values_list() call so the rst item is the rst eld, etc. For example:
>>> Entry.objects.values_list(id, headline) [(1, uFirst entry), ...]
If you only pass in a single eld, you can also pass in the flat parameter. If True, this will mean the returned results are single values, rather than one-tuples. An example should make the difference clearer:
>>> Entry.objects.values_list(id).order_by(id) [(1,), (2,), (3,), ...] >>> Entry.objects.values_list(id, flat=True).order_by(id) [1, 2, 3, ...]
It is an error to pass in flat when there is more than one eld. If you dont pass any values to values_list(), it will return all the elds in the model, in the order they were declared.
772
none()
none() New in version 1.0: Please, see the release notes Returns an EmptyQuerySet a QuerySet that always evaluates to an empty list. This can be used in cases where you know that you should return an empty result set and your caller is expecting a QuerySet object (instead of returning an empty list, for example.) Examples:
>>> Entry.objects.none() []
all()
all() New in version 1.0: Please, see the release notes Returns a copy of the current QuerySet (or QuerySet subclass you pass in). This can be useful in some situations where you might want to pass in either a model manager or a QuerySet and do further ltering on the result. You can safely call all() on either object and then youll denitely have a QuerySet to work with.
select_related()
select_related() Returns a QuerySet that will automatically follow foreign-key relationships, selecting that additional relatedobject data when it executes its query. This is a performance booster which results in (sometimes much) larger queries but means later use of foreign-key relationships wont require database queries. The following examples illustrate the difference between plain lookups and select_related() lookups. Heres standard lookup:
# Hits the database. e = Entry.objects.get(id=5) # Hits the database again to get the related Blog object. b = e.blog
select_related() follows foreign keys as far as possible. If you have the following models:
class City(models.Model): # ... class Person(models.Model):
773
...then a call to Book.objects.select_related().get(id=4) will cache the related Person and the related City:
b = Book.objects.select_related().get(id=4) p = b.author # Doesnt hit the database. c = p.hometown # Doesnt hit the database. b = Book.objects.get(id=4) # No select_related() in this example. p = b.author # Hits the database. c = p.hometown # Hits the database.
Note that, by default, select_related() does not follow foreign keys that have null=True. Usually, using select_related() can vastly improve performance because your app can avoid many database calls. However, in situations with deeply nested sets of relationships select_related() can sometimes end up following too many relations, and can generate queries so large that they end up being slow. In these situations, you can use the depth argument to select_related() to control how many levels of relations select_related() will actually follow:
b = Book.objects.select_related(depth=1).get(id=4) p = b.author # Doesnt hit the database. c = p.hometown # Requires a database call.
Sometimes you only want to access specic models that are related to your root model, not all of the related models. In these cases, you can pass the related eld names to select_related() and it will only follow those relations. You can even do this for models that are more than one relation away by separating the eld names with double underscores, just as for lters. For example, if you have this model:
class Room(models.Model): # ... building = models.ForeignKey(...) class Group(models.Model): # ... teacher = models.ForeignKey(...) room = models.ForeignKey(Room) subject = models.ForeignKey(...)
...and you only needed to work with the room and subject attributes, you could write this:
g = Group.objects.select_related(room, subject)
774
You can refer to any ForeignKey or OneToOneField relation in the list of elds passed to select_related. Ths includes foreign keys that have null=True (unlike the default select_related() call). Its an error to use both a list of elds and the depth parameter in the same select_related() call, since they are conicting options. New in version 1.0: Please, see the release notes Both the depth argument and the ability to specify eld names in the call to select_related() are new in Django version 1.0. Changed in version 1.2: Please, see the release notes You can also refer to the reverse direction of a OneToOneFields in the list of elds passed to select_related that is, you can traverse a OneToOneField back to the object on which the eld is dened. Instead of specifying the eld name, use the related_name for the eld on the related object. OneToOneFields will not be traversed in the reverse direction if you are performing a depth-based select_related.
As a result, each Entry object will have an extra attribute, is_recent, a boolean representing whether the entrys pub_date is greater than Jan. 1, 2006. Django inserts the given SQL snippet directly into the SELECT statement, so the resulting SQL of the above example would be:
SELECT blog_entry.*, (pub_date > 2006-01-01) FROM blog_entry;
The next example is more advanced; it does a subquery to give each resulting Blog object an entry_count attribute, an integer count of associated Entry objects:
Blog.objects.extra( select={ entry_count: SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id }, )
(In this particular case, were exploiting the fact that the query will already contain the blog_blog table in its FROM clause.) The resulting SQL of the above example would be:
775
SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id) AS FROM blog_blog;
Note that the parenthesis required by most database engines around subqueries are not required in Djangos select clauses. Also note that some database backends, such as some MySQL versions, dont support subqueries. New in version 1.0: Please, see the release notes In some rare cases, you might wish to pass parameters to the SQL fragments in extra(select=...). For this purpose, use the select_params parameter. Since select_params is a sequence and the select attribute is a dictionary, some care is required so that the parameters are matched up correctly with the extra select pieces. In this situation, you should use a django.utils.datastructures.SortedDict for the select value, not just a normal Python dictionary. This will work, for example:
Blog.objects.extra( select=SortedDict([(a, %s), (b, %s)]), select_params=(one, two))
The only thing to be careful about when using select parameters in extra() is to avoid using the substring "%%s" (thats two percent characters before the s) in the select strings. Djangos tracking of parameters looks for %s and an escaped % character like this isnt detected. That will lead to incorrect results. where / tables You can dene explicit SQL WHERE clauses perhaps to perform non-explicit joins by using where. You can manually add tables to the SQL FROM clause by using tables. where and tables both take a list of strings. All where parameters are ANDed to any other search criteria. Example:
Entry.objects.extra(where=[id IN (3, 4, 5, 20)])
Be careful when using the tables parameter if youre specifying tables that are already used in the query. When you add extra tables via the tables parameter, Django assumes you want that table included an extra time, if it is already included. That creates a problem, since the table name will then be given an alias. If a table appears multiple times in an SQL statement, the second and subsequent occurrences must use aliases so the database can tell them apart. If youre referring to the extra table you added in the extra where parameter this is going to cause errors. Normally youll only be adding extra tables that dont already appear in the query. However, if the case outlined above does occur, there are a few solutions. First, see if you can get by without including the extra table and use the one already in the query. If that isnt possible, put your extra() call at the front of the queryset construction so that your table is the rst use of that table. Finally, if all else fails, look at the query produced and rewrite your where addition to use the alias given to your extra table. The alias will be the same each time you construct the queryset in the same way, so you can rely upon the alias name to not change. order_by If you need to order the resulting queryset using some of the new elds or tables you have included via extra() use the order_by parameter to extra() and pass in a sequence of strings. These strings should either be model elds (as in the normal order_by() method on querysets), of the form table_name.column_name or an alias for a column that you specied in the select parameter to extra(). For example:
776
This would sort all the items for which is_recent is true to the front of the result set (True sorts before False in a descending ordering). This shows, by the way, that you can make multiple calls to extra() and it will behave as you expect (adding new constraints each time). params The where parameter described above may use standard Python database string placeholders %s to indicate parameters the database engine should automatically quote. The params argument is a list of any extra parameters to be substituted. Example:
Entry.objects.extra(where=[headline=%s], params=[Lennon])
Always use params instead of embedding values directly into where because params will ensure values are quoted correctly according to your particular backend. (For example, quotes will be escaped correctly.) Bad:
Entry.objects.extra(where=["headline=Lennon"])
Good:
Entry.objects.extra(where=[headline=%s], params=[Lennon])
defer(*fields)
defer(*elds) New in version 1.1: Please, see the release notes In some complex data-modeling situations, your models might contain a lot of elds, some of which could contain a lot of data (for example, text elds), or require expensive processing to convert them to Python objects. If you are using the results of a queryset in some situation where you know you dont need those particular elds, you can tell Django not to retrieve them from the database. This is done by passing the names of the elds to not load to defer():
Entry.objects.defer("headline", "body")
A queryset that has deferred elds will still return model instances. Each deferred eld will be retrieved from the database if you access that eld (one at a time, not all the deferred elds at once). You can make multiple calls to defer(). Each call adds new elds to the deferred set:
# Defers both the body and lede fields. Entry.objects.defer("body").filter(rating=5).defer("headline")
The order in which elds are added to the deferred set does not matter. Calling defer() with a eld name that has already been deferred is harmless (the eld will still be deferred). You can defer loading of elds in related models (if the related models are loading via select_related()) by using the standard double-underscore notation to separate related elds:
777
Blog.objects.select_related().defer("entry__headline", "entry__body")
If you want to clear the set of deferred elds, pass None as a parameter to defer():
# Load all fields immediately. my_queryset.defer(None)
Some elds in a model wont be deferred, even if you ask for them. You can never defer the loading of the primary key. If you are using select_related() to retrieve other models at the same time you shouldnt defer the loading of the eld that connects from the primary model to the related one (at the moment, that doesnt raise an error, but it will eventually). Note: The defer() method (and its cousin, only(), below) are only for advanced use-cases. They provide an optimization for when you have analyzed your queries closely and understand exactly what information you need and have measured that the difference between returning the elds you need and the full set of elds for the model will be signicant. When you are initially developing your applications, dont bother using defer(); leave it until your query construction has settled down and you understand where the hot-points are.
only(*fields)
only(*elds) New in version 1.1: Please, see the release notes The only() method is more or less the opposite of defer(). You call it with the elds that should not be deferred when retrieving a model. If you have a model where almost all the elds need to be deferred, using only() to specify the complementary set of elds could result in simpler code. If you have a model with elds name, age and biography, the following two querysets are the same, in terms of deferred elds:
Person.objects.defer("age", "biography") Person.objects.only("name")
Whenever you call only() it replaces the set of elds to load immediately. The methods name is mnemonic: only those elds are loaded immediately; the remainder are deferred. Thus, successive calls to only() result in only the nal elds being considered:
# This will defer all fields except the headline. Entry.objects.only("body", "lede").only("headline")
Since defer() acts incrementally (adding elds to the deferred list), you can combine calls to only() and defer() and things will behave logically:
# Final result is that everything except "headline" is deferred. Entry.objects.only("headline", "body").defer("body") # Final result loads headline and body immediately (only() replaces any # existing set of fields). Entry.objects.defer("body").only("headline", "body")
using(alias)
using(alias)
778
New in version 1.2: Please, see the release notes This method is for controlling which database the QuerySet will be evaluated against if you are using more than one database. The only argument this method takes is the alias of a database, as dened in DATABASES. For example:
# queries the database with the default alias. >>> Entry.objects.all() # queries the database with the backup alias >>> Entry.objects.using(backup)
QuerySet methods that do not return QuerySets The following QuerySet methods evaluate the QuerySet and return something other than a QuerySet. These methods do not use a cache (see Caching and QuerySets). Rather, they query the database each time theyre called.
get(**kwargs)
get(**kwargs) Returns the object matching the given lookup parameters, which should be in the format described in Field lookups. get() raises MultipleObjectsReturned if more than one MultipleObjectsReturned exception is an attribute of the model class. object was found. The
get() raises a DoesNotExist exception if an object wasnt found for the given parameters. This exception is also an attribute of the model class. Example:
Entry.objects.get(id=foo) # raises Entry.DoesNotExist
The DoesNotExist exception inherits from django.core.exceptions.ObjectDoesNotExist, so you can target multiple DoesNotExist exceptions. Example:
from django.core.exceptions import ObjectDoesNotExist try: e = Entry.objects.get(id=3) b = Blog.objects.get(id=1) except ObjectDoesNotExist: print "Either the entry or blog doesnt exist."
create(**kwargs)
create(**kwargs) A convenience method for creating an object and saving it all in one step. Thus:
p = Person.objects.create(first_name="Bruce", last_name="Springsteen")
and:
779
are equivalent. The force_insert parameter is documented elsewhere, but all it means is that a new object will always be created. Normally you wont need to worry about this. However, if your model contains a manual primary key value that you set and if that value already exists in the database, a call to create() will fail with an IntegrityError since primary keys must be unique. So remember to be prepared to handle the exception if you are using manual primary keys.
get_or_create(**kwargs)
get_or_create(**kwargs) A convenience method for looking up an object with the given kwargs, creating one if necessary. Returns a tuple of (object, created), where object is the retrieved or created object and created is a boolean specifying whether a new object was created. This is meant as a shortcut to boilerplatish code and is mostly useful for data-import scripts. For example:
try: obj = Person.objects.get(first_name=John, last_name=Lennon) except Person.DoesNotExist: obj = Person(first_name=John, last_name=Lennon, birthday=date(1940, 10, 9)) obj.save()
This pattern gets quite unwieldy as the number of elds in a model goes up. The above example can be rewritten using get_or_create() like so:
obj, created = Person.objects.get_or_create(first_name=John, last_name=Lennon, defaults={birthday: date(1940, 10, 9)})
Any keyword arguments passed to get_or_create() except an optional one called defaults will be used in a get() call. If an object is found, get_or_create() returns a tuple of that object and False. If an object is not found, get_or_create() will instantiate and save a new object, returning a tuple of the new object and True. The new object will be created roughly according to this algorithm:
defaults = kwargs.pop(defaults, {}) params = dict([(k, v) for k, v in kwargs.items() if __ not in k]) params.update(defaults) obj = self.model(**params) obj.save()
In English, that means start with any non-defaults keyword argument that doesnt contain a double underscore (which would indicate a non-exact lookup). Then add the contents of defaults, overriding any keys if necessary, and use the result as the keyword arguments to the model class. As hinted at above, this is a simplication of the algorithm that is used, but it contains all the pertinent details. The internal implementation has some more errorchecking than this and handles some extra edge-conditions; if youre interested, read the code. If you have a eld named defaults and want to use it as an exact lookup in get_or_create(), just use defaults__exact, like so:
Foo.objects.get_or_create(defaults__exact=bar, defaults={defaults: baz})
780
The get_or_create() method has similar error behaviour to create() when you are using manually specied primary keys. If an object needs to be created and the key already exists in the database, an IntegrityError will be raised. Finally, a word on using get_or_create() in Django views. As mentioned earlier, get_or_create() is mostly useful in scripts that need to parse data and create new records if existing ones arent available. But if you need to use get_or_create() in a view, please make sure to use it only in POST requests unless you have a good reason not to. GET requests shouldnt have any effect on data; use POST whenever a request to a page has a side effect on your data. For more, see Safe methods in the HTTP spec.
count()
count() Returns an integer representing the number of objects in the database matching the QuerySet. count() never raises exceptions. Example:
# Returns the total number of entries in the database. Entry.objects.count() # Returns the number of entries whose headline contains Lennon Entry.objects.filter(headline__contains=Lennon).count()
count() performs a SELECT COUNT(*) behind the scenes, so you should always use count() rather than loading all of the record into Python objects and calling len() on the result (unless you need to load the objects into memory anyway, in which case len() will be faster). Depending on which database youre using (e.g. PostgreSQL vs. MySQL), count() may return a long integer instead of a normal Python integer. This is an underlying implementation quirk that shouldnt pose any real-world problems.
in_bulk(id_list)
in_bulk(id_list) Takes a list of primary-key values and returns a dictionary mapping each primary-key value to an instance of the object with the given ID. Example:
>>> {1: >>> {1: >>> {} Blog.objects.in_bulk([1]) <Blog: Beatles Blog>} Blog.objects.in_bulk([1, 2]) <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>} Blog.objects.in_bulk([])
iterator()
iterator()
781
Evaluates the QuerySet (by performing the query) and returns an iterator over the results. A QuerySet typically caches its results internally so that repeated evaluations do not result in additional queries; iterator() will instead read results directly, without doing any caching at the QuerySet level. For a QuerySet which returns a large number of objects, this often results in better performance and a signicant reduction in memory Note that using iterator() on a QuerySet which has already been evaluated will force it to evaluate again, repeating the query.
latest(field_name=None)
latest(eld_name=None) Returns the latest object in the table, by date, using the field_name provided as the date eld. This example returns the latest Entry in the table, according to the pub_date eld:
Entry.objects.latest(pub_date)
If your models Meta species get_latest_by, you can leave off the field_name argument to latest(). Django will use the eld specied in get_latest_by by default. Like get(), latest() raises DoesNotExist if an object doesnt exist with the given parameters. Note latest() exists purely for convenience and readability.
aggregate(*args, **kwargs)
aggregate(*args, **kwargs) New in version 1.1: Please, see the release notes Returns a dictionary of aggregate values (averages, sums, etc) calculated over the QuerySet. Each argument to aggregate() species a value that will be included in the dictionary that is returned. The aggregation functions that are provided by Django are described in Aggregation Functions below. Aggregates specied using keyword arguments will use the keyword as the name for the annotation. Anonymous arguments will have an name generated for them based upon the name of the aggregate function and the model eld that is being aggregated. For example, if you were manipulating blog entries, you may want to know the number of authors that have contributed blog entries:
>>> q = Blog.objects.aggregate(Count(entry)) {entry__count: 16}
By using a keyword argument to specify the aggregate function, you can control the name of the aggregation value that is returned:
>>> q = Blog.objects.aggregate(number_of_entries=Count(entry)) {number_of_entries: 16}
782
exists()
exists() New in version 1.2: Please, see the release notes Returns True if the QuerySet contains any results, and False if not. This tries to perform the query in the simplest and fastest way possible, but it does execute nearly the same query. This means that calling QuerySet.exists() is faster than bool(some_query_set), but not by a large degree. If some_query_set has not yet been evaluated, but you know that it will be at some point, then using some_query_set.exists() will do more overall work (an additional query) than simply using bool(some_query_set). Field lookups Field lookups are how you specify the meat of an SQL WHERE clause. Theyre specied as keyword arguments to the QuerySet methods filter(), exclude() and get(). For an introduction, see Field lookups.
exact
Exact match. If the value provided for comparison is None, it will be interpreted as an SQL NULL (See isnull for more details). Examples:
Entry.objects.get(id__exact=14) Entry.objects.get(id__exact=None)
SQL equivalents:
SELECT ... WHERE id = 14; SELECT ... WHERE id IS NULL;
Changed in version 1.0: The semantics of id__exact=None have changed in Django 1.0. Previously, it was (intentionally) converted to WHERE id = NULL at the SQL level, which would never match anything. It has now been changed to behave the same as id__isnull=True. MySQL comparisons In MySQL, a database tables collation setting determines whether exact comparisons are case-sensitive. This is a database setting, not a Django setting. Its possible to congure your MySQL tables to use case-sensitive comparisons, but some trade-offs are involved. For more information about this, see the collation section in the databases documentation.
iexact
Case-insensitive exact match. Example:
Blog.objects.get(name__iexact=beatles blog)
SQL equivalent:
783
Note this will match Beatles Blog, beatles blog, BeAtLes BLoG, etc. SQLite users When using the SQLite backend and Unicode (non-ASCII) strings, bear in mind the database note about string comparisons. SQLite does not do case-insensitive matching for Unicode strings.
contains
Case-sensitive containment test. Example:
Entry.objects.get(headline__contains=Lennon)
SQL equivalent:
SELECT ... WHERE headline LIKE %Lennon%;
Note this will match the headline Today Lennon honored but not today lennon honored. SQLite doesnt support case-sensitive LIKE statements; contains acts like icontains for SQLite.
icontains
Case-insensitive containment test. Example:
Entry.objects.get(headline__icontains=Lennon)
SQL equivalent:
SELECT ... WHERE headline ILIKE %Lennon%;
SQLite users When using the SQLite backend and Unicode (non-ASCII) strings, bear in mind the database note about string comparisons.
in
In a given list. Example:
Entry.objects.filter(id__in=[1, 3, 4])
SQL equivalent:
SELECT ... WHERE id IN (1, 3, 4);
784
You can also use a queryset to dynamically evaluate the list of values instead of providing a list of literal values:
inner_qs = Blog.objects.filter(name__contains=Cheddar) entries = Entry.objects.filter(blog__in=inner_qs)
Changed in version 1.1: In Django 1.0, only the latter piece of code is valid. This second form is a bit less readable and unnatural to write, since it accesses the internal query attribute and requires a ValuesQuerySet. If your code doesnt require compatibility with Django 1.0, use the rst form, passing in a queryset directly. If you pass in a ValuesQuerySet or ValuesListQuerySet (the result of calling values() or values_list() on a queryset) as the value to an __in lookup, you need to ensure you are only extracting one eld in the result. For example, this will work (ltering on the blog names):
inner_qs = Blog.objects.filter(name__contains=Ch).values(name) entries = Entry.objects.filter(blog__name__in=inner_qs)
This example will raise an exception, since the inner query is trying to extract two eld values, where only one is expected:
# Bad code! Will raise a TypeError. inner_qs = Blog.objects.filter(name__contains=Ch).values(name, id) entries = Entry.objects.filter(blog__name__in=inner_qs)
Warning: This query attribute should be considered an opaque internal attribute. Its ne to use it like above, but its API may change between Django versions. Performance considerations Be cautious about using nested queries and understand your database servers performance characteristics (if in doubt, benchmark!). Some database backends, most notably MySQL, dont optimize nested queries very well. It is more efcient, in those cases, to extract a list of values and then pass that into the second query. That is, execute two queries instead of one:
values = Blog.objects.filter( name__contains=Cheddar).values_list(pk, flat=True) entries = Entry.objects.filter(blog__in=list(values))
Note the list() call around the Blog QuerySet to force execution of the rst query. Without it, a nested query would be executed, because QuerySets are lazy.
gt
Greater than. Example:
785
Entry.objects.filter(id__gt=4)
SQL equivalent:
SELECT ... WHERE id > 4;
gte
Greater than or equal to.
lt
Less than.
lte
Less than or equal to.
startswith
Case-sensitive starts-with. Example:
Entry.objects.filter(headline__startswith=Will)
SQL equivalent:
SELECT ... WHERE headline LIKE Will%;
SQLite doesnt support case-sensitive LIKE statements; startswith acts like istartswith for SQLite.
istartswith
Case-insensitive starts-with. Example:
Entry.objects.filter(headline__istartswith=will)
SQL equivalent:
SELECT ... WHERE headline ILIKE Will%;
SQLite users When using the SQLite backend and Unicode (non-ASCII) strings, bear in mind the database note about string comparisons.
786
endswith
Case-sensitive ends-with. Example:
Entry.objects.filter(headline__endswith=cats)
SQL equivalent:
SELECT ... WHERE headline LIKE %cats;
SQLite doesnt support case-sensitive LIKE statements; endswith acts like iendswith for SQLite.
iendswith
Case-insensitive ends-with. Example:
Entry.objects.filter(headline__iendswith=will)
SQL equivalent:
SELECT ... WHERE headline ILIKE %will
SQLite users When using the SQLite backend and Unicode (non-ASCII) strings, bear in mind the database note about string comparisons.
range
Range test (inclusive). Example:
start_date = datetime.date(2005, 1, 1) end_date = datetime.date(2005, 3, 31) Entry.objects.filter(pub_date__range=(start_date, end_date))
SQL equivalent:
SELECT ... WHERE pub_date BETWEEN 2005-01-01 and 2005-03-31;
You can use range anywhere you can use BETWEEN in SQL for dates, numbers and even characters.
787
year
For date/datetime elds, exact year match. Takes a four-digit year. Example:
Entry.objects.filter(pub_date__year=2005)
SQL equivalent:
SELECT ... WHERE EXTRACT(year FROM pub_date) = 2005;
month
For date/datetime elds, exact month match. Takes an integer 1 (January) through 12 (December). Example:
Entry.objects.filter(pub_date__month=12)
SQL equivalent:
SELECT ... WHERE EXTRACT(month FROM pub_date) = 12;
day
For date/datetime elds, exact day match. Example:
Entry.objects.filter(pub_date__day=3)
SQL equivalent:
SELECT ... WHERE EXTRACT(day FROM pub_date) = 3;
(The exact SQL syntax varies for each database engine.) Note this will match any record with a pub_date on the third day of the month, such as January 3, July 3, etc.
week_day
New in version 1.1: Please, see the release notes For date/datetime elds, a day of the week match. Takes an integer value representing the day of week from 1 (Sunday) to 7 (Saturday). Example:
Entry.objects.filter(pub_date__week_day=2)
788
(No equivalent SQL code fragment is included for this lookup because implementation of the relevant query varies among different database engines.) Note this will match any record with a pub_date that falls on a Monday (day 2 of the week), regardless of the month or year in which it occurs. Week days are indexed with day 1 being Sunday and day 7 being Saturday.
isnull
Takes either True or False, which correspond to SQL queries of IS NULL and IS NOT NULL, respectively. Example:
Entry.objects.filter(pub_date__isnull=True)
SQL equivalent:
SELECT ... WHERE pub_date IS NULL;
search
A boolean full-text search, taking advantage of full-text indexing. This is like contains but is signicantly faster due to full-text indexing. Example:
Entry.objects.filter(headline__search="+Django -jazz Python")
SQL equivalent:
SELECT ... WHERE MATCH(tablename, headline) AGAINST (+Django -jazz Python IN BOOLEAN MODE);
Note this is only available in MySQL and requires direct manipulation of the database to add the full-text index. By default Django uses BOOLEAN MODE for full text searches. Please check MySQL documentation for additional details.
regex
New in version 1.0: Please, see the release notes Case-sensitive regular expression match. The regular expression syntax is that of the database backend in use. In the case of SQLite, which has no built in regular expression support, this feature is provided by a (Python) user-dened REGEXP function, and the regular expression syntax is therefore that of Pythons re module. Example:
Entry.objects.get(title__regex=r^(An?|The) +)
SQL equivalents:
789
SELECT ... WHERE title REGEXP BINARY ^(An?|The) +; -- MySQL SELECT ... WHERE REGEXP_LIKE(title, ^(an?|the) +, c); -- Oracle SELECT ... WHERE title ~ ^(An?|The) +; -- PostgreSQL SELECT ... WHERE title REGEXP ^(An?|The) +; -- SQLite
Using raw strings (e.g., rfoo instead of foo) for passing in the regular expression syntax is recommended.
iregex
New in version 1.0: Please, see the release notes Case-insensitive regular expression match. Example:
Entry.objects.get(title__iregex=r^(an?|the) +)
SQL equivalents:
SELECT ... WHERE title REGEXP ^(an?|the) +; -- MySQL SELECT ... WHERE REGEXP_LIKE(title, ^(an?|the) +, i); -- Oracle SELECT ... WHERE title ~* ^(an?|the) +; -- PostgreSQL SELECT ... WHERE title REGEXP (?i)^(an?|the) +; -- SQLite
Aggregation Functions New in version 1.1: Please, see the release notes Django provides the following aggregation functions in the django.db.models module. For details on how to use these aggregate functions, see the topic guide on aggregation.
Avg
class Avg(eld) Returns the mean value of the given eld. Default alias: <field>__avg Return type: oat
Count
class Count(eld, distinct=False) Returns the number of objects that are related through the provided eld. Default alias: <field>__count Return type: integer
790
Has one optional argument: distinct If distinct=True, the count will only include unique instances. COUNT(DISTINCT field). Default value is False. This has the SQL equivalent of
Max
class Max(eld) Returns the maximum value of the given eld. Default alias: <field>__max Return type: same as input eld
Min
class Min(eld) Returns the minimum value of the given eld. Default alias: <field>__min Return type: same as input eld
StdDev
class StdDev(eld, sample=False) Returns the standard deviation of the data in the provided eld. Default alias: <field>__stddev Return type: oat Has one optional argument: sample By default, StdDev returns the population standard deviation. However, if sample=True, the return value will be the sample standard deviation. SQLite SQLite doesnt provide StdDev out of the box. An implementation is available as an extension module for SQLite. Consult the SQlite documentation for instructions on obtaining and installing this extension.
Sum
class Sum(eld) Computes the sum of all values of the given eld. Default alias: <field>__sum Return type: same as input eld
791
Variance
class Variance(eld, sample=False) Returns the variance of the data in the provided eld. Default alias: <field>__variance Return type: oat Has one optional argument: sample By default, Variance returns the population variance. However, if sample=True, the return value will be the sample variance. SQLite SQLite doesnt provide Variance out of the box. An implementation is available as an extension module for SQLite. Consult the SQlite documentation for instructions on obtaining and installing this extension.
792
CHAPTER
FIFTYEIGHT
58.2.1 Attributes
All attributes except session should be considered read-only. path A string representing the full path to the requested page, not including the domain. Example: "/music/bands/the_beatles/" method A string representing the HTTP method used in the request. This is guaranteed to be uppercase. Example:
if request.method == GET: do_something() elif request.method == POST: do_something_else()
encoding New in version 1.0: Please, see the release notes A string representing the current encoding used to decode form submission data (or None, which means the DEFAULT_CHARSET setting is used). You can write to this attribute to change the encoding used when accessing the form data. Any subsequent attribute accesses (such as reading from GET or POST) will use the new encoding value. Useful if you know the form data is not in the DEFAULT_CHARSET encoding.
793
GET A dictionary-like object containing all given HTTP GET parameters. See the QueryDict documentation below. POST A dictionary-like object containing all given HTTP POST parameters. See the QueryDict documentation below. Its possible that a request can come in via POST with an empty POST dictionary if, say, a form is requested via the POST HTTP method but does not include form data. Therefore, you shouldnt use if request.POST to check for use of the POST method; instead, use if request.method == "POST" (see above). Note: POST does not include le-upload information. See FILES. REQUEST For convenience, a dictionary-like object that searches POST rst, then GET. Inspired by PHPs $_REQUEST. For example, if GET = {"name": "john"} and POST = {"age": would be "john", and REQUEST["age"] would be "34". 34}, REQUEST["name"]
Its strongly suggested that you use GET and POST instead of REQUEST, because the former are more explicit. COOKIES A standard Python dictionary containing all cookies. Keys and values are strings. FILES A dictionary-like object containing all uploaded les. Each key in FILES is the name from the <input type="file" name="" />. Each value in FILES is an UploadedFile object containing the following attributes: read(num_bytes=None) Read a number of bytes from the le. name The name of the uploaded le. size The size, in bytes, of the uploaded le. chunks(chunk_size=None) A generator that yields sequential chunks of data. See Managing les for more information. Note that FILES will only contain data if the request method was POST and the <form> that posted to the request had enctype="multipart/form-data". Otherwise, FILES will be a blank dictionary-like object. Changed in version 1.0: Please, see the release notes In previous versions of Django, request.FILES contained simple dict objects representing uploaded les. This is no longer true les are represented by UploadedFile objects as described below. These UploadedFile objects will emulate the old-style dict interface, but this is deprecated and will be removed in the next release of Django. META A standard Python dictionary containing all available HTTP headers. Available headers depend on the client and server, but here are some examples: CONTENT_LENGTH CONTENT_TYPE HTTP_ACCEPT_ENCODING HTTP_ACCEPT_LANGUAGE HTTP_HOST The HTTP Host header sent by the client. HTTP_REFERER The referring page, if any.
794
HTTP_USER_AGENT The clients user-agent string. QUERY_STRING The query string, as a single (unparsed) string. REMOTE_ADDR The IP address of the client. REMOTE_HOST The hostname of the client. REMOTE_USER The user authenticated by the web server, if any. REQUEST_METHOD A string such as "GET" or "POST". SERVER_NAME The hostname of the server. SERVER_PORT The port of the server. With the exception of CONTENT_LENGTH and CONTENT_TYPE, as given above, any HTTP headers in the request are converted to META keys by converting all characters to uppercase, replacing any hyphens with underscores and adding an HTTP_ prex to the name. So, for example, a header called X-Bender would be mapped to the META key HTTP_X_BENDER. user A django.contrib.auth.models.User object representing the currently loggedin user. If the user isnt currently logged in, user will be set to an instance of django.contrib.auth.models.AnonymousUser. You can tell them apart with is_authenticated(), like so:
if request.user.is_authenticated(): # Do something for logged-in users. else: # Do something for anonymous users.
user is only available if your Django installation has the AuthenticationMiddleware activated. For more, see User authentication in Django. session A readable-and-writable, dictionary-like object that represents the current session. This is only available if your Django installation has session support activated. See the session documentation for full details. raw_post_data The raw HTTP POST data. This is only useful for advanced processing. Use POST instead. urlconf Not dened by Django itself, but will be read if other code (e.g., a custom middleware class) sets it. When present, this will be used as the root URLconf for the current request, overriding the ROOT_URLCONF setting. See How Django processes a request for details.
58.2.2 Methods
get_host() New in version 1.0: Please, see the release notes Returns the originating host of the request using information from the HTTP_X_FORWARDED_HOST and HTTP_HOST headers (in that order). If they dont provide a value, the method uses a combination of SERVER_NAME and SERVER_PORT as detailed in PEP 333. Example: "127.0.0.1:8000" get_full_path() Returns the path, plus an appended query string, if applicable. Example: "/music/bands/the_beatles/?print=true"
795
build_absolute_uri(location) New in version 1.0: Please, see the release notes Returns the absolute URI form of location. If no location is provided, the location will be set to request.get_full_path(). If the location is already an absolute URI, it will not be altered. Otherwise the absolute URI is built using the server variables available in this request. Example: "http://example.com/music/bands/the_beatles/?print=true" is_secure() Returns True if the request is secure; that is, if it was made with HTTPS. is_ajax() New in version 1.0: Please, see the release notes Returns True if the request was made via an XMLHttpRequest, by checking the HTTP_X_REQUESTED_WITH header for the string XMLHttpRequest. Most modern JavaScript libraries send this header. If you write your own XMLHttpRequest call (on the browser side), youll have to set this header manually if you want is_ajax() to work.
58.2.4 Methods
QueryDict implements all the standard dictionary methods, because its a subclass of dictionary. Exceptions are outlined here: __getitem__(key) Returns the value for the given key. If the key has more than one value, __getitem__() returns the last value. Raises django.utils.datastructures.MultiValueDictKeyError if the key does not exist. (This is a subclass of Pythons standard KeyError, so you can stick to catching KeyError.) __setitem__(key, value) Sets the given key to [value] (a Python list whose single element is value). Note that this, as other dictionary functions that have side effects, can only be called on a mutable QueryDict (one that was created via copy()). __contains__(key) Returns True if the given key is set. This lets you do, e.g., if "foo" in request.GET. get(key, default) Uses the same logic as __getitem__() above, with a hook for returning a default value if the key doesnt exist. setdefault(key, default) Just like the standard dictionary setdefault() method, except it uses __setitem__ internally.
796
update(other_dict) Takes either a QueryDict or standard dictionary. Just like the standard dictionary update() method, except it appends to the current dictionary items rather than replacing them. For example:
>>> q = QueryDict(a=1) >>> q = q.copy() # to make it mutable >>> q.update({a: 2}) >>> q.getlist(a) [u1, u2] >>> q[a] # returns the last [u2]
items() Just like the standard dictionary items() method, except this uses the same last-value logic as __getitem()__. For example:
>>> q = QueryDict(a=1&a=2&a=3) >>> q.items() [(ua, u3)]
iteritems() Just like the standard dictionary iteritems() method. Like QueryDict.items() this uses the same last-value logic as QueryDict.__getitem()__(). iterlists() Like QueryDict.iteritems() except it includes all values, as a list, for each member of the dictionary. values() Just like the standard dictionary values() method, except this uses the same last-value logic as __getitem()__. For example:
>>> q = QueryDict(a=1&a=2&a=3) >>> q.values() [u3]
itervalues() Just like QueryDict.values(), except an iterator. In addition, QueryDict has the following methods: copy() Returns a copy of the object, using copy.deepcopy() from the Python standard library. The copy will be mutable that is, you can change its values. getlist(key) Returns the data with the requested key, as a Python list. Returns an empty list if the key doesnt exist. Its guaranteed to return a list of some sort. setlist(key, list_) Sets the given key to list_ (unlike __setitem__()). appendlist(key, item) Appends an item to the internal list associated with key. setlistdefault(key, default_list) Just like setdefault, except it takes a list of values instead of a single value. lists() Like items(), except it includes all values, as a list, for each member of the dictionary. For example:
797
58.3.1 Usage
Passing strings Typical usage is to pass the contents of the page, as a string, to the HttpResponse constructor:
>>> response = HttpResponse("Heres the text of the Web page.") >>> response = HttpResponse("Text only, please.", mimetype="text/plain")
But if you want to add content incrementally, you can use response as a le-like object:
>>> response = HttpResponse() >>> response.write("<p>Heres the text of the Web page.</p>") >>> response.write("<p>Heres another paragraph.</p>")
Note that del doesnt raise KeyError if the header doesnt exist. Passing iterators Finally, you can pass HttpResponse an iterator rather than passing it hard-coded strings. If you use this technique, follow these guidelines: The iterator should return strings. If an HttpResponse has been initialized with an iterator as its content, you cant use the class:HttpResponse instance as a le-like object. Doing so will raise Exception.
798
Setting headers To set a header in your response, just treat it like a dictionary:
>>> response = HttpResponse() >>> response[Cache-Control] = no-cache
New in version 1.1: Please, see the release notes HTTP headers cannot contain newlines. An attempt to set a header containing a newline character (CR or LF) will raise BadHeaderError Telling the browser to treat the response as a le attachment To tell the browser to treat the response as a le attachment, use the mimetype argument and set the Content-Disposition header. For example, this is how you might return a Microsoft Excel spreadsheet:
>>> response = HttpResponse(my_data, mimetype=application/vnd.ms-excel) >>> response[Content-Disposition] = attachment; filename=foo.xls
Theres nothing Django-specic about the Content-Disposition header, but its easy to forget the syntax, so weve included it here.
58.3.2 Attributes
content A normal Python string representing the content, encoded from a Unicode object if necessary. status_code The HTTP Status code for the response.
58.3.3 Methods
__init__(content=, mimetype=None, status=200, content_type=DEFAULT_CONTENT_TYPE) Instantiates an HttpResponse object with the given page content (a string) and MIME type. DEFAULT_CONTENT_TYPE is text/html. The
content can be an iterator or a string. If its an iterator, it should return strings, and those strings will be joined together to form the content of the response. status is the HTTP Status code for the response. New in version 1.0: Please, see the release notes content_type is an alias for mimetype. Historically, this parameter was only called mimetype, but since this is actually the value included in the HTTP Content-Type header, it can also include the character set encoding, which makes it more than just a MIME type specication. If mimetype is specied (not None), that value is used. Otherwise, content_type is used. If neither is given, the DEFAULT_CONTENT_TYPE setting is used. __setitem__(header, value) Sets the given header name to the given value. Both header and value should be strings. __delitem__(header) Deletes the header with the given name. Fails silently if the header doesnt exist. Case-sensitive. __getitem__(header) Returns the value for the given header name. Case-sensitive.
799
has_header(header) Returns True or False based on a case-insensitive check for a header with the given name. set_cookie(key, value=, max_age=None, expires=None, path=/, domain=None, secure=None) Sets a cookie. The parameters are the same as in the cookie Morsel object in the Python standard library. max_age should be a number of seconds, or None (default) if the cookie should last only as long as the clients browser session. expires should be a string in the format "Wdy, DD-Mon-YY HH:MM:SS GMT". Use domain if you want to set a cross-domain cookie. For example, domain=".lawrence.com" will set a cookie that is readable by the domains www.lawrence.com, blogs.lawrence.com and calendars.lawrence.com. Otherwise, a cookie will only be readable by the domain that set it. delete_cookie(key, path=/, domain=None) Deletes the cookie with the given key. Fails silently if the key doesnt exist. Due to the way cookies work, path and domain should be the same values you used in set_cookie() otherwise the cookie may not be deleted. write(content) This method makes an HttpResponse instance a le-like object. flush() This method makes an HttpResponse instance a le-like object. tell() This method makes an HttpResponse instance a le-like object.
800
class HttpResponseGone() Acts just like HttpResponse but uses a 410 status code. class HttpResponseServerError() Acts just like HttpResponse but uses a 500 status code.
801
802
CHAPTER
FIFTYNINE
SETTINGS
Available settings Deprecated settings
59.1.1 ABSOLUTE_URL_OVERRIDES
Default: {} (Empty dictionary) A dictionary mapping "app_label.model_name" strings to functions that take a model object and return its URL. This is a way of overriding get_absolute_url() methods on a per-installation basis. Example:
ABSOLUTE_URL_OVERRIDES = { blogs.weblog: lambda o: "/blogs/%s/" % o.slug, news.story: lambda o: "/stories/%s/%s/" % (o.pub_year, o.slug), }
Note that the model name used in this setting should be all lower-case, regardless of the case of the actual model class name.
59.1.2 ADMIN_FOR
Default: () (Empty tuple) Used for admin-site settings modules, this should be a tuple of settings modules (in the format foo.bar.baz) for which this site is an admin. The admin site uses this in its automatically-introspected documentation of models, views and template tags.
59.1.3 ADMIN_MEDIA_PREFIX
Default: /media/
803
The URL prex for admin media CSS, JavaScript and images used by the Django administrative interface. Make sure to use a trailing slash, and to have this be different from the MEDIA_URL setting (since the same URL cannot be mapped onto two different sets of les).
59.1.4 ADMINS
Default: () (Empty tuple) A tuple that lists people who get code error notications. When DEBUG=False and a view raises an exception, Django will e-mail these people with the full exception information. Each member of the tuple should be a tuple of (Full name, e-mail address). Example:
((John, [email protected]), (Mary, [email protected]))
Note that Django will e-mail all of these people whenever an error happens. See Error reporting via e-mail for more information.
59.1.5 ALLOWED_INCLUDE_ROOTS
Default: () (Empty tuple) A tuple of strings representing allowed prexes for the {% ssi %} template tag. This is a security measure, so that template authors cant access les that they shouldnt be accessing. For example, if ALLOWED_INCLUDE_ROOTS is (/home/html, /var/www), /home/html/foo.txt %} would work, but {% ssi /etc/passwd %} wouldnt. then {% ssi
59.1.6 APPEND_SLASH
Default: True Whether to append trailing slashes to URLs. This is only used if CommonMiddleware is installed (see Middleware). See also PREPEND_WWW.
59.1.7 AUTHENTICATION_BACKENDS
Default: (django.contrib.auth.backends.ModelBackend,) A tuple of authentication backend classes (as strings) to use when attempting to authenticate a user. See the authentication backends documentation for details.
59.1.8 AUTH_PROFILE_MODULE
Default: Not dened The site-specic user prole model used by this site. See Storing additional information about users.
59.1.9 CACHE_BACKEND
Default: locmem:// The cache backend to use. See Djangos cache framework.
804
59.1.10 CACHE_MIDDLEWARE_KEY_PREFIX
Default: (Empty string) The cache key prex that the cache middleware should use. See Djangos cache framework.
59.1.11 CACHE_MIDDLEWARE_SECONDS
Default: 600 The default number of seconds to cache a page when the caching middleware or cache_page() decorator is used.
59.1.12 CSRF_COOKIE_NAME
New in version 1.2: Please, see the release notes Default: csrftoken The name of the cookie to use for the CSRF authentication token. This can be whatever you want. See Cross Site Request Forgery protection.
59.1.13 CSRF_COOKIE_DOMAIN
New in version 1.2: Please, see the release notes Default: None The domain to be used when setting the CSRF cookie. This can be useful for allowing cross-subdomain requests to be exluded from the normal cross site request forgery protection. It should be set to a string such as ".lawrence.com" to allow a POST request from a form on one subdomain to be accepted by accepted by a view served from another subdomain.
59.1.14 CSRF_FAILURE_VIEW
New in version 1.2: Please, see the release notes Default: django.views.csrf.csrf_failure A dotted path to the view function to be used when an incoming request is rejected by the CSRF protection. The function should have this signature:
def csrf_failure(request, reason="")
where reason is a short message (intended for developers or logging, not for end users) indicating the reason the request was rejected. See Cross Site Request Forgery protection.
59.1.15 DATABASES
New in version 1.2: Please, see the release notes Default: {} (Empty dictionary) A dictionary containing the settings for all databases to be used with Django. It is a nested dictionary whos contents maps database aliases to a dictionary containing the options for an individual database. The DATABASES setting must congure a default database; any number of additional databases may also be specied. The simplest possible settings le is for a single-database setup using SQLite. This can be congured using the following:
805
For other database backends, or more complex SQLite congurations, other options will be required. The following inner options are available. ENGINE Default: (Empty string) The database backend to use. The built-in database backends are: django.db.backends.postgresql_psycopg2 django.db.backends.postgresql django.db.backends.mysql django.db.backends.sqlite3 django.db.backends.oracle You can use a database backend that doesnt ship with Django by setting ENGINE to a fully-qualied path (i.e. mypackage.backends.whatever). Writing a whole new database backend from scratch is left as an exercise to the reader; see the other backends for examples. Note: Prior to Django 1.2, you could use a short version of the backend name to reference the built-in database backends (e.g., you could use sqlite3 to refer to the SQLite backend). This format has been deprecated, and will be removed in Django 1.4. HOST Default: (Empty string) Which host to use when connecting to the database. An empty string means localhost. Not used with SQLite. If this value starts with a forward slash (/) and youre using MySQL, MySQL will connect via a Unix socket to the specied socket. For example:
"HOST": /var/run/mysql
If youre using MySQL and this value doesnt start with a forward slash, then this value is assumed to be the host. If youre using PostgreSQL, an empty string means to use a Unix domain socket for the connection, rather than a network connection to localhost. If you explicitly need to use a TCP/IP connection on the local machine with PostgreSQL, specify localhost here. NAME Default: (Empty string) The name of the database to use. For SQLite, its the full path to the database le. When specifying the path, always use forward slashes, even on Windows (e.g. C:/homes/user/mysite/sqlite3.db).
806
OPTIONS Default: {} (Empty dictionary) Extra parameters to use when connecting to the database. Consult backend modules document for available keywords.
PASSWORD Default: (Empty string) The password to use when connecting to the database. Not used with SQLite. PORT Default: (Empty string) The port to use when connecting to the database. An empty string means the default port. Not used with SQLite. USER Default: (Empty string) The username to use when connecting to the database. Not used with SQLite. TEST_CHARSET Default: None The character set encoding used to create the test database. The value of this string is passed directly through to the database, so its format is backend-specic. Supported for the PostgreSQL (postgresql, postgresql_psycopg2) and MySQL (mysql) backends. TEST_COLLATION Default: None The collation order to use when creating the test database. This value is passed directly to the backend, so its format is backend-specic. Only supported for the mysql backend (see the MySQL manual for details). TEST_MIRROR Default: None The alias of the database that this database should mirror during testing. This setting exists to allow for testing of master/slave congurations of multiple databases. See the documentation on testing master/slave congurations for details.
807
TEST_NAME Default: None The name of database to use when running the test suite. If the default value (None) is used with the SQLite database engine, the tests will use a memory resident database. For all other database engines the test database will use the name test_ + DATABASE_NAME. See Testing Django applications.
59.1.16 DATABASE_ROUTERS
New in version 1.2: Please, see the release notes Default: [] (Empty list) The list of routers that will be used to determine which database to use when performing a database queries. See the documentation on automatic database routing in multi database congurations.
59.1.17 DATE_FORMAT
Default: N j, Y (e.g. Feb. 4, 2003)
The default formatting to use for displaying date elds in any part of the system. Note that if USE_L10N is set to True, then the locale-dictated format has higher precedence and will be applied instead. See allowed date format strings. Changed in version 1.2: This setting can now be overriden by setting USE_L10N to True. See also DATETIME_FORMAT, TIME_FORMAT and SHORT_DATE_FORMAT.
59.1.18 DATE_INPUT_FORMATS
New in version 1.2: Please, see the release notes Default:
(%Y-%m-%d, %m/%d/%Y, %m/%d/%y, %b %d %Y, %b %d, %Y, %d %b %Y, %d %b, %Y, %B %d %Y, %B %d, %Y, %d %B %Y, %d %B, %Y)
A tuple of formats that will be accepted when inputting data on a date eld. Formats will be tried in order, using the rst valid. Note that these format strings are specied in Pythons datetime module syntax, that is different from the one used by Django for formatting dates to be displayed. See also DATETIME_INPUT_FORMATS and TIME_INPUT_FORMATS.
59.1.19 DATETIME_FORMAT
Default: N j, Y, P (e.g. Feb. 4, 2003, 4 p.m.)
The default formatting to use for displaying datetime elds in any part of the system. Note that if USE_L10N is set to True, then the locale-dictated format has higher precedence and will be applied instead. See allowed date format strings. Changed in version 1.2: This setting can now be overriden by setting USE_L10N to True. See also DATE_FORMAT, TIME_FORMAT and SHORT_DATETIME_FORMAT.
808
59.1.20 DATETIME_INPUT_FORMATS
New in version 1.2: Please, see the release notes Default:
(%Y-%m-%d %H:%M:%S, %Y-%m-%d %H:%M, %Y-%m-%d, %m/%d/%Y %H:%M:%S, %m/%d/%Y %H:%M, %m/%d/%Y, %m/%d/%y %H:%M:%S, %m/%d/%y %H:%M, %m/%d/%y)
A tuple of formats that will be accepted when inputting data on a datetime eld. Formats will be tried in order, using the rst valid. Note that these format strings are specied in Pythons datetime module syntax, that is different from the one used by Django for formatting dates to be displayed. See also DATE_INPUT_FORMATS and TIME_INPUT_FORMATS.
59.1.21 DEBUG
Default: False A boolean that turns on/off debug mode. If you dene custom settings, django/views/debug.py has a HIDDEN_SETTINGS regular expression which will hide from the DEBUG view anything that contains SECRET, PASSWORD, or PROFANITIES. This allows untrusted users to be able to give backtraces without seeing sensitive (or offensive) settings. Still, note that there are always going to be sections of your debug output that are inappropriate for public consumption. File paths, conguration options, and the like all give attackers extra information about your server. It is also important to remember that when running with DEBUG turned on, Django will remember every SQL query it executes. This is useful when you are debugging, but on a production server, it will rapidly consume memory. Never deploy a site into production with DEBUG turned on.
59.1.22 DEBUG_PROPAGATE_EXCEPTIONS
New in version 1.0: Please, see the release notes Default: False If set to True, Djangos normal exception handling of view functions will be suppressed, and exceptions will propagate upwards. This can be useful for some test setups, and should never be used on a live site.
59.1.23 DECIMAL_SEPARATOR
New in version 1.2: Please, see the release notes Default: . (Dot) Default decimal separator used when formatting decimal numbers.
59.1.24 DEFAULT_CHARSET
Default: utf-8 Default charset to use for all HttpResponse objects, if a MIME type isnt manually specied. Used with DEFAULT_CONTENT_TYPE to construct the Content-Type header.
809
59.1.25 DEFAULT_CONTENT_TYPE
Default: text/html Default content type to use for all HttpResponse objects, if a MIME type isnt manually specied. Used with DEFAULT_CHARSET to construct the Content-Type header.
59.1.26 DEFAULT_FILE_STORAGE
Default: django.core.files.storage.FileSystemStorage Default le storage class to be used for any le-related operations that dont specify a particular storage system. See Managing les.
59.1.27 DEFAULT_FROM_EMAIL
Default: webmaster@localhost Default e-mail address to use for various automated correspondence from the site manager(s).
59.1.28 DEFAULT_TABLESPACE
New in version 1.0: Please, see the release notes Default: (Empty string) Default tablespace to use for models that dont specify one, if the backend supports it.
59.1.29 DEFAULT_INDEX_TABLESPACE
New in version 1.0: Please, see the release notes Default: (Empty string) Default tablespace to use for indexes on elds that dont specify one, if the backend supports it.
59.1.30 DISALLOWED_USER_AGENTS
Default: () (Empty tuple) List of compiled regular expression objects representing User-Agent strings that are not allowed to visit any page, systemwide. Use this for bad robots/crawlers. This is only used if CommonMiddleware is installed (see Middleware).
59.1.31 EMAIL_BACKEND
New in version 1.2: Please, see the release notes Default: django.core.mail.backends.smtp The backend to use for sending emails. For the list of available backends see Sending e-mail.
59.1.32 EMAIL_FILE_PATH
New in version 1.2: Please, see the release notes Default: Not dened The directory used by the file email backend to store output les.
810
59.1.33 EMAIL_HOST
Default: localhost The host to use for sending e-mail. See also EMAIL_PORT.
59.1.34 EMAIL_HOST_PASSWORD
Default: (Empty string) Password to use for the SMTP server dened in EMAIL_HOST. This setting is used in conjunction with EMAIL_HOST_USER when authenticating to the SMTP server. If either of these settings is empty, Django wont attempt authentication. See also EMAIL_HOST_USER.
59.1.35 EMAIL_HOST_USER
Default: (Empty string) Username to use for the SMTP server dened in EMAIL_HOST. If empty, Django wont attempt authentication. See also EMAIL_HOST_PASSWORD.
59.1.36 EMAIL_PORT
Default: 25 Port to use for the SMTP server dened in EMAIL_HOST.
59.1.37 EMAIL_SUBJECT_PREFIX
Default: [Django] Subject-line prex for e-mail messages sent with django.core.mail.mail_admins django.core.mail.mail_managers. Youll probably want to include the trailing space. or
59.1.38 EMAIL_USE_TLS
New in version 1.0: Please, see the release notes Default: False Whether to use a TLS (secure) connection when talking to the SMTP server.
59.1.39 FILE_CHARSET
New in version 1.0: Please, see the release notes Default: utf-8 The character encoding used to decode any les read from disk. This includes template les and initial SQL data les.
811
59.1.40 FILE_UPLOAD_HANDLERS
New in version 1.0: Please, see the release notes Default:
("django.core.files.uploadhandler.MemoryFileUploadHandler", "django.core.files.uploadhandler.TemporaryFileUploadHandler",)
A tuple of handlers to use for uploading. See Managing les for details.
59.1.41 FILE_UPLOAD_MAX_MEMORY_SIZE
New in version 1.0: Please, see the release notes Default: 2621440 (i.e. 2.5 MB). The maximum size (in bytes) that an upload will be before it gets streamed to the le system. See Managing les for details.
59.1.42 FILE_UPLOAD_TEMP_DIR
New in version 1.0: Please, see the release notes Default: None The directory to store data temporarily while uploading les. If None, Django will use the standard temporary directory for the operating system. For example, this will default to /tmp on *nix-style operating systems. See Managing les for details.
59.1.43 FILE_UPLOAD_PERMISSIONS
Default: None The numeric mode (i.e. 0644) to set newly uploaded les to. For more information about what these modes mean, see the documentation for os.chmod If this isnt given or is None, youll get operating-system dependent behavior. On most platforms, temporary les will have a mode of 0600, and les saved from memory will be saved using the systems standard umask. Warning: Always prex the mode with a 0. If youre not familiar with le modes, please note that the leading 0 is very important: it indicates an octal number, which is the way that modes must be specied. If you try to use 644, youll get totally incorrect behavior.
59.1.44 FIRST_DAY_OF_WEEK
New in version 1.2: Please, see the release notes Default: 0 (Sunday) Number representing the rst day of the week. This is especially useful when displaying a calendar. This value is only used when not using format internationalization, or when a format cannot be found for the current locale. The value must be an integer from 0 to 6, where 0 means Sunday, 1 means Monday and so on.
812
59.1.45 FIXTURE_DIRS
Default: () (Empty tuple) List of locations of the xture data les, in search order. Note that these paths should use Unix-style forward slashes, even on Windows. See Testing Django applications.
59.1.46 FORCE_SCRIPT_NAME
Default: None If not None, this will be used as the value of the SCRIPT_NAME environment variable in any HTTP request. This setting can be used to override the server-provided value of SCRIPT_NAME, which may be a rewritten version of the preferred value or not supplied at all.
59.1.47 FORMAT_MODULE_PATH
New in version 1.2: Please, see the release notes Default: None A full Python path to a Python package that contains format denitions for project locales. If not None, Django will check for a formats.py le, under the directory named as the current locale, and will use the formats dened on this le. For example, if FORMAT_MODULE_PATH is set to mysite.formats, and current language is en (English), Django will expect a directory tree like:
mysite/ formats/ __init__.py en/ __init__.py formats.py
Available formats are DATE_FORMAT, TIME_FORMAT, DATETIME_FORMAT, YEAR_MONTH_FORMAT, MONTH_DAY_FORMAT, SHORT_DATE_FORMAT, SHORT_DATETIME_FORMAT, FIRST_DAY_OF_WEEK, DECIMAL_SEPARATOR, THOUSAND_SEPARATOR and NUMBER_GROUPING.
59.1.48 IGNORABLE_404_ENDS
Default: .php) (mail.pl, mailform.pl, mail.cgi, mailform.cgi, favicon.ico,
59.1.49 IGNORABLE_404_STARTS
Default: (/cgi-bin/, /_vti_bin, /_vti_inf) A tuple of strings that specify beginnings of URLs that should be ignored by the 404 e-mailer. SEND_BROKEN_LINK_EMAILS, IGNORABLE_404_ENDS and the Error reporting via e-mail. See
813
59.1.50 INSTALLED_APPS
Default: () (Empty tuple) A tuple of strings designating all applications that are enabled in this Django installation. Each string should be a full Python path to a Python package that contains a Django application, as created by django-admin.py startapp. App names must be unique The application names (that is, the nal dotted part of the path to the module containing models.py) dened in INSTALLED_APPS must be unique. For example, you cant include both django.contrib.auth and myproject.auth in INSTALLED_APPS.
59.1.51 INTERNAL_IPS
Default: () (Empty tuple) A tuple of IP addresses, as strings, that: See debug comments, when DEBUG is True Receive X headers if the XViewMiddleware is installed (see Middleware)
59.1.52 LANGUAGE_CODE
Default: en-us A string representing the language code for this installation. This should be in standard language format. For example, U.S. English is "en-us". See Internationalization and localization.
59.1.53 LANGUAGE_COOKIE_NAME
New in version 1.0: Please, see the release notes Default: django_language The name of the cookie to use for the language cookie. This can be whatever you want (but should be different from SESSION_COOKIE_NAME). See Internationalization and localization.
59.1.54 LANGUAGES
Default: A tuple of all available languages. This list is continually growing and including a copy here would inevitably become rapidly out of date. You can see the current list of translated languages by looking in django/conf/global_settings.py (or view the online source). The list is a tuple of two-tuples in the format (language code, language name), the language code part should be a language name for example, (ja, Japanese). This species which languages are available for language selection. See Internationalization and localization. Generally, the default value should sufce. Only set this setting if you want to restrict language selection to a subset of the Django-provided languages. If you dene a custom LANGUAGES setting, its OK to mark the languages as translation strings (as in the default value displayed above) but use a dummy gettext() function, not the one in django.utils.translation. You should never import django.utils.translation from within your settings le, because that module in itself depends on the settings, and that would cause a circular import. The solution is to use a dummy gettext() function. Heres a sample settings le:
814
With this arrangement, django-admin.py makemessages will still nd and mark these strings for translation, but the translation wont happen at runtime so youll have to remember to wrap the languages in the real gettext() in any code that uses LANGUAGES at runtime.
59.1.55 LOCALE_PATHS
Default: () (Empty tuple) A tuple of directories where Django looks for translation les. See Using internationalization in your own projects.
59.1.56 LOGIN_REDIRECT_URL
New in version 1.0: Please, see the release notes Default: /accounts/profile/ The URL where requests are redirected after login when the contrib.auth.login view gets no next parameter. This is used by the login_required() decorator, for example.
59.1.57 LOGIN_URL
New in version 1.0: Please, see the release notes Default: /accounts/login/ The URL where requests are redirected for login, especially when using the login_required() decorator.
59.1.58 LOGOUT_URL
New in version 1.0: Please, see the release notes Default: /accounts/logout/ LOGIN_URL counterpart.
59.1.59 MANAGERS
Default: () (Empty tuple) A tuple in the same format as ADMINS that species who should get broken-link notications when SEND_BROKEN_LINK_EMAILS=True.
59.1.60 MEDIA_ROOT
Default: (Empty string) Absolute path to the directory that holds media for "/home/media/media.lawrence.com/" See also MEDIA_URL. this installation. Example:
815
59.1.61 MEDIA_URL
Default: (Empty string) URL that handles the media served from MEDIA_ROOT. Example: "http://media.lawrence.com" Note that this should have a trailing slash if it has a path component. Good: "http://www.example.com/static/" Bad: "http://www.example.com/static"
59.1.62 MESSAGE_LEVEL
New in version 1.2: Please, see the release notes Default: messages.INFO Sets the minimum message level that will be recorded by the messages framework. See the messages documentation for more details.
59.1.63 MESSAGE_STORAGE
New in version 1.2: Please, see the release notes Default: django.contrib.messages.storage.user_messages.Legacy Controls where Django stores message data. See the messages documentation for more details.
59.1.64 MESSAGE_TAGS
New in version 1.2: Please, see the release notes Default:
{messages.DEBUG: debug, messages.INFO: info, messages.SUCCESS: success, messages.WARNING: warning, messages.ERROR: error,}
Sets the mapping of message levels to message tags. See the messages documentation for more details.
59.1.65 MIDDLEWARE_CLASSES
Default:
(django.middleware.common.CommonMiddleware, django.contrib.sessions.middleware.SessionMiddleware, django.middleware.csrf.CsrfViewMiddleware, django.contrib.auth.middleware.AuthenticationMiddleware, django.contrib.messages.middleware.MessageMiddleware,)
A tuple of middleware classes to use. See Middleware. Changed in version django.contrib.messages.middleware.MessageMiddleware was added to the default. more information, see the messages documentation.
1.2: For
816
59.1.66 MONTH_DAY_FORMAT
Default: F j The default formatting to use for date elds on Django admin change-list pages and, possibly, by other parts of the system in cases when only the month and day are displayed. For example, when a Django admin change-list page is being ltered by a date drilldown, the header for a given day displays the day and month. Different locales have different formats. For example, U.S. English would say January 1, whereas Spanish might say 1 Enero. See allowed date format strings. See also DATE_FORMAT, DATETIME_FORMAT, TIME_FORMAT and YEAR_MONTH_FORMAT.
59.1.67 NUMBER_GROUPING
New in version 1.2: Please, see the release notes Default: 0 Number of digits grouped together on the integer part of a number. Common use is to display a thousand separator. If this setting is 0, then, no grouping will be applied to the number. If this setting is greater than 0 then the setting THOUSAND_SEPARATOR will be used as the separator between those groups. See also THOUSAND_SEPARATOR
59.1.68 PREPEND_WWW
Default: False Whether to prepend the www. subdomain to URLs that dont have it. This is only used if CommonMiddleware is installed (see Middleware). See also APPEND_SLASH.
59.1.69 PROFANITIES_LIST
A tuple of profanities, as strings, that will trigger a validation error when the hasNoProfanities validator is called. We dont list the default values here, because that would be profane. To see the default values, see the le django/conf/global_settings.py.
59.1.70 ROOT_URLCONF
Default: Not dened A string representing the full Python import path to your root URLconf. For example: "mydjangoapps.urls". Can be overridden on a per-request basis by setting the attribute urlconf on the incoming HttpRequest object. See How Django processes a request for details.
59.1.71 SECRET_KEY
Default: (Empty string) A secret key for this particular Django installation. Used to provide a seed in secret-key hashing algorithms. Set this to a random string the longer, the better. django-admin.py startproject creates one automatically.
817
59.1.72 SEND_BROKEN_LINK_EMAILS
Default: False Whether to send an e-mail to the MANAGERS each time somebody visits a Django-powered page that is 404ed with a non-empty referer (i.e., a broken link). This is only used if CommonMiddleware is installed (see Middleware. See also IGNORABLE_404_STARTS, IGNORABLE_404_ENDS and Error reporting via e-mail.
59.1.73 SERIALIZATION_MODULES
Default: Not dened. A dictionary of modules containing serializer denitions (provided as strings), keyed by a string identier for that serialization type. For example, to dene a YAML serializer, use:
SERIALIZATION_MODULES = { yaml : path.to.yaml_serializer }
59.1.74 SERVER_EMAIL
Default: root@localhost The e-mail address that error messages come from, such as those sent to ADMINS and MANAGERS.
59.1.75 SESSION_ENGINE
New in version 1.0: Please, see the release notesChanged in version 1.1: The cached_db backend was added Default: django.contrib.sessions.backends.db Controls where Django stores session data. Valid values are: django.contrib.sessions.backends.db django.contrib.sessions.backends.file django.contrib.sessions.backends.cache django.contrib.sessions.backends.cached_db See How to use sessions.
59.1.76 SESSION_COOKIE_AGE
Default: 1209600 (2 weeks, in seconds) The age of session cookies, in seconds. See How to use sessions.
59.1.77 SESSION_COOKIE_DOMAIN
Default: None The domain to use for session cookies. Set this to a string such as ".lawrence.com" for cross-domain cookies, or use None for a standard domain cookie. See the How to use sessions.
818
59.1.78 SESSION_COOKIE_NAME
Default: sessionid The name of the cookie to use for sessions. This can be whatever you want (but should be different from LANGUAGE_COOKIE_NAME). See the How to use sessions.
59.1.79 SESSION_COOKIE_PATH
New in version 1.0: Please, see the release notes Default: / The path set on the session cookie. This should either match the URL path of your Django installation or be parent of that path. This is useful if you have multiple Django instances running under the same hostname. They can use different cookie paths, and each instance will only see its own session cookie.
59.1.80 SESSION_COOKIE_SECURE
Default: False Whether to use a secure cookie for the session cookie. If this is set to True, the cookie will be marked as secure, which means browsers may ensure that the cookie is only sent under an HTTPS connection. See the How to use sessions.
59.1.81 SESSION_EXPIRE_AT_BROWSER_CLOSE
Default: False Whether to expire the session when the user closes his or her browser. See the How to use sessions.
59.1.82 SESSION_FILE_PATH
New in version 1.0: Please, see the release notes Default: None If youre using le-based session storage, this sets the directory in which Django will store session data. See How to use sessions. When the default value (None) is used, Django will use the standard temporary directory for the system.
59.1.83 SESSION_SAVE_EVERY_REQUEST
Default: False Whether to save the session data on every request. See How to use sessions.
59.1.84 SHORT_DATE_FORMAT
New in version 1.2: Please, see the release notes Default: m/d/Y (e.g. 12/31/2003) An available formatting that can be used for displaying date elds on templates. Note that if USE_L10N is set to True, then the corresponding locale-dictated format has higher precedence and will be applied. See allowed date format strings. See also DATE_FORMAT and SHORT_DATETIME_FORMAT. 59.1. Available settings 819
59.1.85 SHORT_DATETIME_FORMAT
New in version 1.2: Please, see the release notes Default: m/d/Y P (e.g. 12/31/2003 4 p.m.) An available formatting that can be used for displaying datetime elds on templates. Note that if USE_L10N is set to True, then the corresponding locale-dictated format has higher precedence and will be applied. See allowed date format strings. See also DATE_FORMAT and SHORT_DATETIME_FORMAT.
59.1.86 SITE_ID
Default: Not dened The ID, as an integer, of the current site in the django_site database table. This is used so that application data can hook into specic site(s) and a single database can manage content for multiple sites. See The sites framework.
59.1.87 TEMPLATE_CONTEXT_PROCESSORS
Default:
("django.contrib.auth.context_processors.auth", "django.core.context_processors.debug", "django.core.context_processors.i18n", "django.core.context_processors.media", "django.contrib.messages.context_processors.messages")
A tuple of callables that are used to populate the context in RequestContext. These callables take a request object as their argument and return a dictionary of items to be merged into the context. Changed in version 1.2: "django.contrib.messages.context_processors.messages" was added to the default. For more information, see the messages documentation.Changed in version 1.2: The auth context processor was moved in this release from its old location django.core.context_processors.auth to django.contrib.auth.context_processors.auth.
59.1.88 TEMPLATE_DEBUG
Default: False A boolean that turns on/off template debug mode. If this is True, the fancy error page will display a detailed report for any TemplateSyntaxError. This report contains the relevant snippet of the template, with the appropriate line highlighted. Note that Django only displays fancy error pages if DEBUG is True, so youll want to set that to take advantage of this setting. See also DEBUG.
59.1.89 TEMPLATE_DIRS
Default: () (Empty tuple) List of locations of the template source les, in search order. Note that these paths should use Unix-style forward slashes, even on Windows. 820 Chapter 59. Settings
59.1.90 TEMPLATE_LOADERS
Default:
(django.template.loaders.filesystem.Loader, django.template.loaders.app_directories.Loader)
A tuple of template loader classes, specied as strings. Each Loader class knows how to import templates from a particular source. Optionally, a tuple can be used instead of a string. The rst item in the tuple should be the Loaders module, subsequent items are passed to the Loader during initialization. See The Django template language: For Python programmers.
59.1.91 TEMPLATE_STRING_IF_INVALID
Default: (Empty string) Output, as a string, that the template system should use for invalid (e.g. misspelled) variables. See How invalid variables are handled..
59.1.92 TEST_RUNNER
Default: django.test.simple.DjangoTestSuiteRunner Changed in version 1.2: Prior to 1.2, test runners were a function, not a class. The name of the class to use for starting the test suite. See Testing Django applications.
59.1.93 THOUSAND_SEPARATOR
New in version 1.2: Please, see the release notes Default , (Comma) Default thousand separator used when formatting numbers. This setting is used only when NUMBER_GROUPING is set. See also NUMBER_GROUPING, DECIMAL_SEPARATOR
59.1.94 TIME_FORMAT
Default: P (e.g. 4 p.m.) The default formatting to use for displaying time elds in any part of the system. Note that if USE_L10N is set to True, then the locale-dictated format has higher precedence and will be applied instead. See allowed date format strings. Changed in version 1.2: This setting can now be overriden by setting USE_L10N to True. See also DATE_FORMAT and DATETIME_FORMAT.
59.1.95 TIME_INPUT_FORMATS
New in version 1.2: Please, see the release notes Default: (%H:%M:%S, %H:%M) A tuple of formats that will be accepted when inputting data on a time eld. Formats will be tried in order, using the rst valid. Note that these format strings are specied in Pythons datetime module syntax, that is different from the one used by Django for formatting dates to be displayed. 59.1. Available settings 821
59.1.96 TIME_ZONE
Default: America/Chicago Changed in version 1.2: None was added as an allowed value. A string representing the time zone for this installation, or None. See available choices. (Note that list of available choices lists more than one on the same line; youll want to use just one of the choices for a given time zone. For instance, one line says Europe/London GB GB-Eire, but you should use the rst bit of that Europe/London as your TIME_ZONE setting.) Note that this is the time zone to which Django will convert all dates/times not necessarily the timezone of the server. For example, one server may serve multiple Django-powered sites, each with a separate time-zone setting. Normally, Django sets the os.environ[TZ] variable to the time zone you specify in the TIME_ZONE setting. Thus, all your views and models will automatically operate in the correct time zone. However, Django wont set the TZ environment variable under the following conditions: If youre using the manual conguration option as described in manually conguring settings, or If you specify TIME_ZONE = None. This will cause Django to fall back to using the system timezone. If Django doesnt set the TZ environment variable, its up to you to ensure your processes are running in the correct environment. Note: Django cannot reliably use alternate time zones in a Windows environment. If youre running Django on Windows, this variable must be set to match the system timezone.
59.1.97 URL_VALIDATOR_USER_AGENT
Default: Django/<version> (http://www.djangoproject.com/) The string to use as the User-Agent header when checking to see if URLs exist (see the verify_exists option on URLField).
59.1.98 USE_ETAGS
Default: False A boolean that species whether to output the Etag header. This saves bandwidth but slows down performance. This is only used if CommonMiddleware is installed (see Middleware).
59.1.99 USE_L10N
New in version 1.2: Please, see the release notes Default False A boolean that species if data will be localized by default or not. If this is set to True, e.g. Django will display numbers and dates using the format of the current locale. See also USE_I18N and LANGUAGE_CODE
59.1.100 USE_I18N
Default: True
822
A boolean that species whether Djangos internationalization system should be enabled. This provides an easy way to turn it off, for performance. If this is set to False, Django will make some optimizations so as not to load the internationalization machinery. See also USE_L10N
59.1.101 USE_THOUSAND_SEPARATOR
New in version 1.2: Please, see the release notes Default False A boolean that species wheter to display numbers using a thousand separator. If this is set to True, Django will use values from THOUSAND_SEPARATOR and NUMBER_GROUPING from current locale, to format the number. USE_L10N must be set to True, in order to format numbers. See also THOUSAND_SEPARATOR and NUMBER_GROUPING.
59.1.102 YEAR_MONTH_FORMAT
Default: F Y The default formatting to use for date elds on Django admin change-list pages and, possibly, by other parts of the system in cases when only the year and month are displayed. For example, when a Django admin change-list page is being ltered by a date drilldown, the header for a given month displays the month and the year. Different locales have different formats. For example, U.S. English would say January 2006, whereas another locale might say 2006/January. See allowed date format strings. See also DATE_FORMAT, DATETIME_FORMAT, TIME_FORMAT and MONTH_DAY_FORMAT.
59.2.2 DATABASE_HOST
Deprecated since version 1.2: This setting has been replaced by HOST in DATABASES.
59.2.3 DATABASE_NAME
Deprecated since version 1.2: This setting has been replaced by NAME in DATABASES.
59.2.4 DATABASE_OPTIONS
Deprecated since version 1.2: This setting has been replaced by OPTIONS in DATABASES.
823
59.2.5 DATABASE_PASSWORD
Deprecated since version 1.2: This setting has been replaced by PASSWORD in DATABASES.
59.2.6 DATABASE_PORT
Deprecated since version 1.2: This setting has been replaced by PORT in DATABASES.
59.2.7 DATABASE_USER
Deprecated since version 1.2: This setting has been replaced by USER in DATABASES.
59.2.8 TEST_DATABASE_CHARSET
Deprecated since version 1.2: This setting has been replaced by TEST_CHARSET in DATABASES.
59.2.9 TEST_DATABASE_COLLATION
Deprecated since version 1.2: This setting has been replaced by TEST_COLLATION in DATABASES.
59.2.10 TEST_DATABASE_NAME
Deprecated since version 1.2: This setting has been replaced by TEST_NAME in DATABASES.
824
CHAPTER
SIXTY
SIGNALS
A list of all the signals that Django sends. See Also: See the documentation on the signal dispatcher for information regarding how to register for and receive signals. The comment framework sends a set of comment-related signals.
60.1.1 pre_init
pre_init Whenever you instantiate a Django model this signal is sent at the beginning of the models __init__() method. Arguments sent with this signal: sender The model class that just had an instance created. args A list of positional arguments passed to __init__(): kwargs A dictionary of keyword arguments passed to __init__():. For example, the tutorial has this line:
p = Poll(question="Whats up?", pub_date=datetime.now())
825
Value Poll (the class itself) [] (an empty list because there were no positional arguments passed to __init__.) {question: "Whats up?", pub_date: datetime.now()}
60.1.2 post_init
post_init Like pre_init, but this one is sent when the __init__(): method nishes. Arguments sent with this signal: sender As above: the model class that just had an instance created. instance The actual instance of the model thats just been created.
60.1.3 pre_save
pre_save This is sent at the beginning of a models save() method. Arguments sent with this signal: sender The model class. instance The actual instance being saved.
60.1.4 post_save
post_save Like pre_save, but sent at the end of the save() method. Arguments sent with this signal: sender The model class. instance The actual instance being saved. created A boolean; True if a new record was created.
60.1.5 pre_delete
pre_delete Sent at the beginning of a models delete() method. Arguments sent with this signal: sender The model class. instance The actual instance being deleted.
826
60.1.6 post_delete
post_delete Like pre_delete, but sent at the end of the delete() method. Arguments sent with this signal: sender The model class. instance The actual instance being deleted. Note that the object will no longer be in the database, so be very careful what you do with this instance.
60.1.7 m2m_changed
m2m_changed New in version 1.2: Please, see the release notes Sent when a ManyToManyField is changed on a model instance. Strictly speaking, this is not a model signal since it is sent by the ManyToManyField, but since it complements the pre_save/post_save and pre_delete/post_delete when it comes to tracking changes to models, it is included here. Arguments sent with this signal: sender The intermediate model class describing the ManyToManyField. This class is automatically created when a many-to-many eld is dened; you can access it using the through attribute on the many-to-many eld. instance The instance whose many-to-many relation is updated. This can be an instance of the sender, or of the class the ManyToManyField is related to. action A string indicating the type of update that is done on the relation. This can be one of the following: "pre_add" Sent before one or more objects are added to the relation "post_add" Sent after one or more objects are added to the relation "pre_remove" Sent after one or more objects are removed from the relation "post_remove" Sent after one or more objects are removed from the relation "pre_clear" Sent before the relation is cleared "post_clear" Sent after the relation is cleared reverse Indicates which side of the relation is updated (i.e., if it is the forward or reverse relation that is being modied). model The class of the objects that are added to, removed from or cleared from the relation. pk_set With the "add" and "remove" action, this is a list of primary key values that have been added to or removed from the relation. For the "clear" action, this is None. For example, if a Pizza can have multiple Topping objects, modeled like this:
class Topping(models.Model): # ... class Pizza(models.Model): # ... toppings = models.ManyToManyField(Topping)
827
the arguments sent to a m2m_changed handler would be: Argument sender instance action reverse model pk_set Value Pizza.toppings.through (the intermediate m2m class) p (the Pizza instance being modied) "add" False (Pizza contains the ManyToManyField, so this call modies the forward relation) Topping (the class of the objects added to the Pizza) [t.id] (since only Topping t was added to the relation)
the arguments sent to a m2m_changed handler would be: Argument sender instance action reverse model pk_set Value Pizza.toppings.through (the intermediate m2m class) t (the Topping instance being modied) "remove" True (Pizza contains the ManyToManyField, so this call modies the reverse relation) Pizza (the class of the objects removed from the Topping) [p.id] (since only Pizza p was removed from the relation)
60.1.8 class_prepared
class_prepared Sent whenever a model class has been prepared that is, once model has been dened and registered with Djangos model system. Django uses this signal internally; its not generally used in third-party applications. Arguments that are sent with this signal: sender The model class which was just prepared.
60.2.1 post_syncdb
post_syncdb Sent by syncdb after it installs an application. Any handlers that listen to this signal need to be written in a particular place: a management module in one of your INSTALLED_APPS. If handlers are registered anywhere else they may not be loaded by syncdb. Arguments sent with this signal:
828
sender The models module that was just installed. That is, if syncdb just installed an app called "foo.bar.myapp", sender will be the foo.bar.myapp.models module. app Same as sender. created_models A list of the model classes from any app which syncdb has created so far. verbosity Indicates how much information manage.py is printing on screen. See the --verbosity ag for details. Functions which listen for post_syncdb should adjust what they output to the screen based on the value of this argument. interactive If interactive is True, its safe to prompt the user to input things on the command line. If interactive is False, functions which listen for this signal should not try to prompt for anything. For example, the django.contrib.auth app only prompts to create a superuser when interactive is True.
60.3.1 request_started
request_started Sent when Django begins processing an HTTP request. Arguments sent with this signal: sender The handler class i.e. django.core.handlers.modpython.ModPythonHandler or django.core.handlers.wsgi.WsgiHandler that handled the request.
60.3.2 request_nished
request_finished Sent when Django nishes processing an HTTP request. Arguments sent with this signal: sender The handler class, as above.
60.3.3 got_request_exception
got_request_exception This signal is sent whenever Django encounters an exception while processing an incoming HTTP request. Arguments sent with this signal: sender The handler class, as above. request The HttpRequest object.
829
60.4.1 template_rendered
template_rendered Sent when the test system renders a template. This signal is not emitted during normal operation of a Django server it is only available during testing. Arguments sent with this signal: sender The Template object which was rendered. template Same as sender context The Context with which the template was rendered.
830
CHAPTER
SIXTYONE
TEMPLATES
Djangos template engine provides a powerful mini-language for dening the user-facing layer of your application, encouraging a clean separation of application and presentation logic. Templates can be maintained by anyone with an understanding of HTML; no knowledge of Python is required.
831
cycle Changed in version 1.0: Cycle among the given strings or variables each time this tag is encountered. Within a loop, cycles among the given strings each time through the loop:
{% for o in some_list %} <tr class="{% cycle row1 row2 %}"> ... </tr> {% endfor %}
You can use variables, too. For example, if you have two template variables, rowvalue1 and rowvalue2, you can cycle between their values like this:
{% for o in some_list %} <tr class="{% cycle rowvalue1 rowvalue2 %}"> ... </tr> {% endfor %}
In some cases you might want to refer to the next value of a cycle from outside of a loop. To do this, just give the {% cycle %} tag a name, using as, like this:
{% cycle row1 row2 as rowcolors %}
From then on, you can insert the current value of the cycle wherever youd like in your template:
<tr class="{% cycle rowcolors %}">...</tr> <tr class="{% cycle rowcolors %}">...</tr>
You can use any number of values in a {% cycle %} tag, separated by spaces. Values enclosed in single () or double quotes (") are treated as string literals, while values without quotes are treated as template variables. Note that the variables included in the cycle will not be escaped. This is because template tags do not escape their content. Any HTML or Javascript code contained in the printed variable will be rendered as-is, which could potentially lead to security issues. If you need to escape the variables in the cycle, you must do so explicitly:
{% filter force_escape %} {% cycle var1 var2 var3 %} {% endfilter %}
For backwards compatibility, the {% cycle %} tag supports the much inferior old syntax from previous Django versions. You shouldnt use this in any new projects, but for the sake of the people who are still using it, heres what it looks like:
{% cycle row1,row2,row3 %}
832
In this syntax, each value gets interpreted as a literal string, and theres no way to specify variable values. Or literal commas. Or spaces. Did we mention you shouldnt use this syntax in any new projects? debug Output a whole load of debugging information, including the current context and imported modules. extends Signal that this template extends a parent template. This tag can be used in two ways: {% extends "base.html" %} (with quotes) uses the literal value "base.html" as the name of the parent template to extend. {% extends variable %} uses the value of variable. If the variable evaluates to a string, Django will use that string as the name of the parent template. If the variable evaluates to a Template object, Django will use that object as the parent template. See Template inheritance for more information. lter Filter the contents of the variable through variable lters. Filters can also be piped through each other, and they can have arguments just like in variable syntax. Sample usage:
{% filter force_escape|lower %} This text will be HTML-escaped, and will appear in all lowercase. {% endfilter %}
rstof Outputs the rst variable passed that is not False, without escaping. Outputs nothing if all the passed variables are False. Sample usage:
{% firstof var1 var2 var3 %}
You can also use a literal string as a fallback value in case all passed variables are False:
833
Note that the variables included in the rstof tag will not be escaped. This is because template tags do not escape their content. Any HTML or Javascript code contained in the printed variable will be rendered as-is, which could potentially lead to security issues. If you need to escape the variables in the rstof tag, you must do so explicitly:
{% filter force_escape %} {% firstof var1 var2 var3 "fallback value" %} {% endfilter %}
for Loop over each item in an array. For example, to display a list of athletes provided in athlete_list:
<ul> {% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% endfor %} </ul>
You can loop over a list in reverse by using {% for obj in list reversed %}. New in version 1.0: Please, see the release notes If you need to loop over a list of lists, you can unpack the values in each sub-list into individual variables. For example, if your context contains a list of (x,y) coordinates called points, you could use the following to output the list of points:
{% for x, y in points %} There is a point at {{ x }},{{ y }} {% endfor %}
This can also be useful if you need to access the items in a dictionary. For example, if your context contained a dictionary data, the following would display the keys and values of the dictionary:
{% for key, value in data.items %} {{ key }}: {{ value }} {% endfor %}
The for loop sets a number of variables available within the loop: Variable forloop.counter forloop.counter0 forloop.revcounter forloop.revcounter0 forloop.first forloop.last forloop.parentloop Description The current iteration of the loop (1-indexed) The current iteration of the loop (0-indexed) The number of iterations from the end of the loop (1-indexed) The number of iterations from the end of the loop (0-indexed) True if this is the rst time through the loop True if this is the last time through the loop For nested loops, this is the loop above the current one
<ul> {% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% empty %} <li>Sorry, no athlete in this list!</li> {% endfor %} <ul>
The above is equivalent to but shorter, cleaner, and possibly faster than the following:
<ul> {% if athlete_list %} {% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% endfor %} {% else %} <li>Sorry, no athletes in this list.</li> {% endif %} </ul>
if The {% if %} tag evaluates a variable, and if that variable is true (i.e. exists, is not empty, and is not a false boolean value) the contents of the block are output:
{% if athlete_list %} Number of athletes: {{ athlete_list|length }} {% else %} No athletes. {% endif %}
In the above, if athlete_list is not empty, the number of athletes will be displayed by the {{ athlete_list|length }} variable. As you can see, the if tag can take an optional {% else %} clause that will be displayed if the test fails.
Boolean operators
if tags may use and, or or not to test a number of variables or to negate a given variable:
{% 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 (OK, so
835
writing English translations of boolean logic sounds stupid; its not our fault). {% endif %} {% if athlete_list and not coach_list %} There are some athletes and absolutely no coaches. {% endif %}
Changed in version 1.2: Please, see the release notes Use of both and and or clauses within the same tag is allowed, with and having higher precedence than or e.g.:
{% if athlete_list and coach_list or cheerleader_list %}
Use of actual brackets in the if tag is invalid syntax. If you need them to indicate precedence, you should use nested if tags. New in version 1.2: Please, see the release notes if tags may also use the operators ==, !=, <, >, <=, >= and in which work as follows:
== operator
Equality. Example:
{% if somevar == "x" %} This appears if variable somevar equals the string "x" {% endif %}
!= operator
Inequality. Example:
{% if somevar != "x" %} This appears if variable somevar does not equal the string "x", or if somevar is not found in the context {% endif %}
< operator
Less than. Example:
{% if somevar < 100 %} This appears if variable somevar is less than 100. {% endif %}
836
> operator
Greater than. Example:
{% if somevar > 0 %} This appears if variable somevar is greater than 0. {% endif %}
<= operator
Less than or equal to. Example:
{% if somevar <= 100 %} This appears if variable somevar is less than 100 or equal to 100. {% endif %}
>= operator
Greater than or equal to. Example:
{% if somevar >= 1 %} This appears if variable somevar is greater than 1 or equal to 1. {% endif %}
in operator
Contained within. This operator is supported by many Python containers to test whether the given value is in the container. The following are some examples of how x in y will be interpreted:
{% if "bc" in "abcdef" %} This appears since "bc" is a substring of "abcdef" {% endif %} {% if "hello" in greetings %} If greetings is a list or set, one element of which is the string "hello", this will appear. {% endif %} {% if user in users %} If users is a QuerySet, this will appear if user is an instance that belongs to the QuerySet. {% endif %}
not in operator Not contained within. This is the negation of the in operator. The comparison operators cannot be chained like in Python or in mathematical notation. For example, instead of using:
837
{% if a > b > c %}
(WRONG)
Filters
You can also use lters in the if expression. For example:
{% if messages|length >= 100 %} You have lots of messages today! {% endif %}
Complex expressions
All of the above can be combined to form complex expressions. For such expressions, it can be important to know how the operators are grouped when the expression is evaluated - that is, the precedence rules. The precedence of the operators, from lowest to highest, is as follows: or and not in ==, !=, <, >,<=, >= (This follows Python exactly). So, for example, the following complex if tag: {% if a == b or c == d and e %} ...will be interpreted as:
(a == b) or ((c == d) and e)
If you need different precedence, you will need to use nested if tags. Sometimes that is better for clarity anyway, for the sake of those who do not know the precedence rules. ifchanged Check if a value has changed from the last iteration of a loop. The ifchanged block tag is used within a loop. It has two possible uses. 1. Checks its own rendered contents against its previous state and only displays the content if it has changed. For example, this displays a list of days, only displaying the month if it changes:
<h1>Archive for {{ year }}</h1> {% for date in days %} {% ifchanged %}<h3>{{ date|date:"F" }}</h3>{% endifchanged %}
838
2. If given a variable, check whether that variable has changed. For example, the following shows the date every time it changes, but only shows the hour if both the hour and the date has changed:
{% for date in days %} {% ifchanged date.date %} {{ date.date }} {% endifchanged %} {% ifchanged date.hour date.date %} {{ date.hour }} {% endifchanged %} {% endfor %}
The ifchanged tag can also take an optional {% else %} clause that will be displayed if the value has not changed:
{% for match in matches %} <div style="background-color: {% ifchanged match.ballot_id %} {% cycle "red" "blue" %} {% else %} grey {% endifchanged %} ">{{ match }}</div> {% endfor %}
ifequal Output the contents of the block if the two arguments equal each other. Example:
{% ifequal user.id comment.user_id %} ... {% endifequal %}
As in the {% if %} tag, an {% else %} clause is optional. The arguments can be hard-coded strings, so the following is valid:
{% ifequal user.username "adrian" %} ... {% endifequal %}
It is only possible to compare an argument to template variables or strings. You cannot check for equality with Python objects such as True or False. If you need to test if something is true or false, use the if tag instead. New in version 1.2: An alternative to the ifequal tag is to use the if tag and the == operator. ifnotequal Just like ifequal, except it tests that the two arguments are not equal. New in version 1.2: An alternative to the ifnotequal tag is to use the if tag and the != operator.
839
include Loads a template and renders it with the current context. This is a way of including other templates within a template. The template name can either be a variable or a hard-coded (quoted) string, in either single or double quotes. This example includes the contents of the template "foo/bar.html":
{% include "foo/bar.html" %}
This example includes the contents of the template whose name is contained in the variable template_name:
{% include template_name %}
An included template is rendered with the context of the template thats including it. This example produces the output "Hello, John": Context: variable person is set to "john". Template:
{% include "name_snippet.html" %}
See also: {% ssi %}. Note: The include tag should be considered as an implementation of render this subtemplate and include the HTML, not as parse this subtemplate and include its contents as if it were part of the parent. This means that there is no shared state between included templates each include is a completely independent rendering process. load Load a custom template tag set. See Custom tag and lter libraries for more information. now Display the date, formatted according to the given string. Uses the same format as PHPs date() function (http://php.net/date) with some custom extensions. Available format strings: Format character a A b B c d D f
Description a.m. or p.m. (Note that this is slightly different than PHPs output, because this includes periods to ma AM or PM. Month, textual, 3 letters, lowercase. Not implemented. ISO 8601 Format. Day of the month, 2 digits with leading zeros. Day of the week, textual, 3 letters. Time, in 12-hour hours and minutes, with minutes left off if theyre zero. Proprietary extension.
840
F g G h H i I j l L m M n N O P r s S t T u U w W y Y z Z
Table 61.1 conti Month, textual, long. Hour, 12-hour format without leading zeros. Hour, 24-hour format without leading zeros. Hour, 12-hour format. Hour, 24-hour format. Minutes. Not implemented. Day of the month without leading zeros. Day of the week, textual, long. Boolean for whether its a leap year. Month, 2 digits with leading zeros. Month, textual, 3 letters. Month without leading zeros. Month abbreviation in Associated Press style. Proprietary extension. Difference to Greenwich time in hours. Time, in 12-hour hours, minutes and a.m./p.m., with minutes left off if theyre zero and the special-case strin RFC 2822 formatted date. Seconds, 2 digits with leading zeros. English ordinal sufx for day of the month, 2 characters. Number of days in the given month. Time zone of this machine. Microseconds. Seconds since the Unix Epoch (January 1 1970 00:00:00 UTC). Day of the week, digits without leading zeros. ISO-8601 week number of year, with weeks starting on Monday. Year, 2 digits. Year, 4 digits. Day of the year. Time zone offset in seconds. The offset for timezones west of UTC is always negative, and for those east of UT
Example:
It is {% now "jS F Y H:i" %}
Note that you can backslash-escape a format string if you want to use the raw value. In this example, f is backslashescaped, because otherwise f is a format string that displays the time. The o doesnt need to be escaped, because its not a format character:
It is the {% now "jS o\f F" %}
This would display as It is the 4th of September. New in version 1.2: Please, see the release notes The c and u format specication characters were added in Django 1.2. regroup Regroup a list of alike objects by a common attribute. This complex tag is best illustrated by use of an example: say that people is a list of people represented by dictionaries with first_name, last_name, and gender keys:
841
George, last_name: Bush, gender: Male}, Bill, last_name: Clinton, gender: Male}, Margaret, last_name: Thatcher, gender: Female}, Condoleezza, last_name: Rice, gender: Female}, Pat, last_name: Smith, gender: Unknown},
...and youd like to display a hierarchical list that is ordered by gender, like this: Male: George Bush Bill Clinton Female: Margaret Thatcher Condoleezza Rice Unknown: Pat Smith You can use the {% regroup %} tag to group the list of people by gender. The following snippet of template code would accomplish this:
{% regroup people by gender as gender_list %} <ul> {% for gender in gender_list %} <li>{{ gender.grouper }} <ul> {% for item in gender.list %} <li>{{ item.first_name }} {{ item.last_name }}</li> {% endfor %} </ul> </li> {% endfor %} </ul>
Lets walk through this example. {% regroup %} takes three arguments: the list you want to regroup, the attribute to group by, and the name of the resulting list. Here, were regrouping the people list by the gender attribute and calling the result gender_list. {% regroup %} produces a list (in this case, gender_list) of group objects. Each group object has two attributes: grouper the item that was grouped by (e.g., the string Male or Female). list a list of all items in this group (e.g., a list of all people with gender=Male). Note that {% regroup %} does not order its input! Our example relies on the fact that the people list was ordered by gender in the rst place. If the people list did not order its members by gender, the regrouping would naively display more than one group for a single gender. For example, say the people list was set to this (note that the males are not grouped together):
people = [ {first_name: Bill, last_name: Clinton, gender: Male}, {first_name: Pat, last_name: Smith, gender: Unknown},
842
{first_name: Margaret, last_name: Thatcher, gender: Female}, {first_name: George, last_name: Bush, gender: Male}, {first_name: Condoleezza, last_name: Rice, gender: Female}, ]
With this input for people, the example {% regroup %} template code above would result in the following output: Male: Bill Clinton Unknown: Pat Smith Female: Margaret Thatcher Male: George Bush Female: Condoleezza Rice The easiest solution to this gotcha is to make sure in your view code that the data is ordered according to how you want to display it. Another solution is to sort the data in the template using the dictsort lter, if your data is in a list of dictionaries:
{% regroup people|dictsort:"gender" by gender as gender_list %}
spaceless Removes whitespace between HTML tags. This includes tab characters and newlines. Example usage:
{% spaceless %} <p> <a href="foo/">Foo</a> </p> {% endspaceless %}
Only space between tags is removed not space between tags and text. In this example, the space around Hello wont be stripped:
{% spaceless %} <strong> Hello </strong> {% endspaceless %}
843
ssi Output the contents of a given le into the page. Like a simple include tag, {% ssi %} includes the contents of another le which must be specied using an absolute path in the current page:
{% ssi /home/html/ljworld.com/includes/right_generic.html %}
If the optional parsed parameter is given, the contents of the included le are evaluated as template code, within the current context:
{% ssi /home/html/ljworld.com/includes/right_generic.html parsed %}
Note that if you use {% ssi %}, youll need to dene ALLOWED_INCLUDE_ROOTS in your Django settings, as a security measure. See also: {% include %}. templatetag Output one of the syntax characters used to compose template tags. Since the template system has no concept of escaping, to display one of the bits used in template tags, you must use the {% templatetag %} tag. The argument tells which template bit to output: Argument openblock closeblock openvariable closevariable openbrace closebrace opencomment closecomment url Returns an absolute URL (i.e., a URL without the domain name) matching a given view function and optional parameters. This is a way to output links without violating the DRY principle by having to hard-code URLs in your templates:
{% url path.to.some_view v1 v2 %}
Outputs {% %} {{ }} { } {# #}
The rst argument is a path to a view function in the format package.package.module.function. Additional arguments are optional and should be space-separated values that will be used as arguments in the URL. The example above shows passing positional arguments. Alternatively you may use keyword syntax:
{% url path.to.some_view arg1=v1 arg2=v2 %}
844
Do not mix both positional and keyword syntax in a single call. All arguments required by the URLconf should be present. For example, suppose you have a view, app_views.client, whose URLconf takes a client ID (here, client() is a method inside the views le app_views.py). The URLconf line might look like this:
(^client/(\d+)/$, app_views.client)
If this apps URLconf is included into the projects URLconf under a path such as this:
(^clients/, include(project_name.app_name.urls))
...then, in a template, you can create a link to this view like this:
{% url app_views.client client.id %}
The template tag will output the string /clients/client/123/. New in version 1.0: Please, see the release notes If youre using named URL patterns, you can refer to the name of the pattern in the url tag instead of using the path to the view. Note that if the URL youre reversing doesnt exist, youll get an NoReverseMatch exception raised, which will cause your site to display an error page. New in version 1.0: Please, see the release notes If youd like to retrieve a URL without displaying it, you can use a slightly different call:
{% url path.to.view arg arg2 as the_url %} <a href="{{ the_url }}">Im linking to {{ the_url }}</a>
This {% url ... as var %} syntax will not cause an error if the view is missing. In practice youll use this to link to views that are optional:
{% url path.to.view as the_url %} {% if the_url %} <a href="{{ the_url }}">Link to optional stuff</a> {% endif %}
New in version 1.1: Please, see the release notes If youd like to retrieve a namespaced URL, specify the fully qualied name:
{% url myapp:view-name %}
This will follow the normal namespaced URL resolution strategy, including using any hints provided by the context as to the current application. Changed in version 1.2: Please, see the release notes For backwards compatibility, the {% url %} tag also supports the use of commas to separate arguments. You shouldnt use this in any new projects, but for the sake of the people who are still using it, heres what it looks like:
{% url path.to.view arg,arg2 %} {% url path.to.view arg, arg2 %}
This syntax doesnt support the use of literal commas, or or equals signs. Did we mention you shouldnt use this syntax in any new projects?
845
widthratio For creating bar charts and such, this tag calculates the ratio of a given value to a maximum value, and then applies that ratio to a constant. For example:
<img src="bar.gif" height="10" width="{% widthratio this_value max_value 100 %}" />
Above, if this_value is 175 and max_value is 200, the image in the above example will be 88 pixels wide (because 175/200 = .875; .875 * 100 = 87.5 which is rounded up to 88). with New in version 1.0: Please, see the release notes Caches a complex variable under a simpler name. This is useful when accessing an expensive method (e.g., one that hits the database) multiple times. For example:
{% with business.employees.count as total %} {{ total }} employee{{ total|pluralize }} {% endwith %}
The populated variable (in the example above, total) is only available between the {% with %} and {% endwith %} tags.
If value is 4, then the output will be 6. Changed in version 1.2: The following behavior didnt exist in previous Django versions. This lter will rst try to coerce both values to integers. If this fails, itll attempt to add the values together anyway. This will work on some data types (strings, list, etc.) and fail on others. If it fails, the result will be an empty string. For example, if we have:
{{ first|add:second }}
and first is [1, 2, 3] and second is [4, 5, 6], then the output will be [1, 2, 3, 4, 5, 6]. Warning: Keep in mind that strings that can both be coerced to integers will be, and thus will be will be summed, not concatenated, as in the rst example above.
846
addslashes Adds slashes before quotes. Useful for escaping strings in CSV, for example. For example:
{{ value|addslashes }}
If value is "Im using Django", the output will be "I\m using Django". caprst Capitalizes the rst character of the value. For example:
{{ value|capfirst }}
If value is "django", the output will be "Django". center Centers the value in a eld of a given width. For example:
"{{ value|center:"15" }}"
If value is "Django", the output will be " Django ". cut Removes all values of arg from the given string. For example:
{{ value|cut:" "}}
If value is "String with spaces", the output will be "Stringwithspaces". date Formats a date according to the given format. Given format can be one of the predened ones DATE_FORMAT, DATETIME_FORMAT, SHORT_DATE_FORMAT or SHORT_DATETIME_FORMAT, or a custom format, same as the now tag. Note that predened formats may vary depending on the current locale. For example:
{{ value|date:"D d M Y" }}
847
If value is a datetime object (e.g., the result of datetime.datetime.now()), the output will be the string Wed 09 Jan 2008. Another example: Assuming that USE_L10N is True and LANGUAGE_CODE is, for example, "es", then for:
{{ value|date:"SHORT_DATE_FORMAT" }}
the output will be the string "09/01/2008" (The "SHORT_DATE_FORMAT" format specier for the es locale as shipped with Django is "d/m/Y"). When used without a format string:
{{ value|date }}
...the formatting string dened in the DATE_FORMAT setting will be used, without applying any localization. Changed in version 1.2: Predened formats can now be inuenced by the current locale. default If value evaluates to False, use given default. Otherwise, use the value. For example:
{{ value|default:"nothing" }}
If value is "" (the empty string), the output will be nothing. default_if_none If (and only if) value is None, use given default. Otherwise, use the value. Note that if an empty string is given, the default value will not be used. Use the default lter if you want to fallback for empty strings. For example:
{{ value|default_if_none:"nothing" }}
If value is None, the output will be the string "nothing". dictsort Takes a list of dictionaries and returns that list sorted by the key given in the argument. For example:
{{ value|dictsort:"name" }}
If value is:
848
[ {name: zed, age: 19}, {name: amy, age: 22}, {name: joe, age: 31}, ]
dictsortreversed Takes a list of dictionaries and returns that list sorted in reverse order by the key given in the argument. This works exactly the same as the above lter, but the returned value will be in reverse order. divisibleby Returns True if the value is divisible by the argument. For example:
{{ value|divisibleby:"3" }}
If value is 21, the output would be True. escape Escapes a strings HTML. Specically, it makes these replacements: < is converted to < > is converted to > (single quote) is converted to ' " (double quote) is converted to " & is converted to & The escaping is only applied when the string is output, so it does not matter where in a chained sequence of lters you put escape: it will always be applied as though it were the last lter. If you want escaping to be applied immediately, use the force_escape lter. Applying escape to a variable that would normally have auto-escaping applied to the result will only result in one round of escaping being done. So it is safe to use this function even in auto-escaping environments. If you want multiple escaping passes to be applied, use the force_escape lter. Changed in version 1.0: Due to auto-escaping, the behavior of this lter has changed slightly. The replacements are only made once, after all other lters are applied including lters before and after it.
849
escapejs New in version 1.0: Please, see the release notes Escapes characters for use in JavaScript strings. This does not make the string safe for use in HTML, but does protect you from syntax errors when using templates to generate JavaScript/JSON. For example:
{{ value|escapejs }}
If value is "testing\r\njavascript \string" <b>escaping</b>", the output will be "testing\\u000D\\u000Ajavascript \\u0027string\\u0022 \\u003Cb\\u003Eescaping\\u003C/b\\u003E". lesizeformat Format the value like a human-readable le size (i.e. 13 KB, 4.1 MB, 102 bytes, etc). For example:
{{ value|filesizeformat }}
If value is 123456789, the output would be 117.7 MB. rst Returns the rst item in a list. For example:
{{ value|first }}
If value is the list [a, b, c], the output will be a. x_ampersands Changed in version 1.0: This is rarely useful as ampersands are now automatically escaped. See escape for more information. Replaces ampersands with & entities. For example:
{{ value|fix_ampersands }}
If value is Tom & Jerry, the output will be Tom & Jerry. oatformat When used without an argument, rounds a oating-point number to one decimal place but only if theres a decimal part to be displayed. For example:
850
If used with a numeric integer argument, floatformat rounds a number to that many decimal places. For example: value 34.23234 34.00000 34.26000 Template {{ value|floatformat:3 }} {{ value|floatformat:3 }} {{ value|floatformat:3 }} Output 34.232 34.000 34.260
If the argument passed to floatformat is negative, it will round a number to that many decimal places but only if theres a decimal part to be displayed. For example: value 34.23234 34.00000 34.26000 Template {{ value|floatformat:"-3" }} {{ value|floatformat:"-3" }} {{ value|floatformat:"-3" }} Output 34.232 34 34.260
Using floatformat with no argument is equivalent to using floatformat with an argument of -1. force_escape New in version 1.0: Please, see the release notes Applies HTML escaping to a string (see the escape lter for details). This lter is applied immediately and returns a new, escaped string. This is useful in the rare cases where you need multiple escaping or want to apply other lters to the escaped results. Normally, you want to use the escape lter. get_digit Given a whole number, returns the requested digit, where 1 is the right-most digit, 2 is the second-right-most digit, etc. Returns the original value for invalid input (if input or argument is not an integer, or if argument is less than 1). Otherwise, output is always an integer. For example:
{{ value|get_digit:"2" }}
If value is 123456789, the output will be 8. iriencode Converts an IRI (Internationalized Resource Identier) to a string that is suitable for including in a URL. This is necessary if youre trying to use strings containing non-ASCII characters in a URL. Its safe to use this lter on a string that has already gone through the urlencode lter. For example:
{{ value|iriencode }}
851
join Joins a list with a string, like Pythons str.join(list) For example:
{{ value|join:" // " }}
If value is the list [a, b, c], the output will be the string "a // b // c". last New in version 1.0: Please, see the release notes Returns the last item in a list. For example:
{{ value|last }}
If value is the list [a, b, c, d], the output will be the string "d". length Returns the length of the value. This works for both strings and lists. For example:
{{ value|length }}
If value is [a, b, c, d], the output will be 4. length_is Returns True if the values length is the argument, or False otherwise. For example:
{{ value|length_is:"4" }}
If value is [a, b, c, d], the output will be True. linebreaks Replaces line breaks in plain text with appropriate HTML; a single newline becomes an HTML line break (<br />) and a new line followed by a blank line becomes a paragraph break (</p>). For example:
{{ value|linebreaks }}
852
linebreaksbr Converts all newlines in a piece of plain text to HTML line breaks (<br />). For example:
{{ value|linebreaksbr }}
If value is Joel\nis a slug, the output will be Joel<br />is a slug. linenumbers Displays text with line numbers. For example:
{{ value|linenumbers }}
If value is:
one two three
ljust Left-aligns the value in a eld of a given width. Argument: eld size For example:
"{{ value|ljust:"10" }}"
If value is Django, the output will be "Django ". lower Converts a string into all lowercase. For example:
{{ value|lower }}
If value is Still MAD At Yoko, the output will be still mad at yoko.
853
make_list Returns the value turned into a list. For an integer, its a list of digits. For a string, its a list of characters. For example:
{{ value|make_list }}
If value is the string "Joel", the output would be the list [uJ, uo, ue, ul]. If value is 123, the output will be the list [1, 2, 3]. phone2numeric Converts a phone number (possibly containing letters) to its numerical equivalent. The input doesnt have to be a valid phone number. This will happily convert any string. For example:
{{ value|phone2numeric }}
If value is 800-COLLECT, the output will be 800-2655328. pluralize Returns a plural sufx if the value is not 1. By default, this sufx is s. Example:
You have {{ num_messages }} message{{ num_messages|pluralize }}.
If num_messages is 1, the output will be You have 1 message. If num_messages is 2 the output will be You have 2 messages. For words that require a sufx other than s, you can provide an alternate sufx as a parameter to the lter. Example:
You have {{ num_walruses }} walrus{{ num_walruses|pluralize:"es" }}.
For words that dont pluralize by simple sufx, you can specify both a singular and plural sufx, separated by a comma. Example:
You have {{ num_cherries }} cherr{{ num_cherries|pluralize:"y,ies" }}.
854
random Returns a random item from the given list. For example:
{{ value|random }}
If value is the list [a, b, c, d], the output could be "b". removetags Removes a space-separated list of [X]HTML tags from the output. For example:
{{ value|removetags:"b span"|safe }}
If value is "<b>Joel</b> <button>is</button> a <span>slug</span>" the output will be "Joel <button>is</button> a slug". rjust Right-aligns the value in a eld of a given width. Argument: eld size For example:
"{{ value|rjust:"10" }}"
If value is Django, the output will be " Django". safe Marks a string as not requiring further HTML escaping prior to output. When autoescaping is off, this lter has no effect. Note: If you are chaining lters, a lter applied after safe can make the contents unsafe again. For example, the following code prints the variable as is, unescaped:
{{ var|safe|escape }}
safeseq Applies the safe lter to each element of a sequence. Useful in conjunction with other lters that operate on sequences, such as join. For example:
{{ some_list|safeseq|join:", " }}
You couldnt use the safe lter directly in this case, as it would rst convert the variable into a string, rather than working with the individual elements of the sequence.
855
slice Returns a slice of the list. Uses the same syntax as Pythons list slicing. See http://diveintopython.org/native_data_types/lists.html#odbchelper.list.slice for an introduction. Example:
{{ some_list|slice:":2" }}
If some_list is [a, b, c], the output will be [a, b]. slugify Converts to lowercase, removes non-word characters (alphanumerics and underscores) and converts spaces to hyphens. Also strips leading and trailing whitespace. For example:
{{ value|slugify }}
If value is "Joel is a slug", the output will be "joel-is-a-slug". stringformat Formats the variable according to the argument, a string formatting specier. This specier uses Python string formatting syntax, with the exception that the leading % is dropped. See http://docs.python.org/library/stdtypes.html#string-formatting-operations for documentation of Python string formatting For example:
{{ value|stringformat:"s" }}
If value is "Joel is a slug", the output will be "Joel is a slug". striptags Strips all [X]HTML tags. For example:
{{ value|striptags }}
856
time Formats a time according to the given format. Given format can be the predened one TIME_FORMAT, or a custom format, same as the now tag. Note that the predened format is locale- dependant. The time lter will only accept parameters in the format string that relate to the time of day, not the date (for obvious reasons). If you need to format a date, use the date lter. For example:
{{ value|time:"H:i" }}
If value is equivalent to datetime.datetime.now(), the output will be the string "01:23". Another example: Assuming that USE_L10N is True and LANGUAGE_CODE is, for example, "de", then for:
{{ value|time:"TIME_FORMAT" }}
the output will be the string "01:23:00" (The "TIME_FORMAT" format specier for the de locale as shipped with Django is "H:i:s"). When used without a format string:
{{ value|time }}
...the formatting string dened in the TIME_FORMAT setting will be used, without applying any localization. Changed in version 1.2: Predened formats can now be inuenced by the current locale. timesince Formats a date as the time since that date (e.g., 4 days, 6 hours). Takes an optional argument that is a variable containing the date to use as the comparison point (without the argument, the comparison point is now). For example, if blog_date is a date instance representing midnight on 1 June 2006, and comment_date is a date instance for 08:00 on 1 June 2006, then {{ blog_date|timesince:comment_date }} would return 8 hours. Comparing offset-naive and offset-aware datetimes will return an empty string. Minutes is the smallest unit used, and 0 minutes will be returned for any date that is in the future relative to the comparison point. timeuntil Similar to timesince, except that it measures the time from now until the given date or datetime. For example, if today is 1 June 2006 and conference_date is a date instance holding 29 June 2006, then {{ conference_date|timeuntil }} will return 4 weeks. Takes an optional argument that is a variable containing the date to use as the comparison point (instead of now). If from_date contains 22 June 2006, then {{ conference_date|timeuntil:from_date }} will return 1 week. Comparing offset-naive and offset-aware datetimes will return an empty string.
857
Minutes is the smallest unit used, and 0 minutes will be returned for any date that is in the past relative to the comparison point. title Converts a string into titlecase. For example:
{{ value|title }}
If value is "my first post", the output will be "My First Post". truncatewords Truncates a string after a certain number of words. Argument: Number of words to truncate after For example:
{{ value|truncatewords:2 }}
If value is "Joel is a slug", the output will be "Joel is ...". truncatewords_html Similar to truncatewords, except that it is aware of HTML tags. Any tags that are opened in the string and not closed before the truncation point, are closed immediately after the truncation. This is less efcient than truncatewords, so should only be used when it is being passed HTML text. For example:
{{ value|truncatewords_html:2 }}
If value is "<p>Joel is a slug</p>", the output will be "<p>Joel is ...</p>". unordered_list Recursively takes a self-nested list and returns an HTML unordered list WITHOUT opening and closing <ul> tags. Changed in version 1.0: The format accepted by unordered_list has changed to be easier to understand. The list is assumed to be in the proper format. For example, if var contains [States, [Kansas, [Lawrence, Topeka], Illinois]], then {{ var|unordered_list }} would return:
<li>States <ul> <li>Kansas <ul> <li>Lawrence</li> <li>Topeka</li> </ul> </li> <li>Illinois</li>
858
</ul> </li>
Note: the previous more restrictive and verbose format is still supported: [States, [[Kansas, [[Lawrence, []], [Topeka, []]]], [Illinois, []]]], upper Converts a string into all uppercase. For example:
{{ value|upper }}
If value is "Joel is a slug", the output will be "JOEL IS A SLUG". urlencode Escapes a value for use in a URL. For example:
{{ value|urlencode }}
If value is "http://www.example.org/foo?a=b&c=d", "http%3A//www.example.org/foo%3Fa%3Db%26c%3Dd". urlize Converts URLs in plain text into clickable links.
the
output
will
be
Note that if urlize is applied to text that already contains HTML markup, things wont work as expected. Apply this lter only to plain text. For example:
{{ value|urlize }}
If value is "Check out www.djangoproject.com", the output will be href="http://www.djangoproject.com">www.djangoproject.com</a>". urlizetrunc Converts URLs into clickable links, truncating URLs longer than the given character limit. As with urlize, this lter should only be applied to plain text. Argument: Length to truncate URLs to For example:
{{ value|urlizetrunc:15 }}
859
If value is "Check out www.djangoproject.com", the output would be Check out <a href="http://www.djangoproject.com">www.djangopr...</a>. wordcount Returns the number of words. For example:
{{ value|wordcount }}
If value is "Joel is a slug", the output will be 4. wordwrap Wraps words at specied line length. Argument: number of characters at which to wrap the text For example:
{{ value|wordwrap:5 }}
yesno Given a string mapping values for true, false and (optionally) None, returns one of those strings according to the value: Value True False None None Argument "yeah,no,maybe" "yeah,no,maybe" "yeah,no,maybe" "yeah,no" Outputs yeah no maybe "no" (converts None to False if no mapping for None is given)
860
django.contrib.markup A collection of template lters that implement these common markup languages: Textile Markdown ReST (ReStructured Text) See markup. django.contrib.webdesign A collection of template tags that can be useful while designing a website, such as a generator of Lorem Ipsum text. See django.contrib.webdesign. i18n Provides a couple of templatetags that allow specifying translatable text in Django templates. It is slightly different from the libraries described above because you dont need to add any application to the INSTALLED_APPS setting but rather set USE_I18N to True, then loading it with {% load i18n %}. See Specifying translation strings: In template code.
61.2.1 Basics
A template is a text document, or a normal Python string, that is marked-up using the Django template language. A template can contain block tags or variables. A block tag is a symbol within a template that does something. This denition is deliberately vague. For example, a block tag can output content, serve as a control structure (an if statement or for loop), grab content from a database or enable access to other template tags. Block tags are surrounded by "{%" and "%}". Example template with block tags:
{% if is_logged_in %}Thanks for logging in!{% else %}Please log in.{% endif %}
A variable is a symbol within a template that outputs a value. Variable tags are surrounded by "{{" and "}}". Example template with variables:
My first name is {{ first_name }}. My last name is {{ last_name }}.
861
A context is a variable name -> variable value mapping that is passed to a template. A template renders a context by replacing the variable holes with values from the context and executing all block tags.
Behind the scenes The system only parses your raw template code once when you create the Template object. From then on, its stored internally as a node structure for performance. Even the parsing itself is quite fast. Most of the parsing happens via a single call to a single, short, regular expression. Rendering a context Once you have a compiled Template object, you can render a context or multiple contexts with it. The Context class lives at django.template.Context, and the constructor takes two (optional) arguments: A dictionary mapping variable names to variable values. The name of the current application. This application name is used to help resolve namespaced URLs. If youre not using namespaced URLs, you can ignore this argument. Call the Template objects render() method with the context to ll the template:
>>> from django.template import Context, Template >>> t = Template("My name is {{ my_name }}.") >>> c = Context({"my_name": "Adrian"}) >>> t.render(c) "My name is Adrian." >>> c = Context({"my_name": "Dolores"}) >>> t.render(c) "My name is Dolores."
Variable names must consist of any letter (A-Z), any digit (0-9), an underscore or a dot. Dots have a special meaning in template rendering. A dot in a variable name signies lookup. Specically, when the template system encounters a dot in a variable name, it tries the following lookups, in this order:
862
Dictionary lookup. Example: foo["bar"] Attribute lookup. Example: foo.bar Method call. Example: foo.bar() List-index lookup. Example: foo[bar] The template system uses the rst lookup type that works. Its short-circuit logic. Here are a few examples:
>>> >>> >>> >>> "My >>> >>> >>> >>> >>> "My >>> ... ... >>> >>> "My from django.template import Context, Template t = Template("My name is {{ person.first_name }}.") d = {"person": {"first_name": "Joe", "last_name": "Johnson"}} t.render(Context(d)) name is Joe." class PersonClass: pass p = PersonClass() p.first_name = "Ron" p.last_name = "Nasty" t.render(Context({"person": p})) name is Ron." class PersonClass2: def first_name(self): return "Samantha" p = PersonClass2() t.render(Context({"person": p})) name is Samantha."
>>> t = Template("The first stooge in the list is {{ stooges.0 }}.") >>> c = Context({"stooges": ["Larry", "Curly", "Moe"]}) >>> t.render(c) "The first stooge in the list is Larry."
Method lookups 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. 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(Exception): ... silent_variable_failure = True >>> class PersonClass4: ... def first_name(self): ... raise SilentAssertionError >>> p = PersonClass4()
863
Note that django.core.exceptions.ObjectDoesNotExist, which is the base class for all Django database API DoesNotExist exceptions, has silent_variable_failure = True. So if youre using Django templates with Django model objects, any DoesNotExist exception will fail silently. 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 itd be either foolish or a security hole to allow the template system to access them. A good example is the delete() method on each Django model object. The template system shouldnt be allowed to do something like this:
I will now delete this valuable data. {{ data.delete }}
To prevent this, set a function attribute alters_data on the method. The template system wont execute a method if the method has alters_data=True set. The dynamically-generated delete() and save() methods on Django model objects get alters_data=True automatically. Example:
def sensitive_function(self): self.database_record.delete() sensitive_function.alters_data = True
Filters that are applied to an invalid variable will only be applied if TEMPLATE_STRING_IF_INVALID is set to (the empty string). If TEMPLATE_STRING_IF_INVALID is set to any other value, variable lters will be ignored. This behavior is slightly different for the if, for and regroup template tags. If an invalid variable is provided to one of these template tags, the variable will be interpreted as None. Filters are always applied to invalid variables within these template tags. If TEMPLATE_STRING_IF_INVALID contains a %s, the format marker will be replaced with the name of the invalid variable. For debug purposes only! While TEMPLATE_STRING_IF_INVALID can be a useful debugging tool, it is a bad idea to turn it on as a development default. Many templates, including those in the Admin site, rely upon the silence of the template system when a non-existent variable is encountered. If you assign a value other than to TEMPLATE_STRING_IF_INVALID, you will experience rendering problems with these templates and sites. Generally, TEMPLATE_STRING_IF_INVALID should only be enabled in order to debug a specic template problem, then cleared once debugging is complete. Playing with Context objects Most of the time, youll instantiate Context objects by passing in a fully-populated dictionary to Context(). But you can add and delete items from a Context object once its been instantiated, too, using standard dictionary syntax: 864 Chapter 61. Templates
>>> c = Context({"foo": "bar"}) >>> c[foo] bar >>> del c[foo] >>> c[foo] >>> c[newvariable] = hello >>> c[newvariable] hello
A Context object is a stack. That is, you can push() and pop() it. If you pop() too much, itll raise django.template.ContextPopException:
>>> c = Context() >>> c[foo] = first level >>> c.push() >>> c[foo] = second level >>> c[foo] second level >>> c.pop() >>> c[foo] first level >>> c[foo] = overwritten >>> c[foo] overwritten >>> c.pop() Traceback (most recent call last): ... django.template.ContextPopException
Using a Context as a stack comes in handy in some custom template tags, as youll see below. Subclassing Context: RequestContext Django comes with a special Context class, django.template.RequestContext, that acts slightly differently than the normal django.template.Context. The rst difference is that it takes an HttpRequest as its rst argument. For example:
c = RequestContext(request, { foo: bar, })
The second difference is that it automatically populates the context with a few variables, according to your TEMPLATE_CONTEXT_PROCESSORS setting. The TEMPLATE_CONTEXT_PROCESSORS setting is a tuple of callables called context processors that take a request object as their argument and return a dictionary of items to be merged into the context. By default, TEMPLATE_CONTEXT_PROCESSORS is set to:
("django.contrib.auth.context_processors.auth", "django.core.context_processors.debug", "django.core.context_processors.i18n", "django.core.context_processors.media", "django.contrib.messages.context_processors.messages")
865
New in version 1.2: In addition to these, RequestContext always uses django.core.context_processors.csrf. This is a security related context processor required by the admin and other contrib apps, and, in case of accidental misconguration, it is deliberately hardcoded in and cannot be turned off by the TEMPLATE_CONTEXT_PROCESSORS setting.New in version 1.2: The messages context processor was added. For more information, see the messages documentation.Changed in version 1.2: The auth context processor was moved in this release from its old location django.core.context_processors.auth to django.contrib.auth.context_processors.auth. Each processor is applied in order. That means, if one processor adds a variable to the context and a second processor adds a variable with the same name, the second will override the rst. The default processors are explained below. When context processors are applied When you use RequestContext, the variables you supply directly are added rst, followed any variables supplied by context processors. This means that a context processor may overwrite a variable youve supplied, so take care to avoid variable names which overlap with those supplied by your context processors. Also, you can give RequestContext a list of additional processors, using the optional, third positional argument, processors. In this example, the RequestContext instance gets a ip_address variable:
def ip_address_processor(request): return {ip_address: request.META[REMOTE_ADDR]} def some_view(request): # ... c = RequestContext(request, { foo: bar, }, [ip_address_processor]) return HttpResponse(t.render(c))
Note: If youre using Djangos render_to_response() shortcut to populate a template with the contents of a dictionary, your template will be passed a Context instance by default (not a RequestContext). To use a RequestContext in your template rendering, pass an optional third argument to render_to_response(): a RequestContext instance. Your code might look like this:
def some_view(request): # ... return render_to_response(my_template.html, my_data_dictionary, context_instance=RequestContext(request))
django.contrib.auth.context_processors.auth
If TEMPLATE_CONTEXT_PROCESSORS contains this processor, every RequestContext will contain these three variables: user An auth.User instance representing the currently logged-in user (or an AnonymousUser instance, if the client isnt logged in). messages A list of messages (as strings) that have been set via the messages framework. perms An instance of django.core.context_processors.PermWrapper, representing the permissions that the currently logged-in user has. Changed in version 1.2: This context processor was moved in this release from django.core.context_processors.auth to its current location.Changed in version 1.2: Prior to
866
version 1.2, the messages variable was a lazy accessor for user.get_and_delete_messages(). It has been changed to include any messages added via the messages framework.
django.core.context_processors.debug
If TEMPLATE_CONTEXT_PROCESSORS contains this processor, every RequestContext will contain these two variables but only if your DEBUG setting is set to True and the requests IP address (request.META[REMOTE_ADDR]) is in the INTERNAL_IPS setting: debug True. You can use this in templates to test whether youre in DEBUG mode. sql_queries A list of {sql: ..., time: ...} dictionaries, representing every SQL query that has happened so far during the request and how long it took. The list is in order by query.
django.core.context_processors.i18n
If TEMPLATE_CONTEXT_PROCESSORS contains this processor, every RequestContext will contain these two variables: LANGUAGES The value of the LANGUAGES setting. LANGUAGE_CODE request.LANGUAGE_CODE, if it exists. LANGUAGE_CODE setting. See Internationalization and localization for more. Otherwise, the value of the
django.core.context_processors.media
New in version 1.0: Please, see the release notes If TEMPLATE_CONTEXT_PROCESSORS contains this processor, every RequestContext will contain a variable MEDIA_URL, providing the value of the MEDIA_URL setting.
django.core.context_processors.csrf
New in version 1.2: Please, see the release notes This processor adds a token that is needed by the csrf_token template tag for protection against Cross Site Request Forgeries.
django.core.context_processors.request
If TEMPLATE_CONTEXT_PROCESSORS contains this processor, every RequestContext will contain a variable request, which is the current HttpRequest. Note that this processor is not enabled by default; youll have to activate it.
django.contrib.messages.context_processors.messages
If TEMPLATE_CONTEXT_PROCESSORS contains this processor, every RequestContext will contain a single additional variable: messages A list of messages (as strings) that have been set via the user model (using user.message_set.create) or through the messages framework.
867
New in version 1.2: This template context variable was previously supplied by the auth context processor. For backwards compatibility the auth context processor will continue to supply the messages variable until Django 1.4. If you use the messages variable, your project will work with either (or both) context processors, but it is recommended to add django.contrib.messages.context_processors.messages so your project will be prepared for the future upgrade.
Your templates can go anywhere you want, as long as the directories and templates are readable by the Web server. They can have any extension you want, such as .html or .txt, or they can have no extension at all. Note that these paths should use Unix-style forward slashes, even on Windows.
/home/html/templates/default/story_detail.html If you call select_template([story_253_detail.html, story_detail.html]), heres what Django will look for: /home/html/templates/lawrence.com/story_253_detail.html /home/html/templates/default/story_253_detail.html /home/html/templates/lawrence.com/story_detail.html /home/html/templates/default/story_detail.html When Django nds a template that exists, it stops looking. Tip You can use select_template() for super-exible templatability. For example, if youve written a news story and want some stories to have custom templates, use something like select_template([story_%s_detail.html % story.id, story_detail.html]). Thatll allow you to use a custom template for an individual story, with a fallback template for stories that dont have custom templates.
Using subdirectories
Its possible and preferable to organize templates in subdirectories of the template directory. The convention is to make a subdirectory for each Django app, with subdirectories within those subdirectories as needed. Do this for your own sanity. Storing all templates in the root level of a single directory gets messy. To load a template thats within a subdirectory, just use a slash, like so:
get_template(news/story_detail.html)
Using the same TEMPLATE_DIRS setting from above, this example get_template() call will attempt to load the following templates: /home/html/templates/lawrence.com/news/story_detail.html /home/html/templates/default/news/story_detail.html
Loader types
By default, Django uses a lesystem-based template loader, but Django comes with a few other template loaders, which know how to load templates from other sources. Some of these other loaders are disabled by default, but you can activate them by editing your TEMPLATE_LOADERS setting. TEMPLATE_LOADERS should be a tuple of strings, where each string represents a template loader. Here are the template loaders that come with Django: django.template.loaders.filesystem.Loader Loads templates from the lesystem, according to TEMPLATE_DIRS. This loader is enabled by default. django.template.loaders.app_directories.Loader Loads templates from Django apps on the lesystem. For each app in INSTALLED_APPS, the loader looks for a templates subdirectory. If the directory exists, Django looks for templates in there. This means you can store templates with your individual apps. This also makes it easy to distribute Django apps with default templates.
869
...then get_template(foo.html) will look for templates in these directories, in this order: /path/to/myproject/polls/templates/foo.html /path/to/myproject/music/templates/foo.html Note that the loader performs an optimization when it is rst imported: INSTALLED_APPS packages have a templates subdirectory. This loader is enabled by default. django.template.loaders.eggs.Loader Just like app_directories above, but it loads templates from Python eggs rather than from the lesystem. This loader is disabled by default. django.template.loaders.cached.Loader By default, the templating system will read and compile your templates every time they need to be rendered. While the Django templating system is quite fast, the overhead from reading and compiling templates can add up. The cached template loader is a class-based loader that you congure with a list of other loaders that it should wrap. The wrapped loaders are used to locate unknown templates when they are rst encountered. The cached loader then stores the compiled Template in memory. The cached Template instance is returned for subsequent requests to load the same template. For example, to enable template caching with the filesystem and app_directories template loaders you might use the following settings:
TEMPLATE_LOADERS = ( (django.template.loaders.cached.Loader, ( django.template.loaders.filesystem.Loader, django.template.loaders.app_directories.Loader, )), )
Note: All of the built-in Django template tags are safe to use with the cached loader, but if youre using custom template tags that come from third party packages, or that you wrote yourself, you should ensure that the Node implementation for each tag is thread-safe. For more information, see template tag thread safety considerations. This loader is disabled by default. Django uses the template loaders in order according to the TEMPLATE_LOADERS setting. It uses each loader until a loader nds a match.
870
The render_to_string shortcut takes one required argument template_name, which should be the name of the template to load and render (or a list of template names, in which case Django will use the rst template in the list that exists) and two optional arguments: dictionary A dictionary to be used as variables and values for the templates context. This can also be passed as the second positional argument. context_instance An instance of Context or a subclass (e.g., an instance of RequestContext) to use as the templates context. This can also be passed as the third positional argument. See also the render_to_response() shortcut, which calls render_to_string and feeds the result into an HttpResponse suitable for returning directly from a view.
871
Thats all thats required to make our ctional Template class compatible with the Django loading and rendering system! The next step is to write a Loader class that returns instances of our custom template class instead of the default django.template.Template. Custom Loader classes should inherit from django.template.loader.BaseLoader and override the load_template_source() method, which takes a template_name argument, loads the template from disk (or elsewhere), and returns a tuple: (template_string, template_origin). The load_template() method of the Loader class retrieves the template string by calling load_template_source(), instantiates a Template from the template source, and returns a tuple: (template, template_origin). Since this is the method that actually instantiates the Template, well need to override it to use our custom template class instead. We can inherit from the builtin django.template.loaders.app_directories.Loader to take advantage of the load_template_source() method implemented there:
from django.template.loaders import app_directories class Loader(app_directories.Loader): is_usable = True def load_template(self, template_name, template_dirs=None): source, origin = self.load_template_source(template_name, template_dirs) template = Template(source) return template, origin
Finally, we need to modify our project settings, telling Django to use our custom loader. Now we can write all of our templates in our alternative template language while continuing to use the rest of the Django templating system. See Also: For information on writing your own custom tags and lters, see Custom template tags and lters.
872
CHAPTER
SIXTYTWO
UNICODE DATA
New in version 1.0: Please, see the release notes Django natively supports Unicode data everywhere. Providing your database can somehow store the data, you can safely pass around Unicode strings to templates, models and the database. This document tells you what you need to know if youre writing applications that use data or templates that are encoded in something other than ASCII.
873
If your code only uses ASCII data, its safe to use your normal strings, passing them around at will, because ASCII is a subset of UTF-8. Dont be fooled into thinking that if your DEFAULT_CHARSET setting is set to something other than utf-8 you can use that other encoding in your bytestrings! DEFAULT_CHARSET only applies to the strings generated as the result of template rendering (and e-mail). Django will always assume UTF-8 encoding for internal bytestrings. The reason for this is that the DEFAULT_CHARSET setting is not actually under your control (if you are the application developer). Its under the control of the person installing and using your application and if that person chooses a different setting, your code must still continue to work. Ergo, it cannot rely on that setting. In most cases when Django is dealing with strings, it will convert them to Unicode strings before doing anything else. So, as a general rule, if you pass in a bytestring, be prepared to receive a Unicode string back in the result.
874
smart_str(s, encoding=utf-8, strings_only=False, errors=strict) is essentially the opposite of smart_unicode(). It forces the rst argument to a bytestring. The strings_only parameter has the same behavior as for smart_unicode() and force_unicode(). This is slightly different semantics from Pythons builtin str() function, but the difference is needed in a few places within Djangos internals. Normally, youll only need to use smart_unicode(). Call it as early as possible on any input data that might be either Unicode or a bytestring, and from then on, you can treat the result as always being Unicode. URI and IRI handling Web frameworks have to deal with URLs (which are a type of IRI). One requirement of URLs is that they are encoded using only ASCII characters. However, in an international environment, you might need to construct a URL from an IRI very loosely speaking, a URI that can contain Unicode characters. Quoting and converting an IRI to URI can be a little tricky, so Django provides some assistance. The function django.utils.encoding.iri_to_uri() implements the conversion from IRI to URI as required by the specication (RFC 3987). The functions django.utils.http.urlquote() and django.utils.http.urlquote_plus() are versions of Pythons standard urllib.quote() and urllib.quote_plus() that work with nonASCII characters. (The data is converted to UTF-8 prior to encoding.) These two groups of functions have slightly different purposes, and its important to keep them straight. Normally, you would use urlquote() on the individual portions of the IRI or URI path so that any reserved characters such as & or % are correctly encoded. Then, you apply iri_to_uri() to the full IRI and it converts any non-ASCII characters to the correct encoded values. Note: Technically, it isnt correct to say that iri_to_uri() implements the full algorithm in the IRI specication. It doesnt (yet) perform the international domain name encoding portion of the algorithm. The iri_to_uri() function will not change ASCII characters that are otherwise permitted in a URL. So, for example, the character % is not further encoded when passed to iri_to_uri(). This means you can pass a full URL to this function and it will not mess up the query string or anything like that. An example might clarify things here:
>>> urlquote(uParis & Orlans) uParis%20%26%20Orl%C3%A9ans >>> iri_to_uri(u/favorites/Franois/%s % urlquote(uParis & Orlans)) /favorites/Fran%C3%A7ois/Paris%20%26%20Orl%C3%A9ans
If you look carefully, you can see that the portion that was generated by urlquote() in the second example was not double-quoted when passed to iri_to_uri(). This is a very important and useful feature. It means that you can construct your IRI without worrying about whether it contains non-ASCII characters and then, right at the end, call iri_to_uri() on the result. The iri_to_uri() function is also idempotent, which means the following is always true:
iri_to_uri(iri_to_uri(some_string)) = iri_to_uri(some_string)
So you can safely call it multiple times on the same IRI without risking double-quoting problems.
875
62.3 Models
Because all strings are returned from the database as Unicode strings, model elds that are character based (CharField, TextField, URLField, etc) will contain Unicode values when Django retrieves data from the database. This is always the case, even if the data could t into an ASCII bytestring. You can pass in bytestrings when creating a model or populating a eld, and Django will convert it to Unicode when it needs to.
This function returns a correctly encoded URL even if self.location is something like Jack visited Paris & Orlans. (In fact, the iri_to_uri() call isnt strictly necessary in the above example, because all the non-ASCII characters would have been removed in quoting in the rst line.)
876
62.5 Templates
You can use either Unicode or bytestrings when creating templates manually:
from django.template import Template t1 = Template(This is a bytestring template.) t2 = Template(uThis is a Unicode template.)
But the common case is to read templates from the lesystem, and this creates a slight complication: not all lesystems store their data encoded as UTF-8. If your template les are not stored with a UTF-8 encoding, set the FILE_CHARSET setting to the encoding of the les on disk. When Django reads in a template le, it will convert the data from this encoding to Unicode. (FILE_CHARSET is set to utf-8 by default.) The DEFAULT_CHARSET setting controls the encoding of rendered templates. This is set to UTF-8 by default.
62.6 E-mail
Djangos e-mail framework (in django.core.mail) supports Unicode transparently. You can use Unicode data in the message bodies and any headers. However, youre still obligated to respect the requirements of the e-mail specications, so, for example, e-mail addresses should use only ASCII characters. The following code example demonstrates that everything except e-mail addresses can be non-ASCII:
from django.core.mail import EmailMessage subject = uMy visit to Sr-Trndelag sender = uArnbjrg Rormsdttir <[email protected]> recipients = [Fred <[email protected]] body = u... EmailMessage(subject, body, sender, recipients).send()
62.5. Templates
877
By default, the DEFAULT_CHARSET setting is used as the assumed encoding for form data. If you need to change this for a particular form, you can set the encoding attribute on an HttpRequest instance. For example:
def some_view(request): # We know that the data must be encoded as KOI8-R (for some reason). request.encoding = koi8-r ...
You can even change the encoding after having accessed request.GET or request.POST, and all subsequent accesses will use the new encoding. Most developers wont need to worry about changing form encoding, but this is a useful feature for applications that talk to legacy systems whose encoding you cannot control. Django does not decode the data of le uploads, because that data is normally treated as collections of bytes, rather than strings. Any automatic decoding there would alter the meaning of the stream of bytes.
878
CHAPTER
SIXTYTHREE
DJANGO UTILS
This document covers all stable modules in django.utils. Most of the modules in django.utils are designed for internal use and only the following parts can be considered stable and thus backwards compatible as per the internal release deprecation policy.
63.1 django.utils.cache
This module contains helper functions for controlling caching. It does so by managing the Vary header of responses. It includes functions to patch the header of response objects directly and decorators that change functions to do that header-patching themselves. For information on the Vary header, see RFC 2616 section 14.44. Essentially, the Vary HTTP header denes which headers a cache should take into account when building its cache key. Requests with the same path but different header content for headers named in Vary need to get different cache keys to prevent delivery of wrong content. For example, internationalization middleware would need to distinguish caches by the Accept-language header. patch_cache_control(response, **kwargs) This function patches the Cache-Control header by adding all keyword arguments to it. The transformation is as follows: All keyword parameter names are turned to lowercase, and underscores are converted to hyphens. If the value of a parameter is True (exactly True, not just a true value), only the parameter name is added to the header. All other parameters are added with their value, after applying str() to it. get_max_age(response) Returns the max-age from the response Cache-Control header as an integer (or None if it wasnt found or wasnt an integer). patch_response_headers(response, cache_timeout=None) Adds some useful headers to the given HttpResponse object: ETag Last-Modified Expires Cache-Control
879
Each header is only added if it isnt already set. cache_timeout is in seconds. The CACHE_MIDDLEWARE_SECONDS setting is used by default. add_never_cache_headers(response) Adds headers to a response to indicate that a page should never be cached. patch_vary_headers(response, newheaders) Adds (or updates) the Vary header in the given HttpResponse object. newheaders is a list of header names that should be in Vary. Existing headers in Vary arent removed. get_cache_key(request, key_prex=None) Returns a cache key based on the request path. It can be used in the request phase because it pulls the list of headers to take into account from the global path registry and uses those to build a cache key to check against. If there is no headerlist stored, the page needs to be rebuilt, so this function returns None. learn_cache_key(request, response, cache_timeout=None, key_prex=None) Learns what headers to take into account for some request path from the response object. It stores those headers in a global path registry so that later access to that path will know what headers to take into account without building the response object itself. The headers are named in the Vary header of the response, but we want to prevent response generation. The list of headers to use for cache key generation is stored in the same cache as the pages themselves. If the cache ages some data out of the cache, this just means that we have to build the response once to get at the Vary header and so at the list of headers to use for the cache key.
63.2 SortedDict
class SortedDict()
63.2.1 Methods
Extra methods that SortedDict adds to the standard Python dict class. insert(index, key, value) Inserts the key, value pair before the item with the given index. value_for_index(index) Returns the value of the item at the given zero-based index.
will not work. Passing in a basic Python dict could produce unreliable results. Instead do:
SortedDict([(b, 1), (a, 2), (c, 3)])
880
63.3 django.utils.encoding
class StrAndUnicode() A class whose __str__ returns its __unicode__ as a UTF-8 bytestring. Useful as a mix-in. smart_unicode(s, encoding=utf-8, strings_only=False, errors=strict) Returns a unicode object representing s. Treats bytestrings using the encoding codec. If strings_only is True, dont convert (some) non-string-like objects. is_protected_type(obj) Determine if the object instance is of a protected type. Objects of protected types are preserved as-is when passed to force_unicode(strings_only=True). force_unicode(s, encoding=utf-8, strings_only=False, errors=strict) Similar to smart_unicode, except that lazy instances are resolved to strings, rather than kept as lazy objects. If strings_only is True, dont convert (some) non-string-like objects. smart_str(s, encoding=utf-8, strings_only=False, errors=strict) Returns a bytestring version of s, encoded as specied in encoding. If strings_only is True, dont convert (some) non-string-like objects. iri_to_uri(iri) Convert an Internationalized Resource Identier (IRI) portion to a URI portion that is suitable for inclusion in a URL. This is the algorithm from section 3.1 of RFC 3987. However, since we are assuming input is either UTF-8 or unicode already, we can simplify things a little from the full method. Returns an ASCII string containing the encoded result.
63.4 django.utils.feedgenerator
Sample usage:
>>> >>> ... ... ... ... ... >>> ... ... ... ... >>> >>> >>> from django.utils import feedgenerator feed = feedgenerator.Rss201rev2Feed( title=u"Poynter E-Media Tidbits", link=u"http://www.poynter.org/column.asp?id=31", description=u"A group weblog by the sharpest minds in online media/journalism/publishing.", language=u"en", ) feed.add_item( title="Hello", link=u"http://www.holovaty.com/test/", description="Testing." ) fp = open(test.rss, w) feed.write(fp, utf-8) fp.close()
63.3. django.utils.encoding
881
For simplifying the selection of a generator use feedgenerator.DefaultFeed which is currently Rss201rev2Feed For denitions of the different versions of RSS, see: http://diveintomark.org/archives/2004/02/04/incompatible-rss get_tag_uri(url, date) Creates a TagURI. See http://diveintomark.org/archives/2004/05/28/howto-atom-id
63.4.1 SyndicationFeed
class SyndicationFeed() Base class for all syndication feeds. Subclasses should provide write(). Methods add_item(title, link, description, [author_email=None, author_name=None, author_link=None, pubdate=None, comments=None, unique_id=None, enclosure=None, categories=(), item_copyright=None, ttl=None, **kwargs]) Adds an item to the feed. All args are expected to be Python unicode objects except pubdate, which is a datetime.datetime object, and enclosure, which is an instance of the Enclosure class. num_items() root_attributes() Return extra attributes to place on the root (i.e. feed/channel) element. Called from write(). add_root_elements(handler) Add elements in the root (i.e. feed/channel) element. Called from write(). item_attributes(item) Return extra attributes to place on each item (i.e. item/entry) element. add_item_elements(handler, item) Add elements on each item (i.e. item/entry) element. write(outle, encoding) Outputs the feed in the given encoding to outfile, which is a le-like object. Subclasses should override this. writeString(encoding) Returns the feed in the given encoding as a string. latest_post_date() Returns the latest items pubdate. If none of them have a pubdate, this returns the current date/time.
63.4.2 Enclosure
class Enclosure() Represents an RSS enclosure
882
63.4.3 RssFeed
class RssFeed(SyndicationFeed)
63.4.4 Rss201rev2Feed
class Rss201rev2Feed(RssFeed) Spec: http://blogs.law.harvard.edu/tech/rss
63.4.5 Atom1Feed
class Atom1Feed(SyndicationFeed) Spec: http://atompub.org/2005/07/11/draft-ietf-atompub-format-10.html
63.5 django.utils.http
urlquote(url, safe=/) A version of Pythons urllib.quote() function that can operate on unicode strings. The url is rst UTF-8 encoded before quoting. The returned string can safely be used as part of an argument to a subsequent iri_to_uri() call without double-quoting occurring. Employs lazy execution. urlquote_plus(url, safe=) A version of Pythons urllib.quote_plus() function that can operate on unicode strings. The url is rst UTF-8 encoded before quoting. The returned string can safely be used as part of an argument to a subsequent iri_to_uri() call without double-quoting occurring. Employs lazy execution. urlencode(query, doseq=0) A version of Pythons urllib.urlencode() function that can operate on unicode strings. The parameters are rst case to UTF-8 encoded strings and then encoded as per normal. cookie_date(epoch_seconds=None) Formats the time to ensure compatibility with Netscapes cookie standard. Accepts a oating point number expressed in seconds since the epoch, in UTC - such as that outputted by time.time(). If set to None, defaults to the current time. Outputs a string in the format Wdy, DD-Mon-YYYY HH:MM:SS GMT. http_date(epoch_seconds=None) Formats the time to match the RFC 1123 date format as specied by HTTP RFC 2616 section 3.3.1. Accepts a oating point number expressed in seconds since the epoch, in UTC - such as that outputted by time.time(). If set to None, defaults to the current time. Outputs a string in the format Wdy, DD Mon YYYY HH:MM:SS GMT. base36_to_int(s) Converted a base 36 string to an integer int_to_base36(i) Converts an integer to a base36 string
63.5. django.utils.http
883
63.6 django.utils.safestring
Functions and classes for working with safe strings: strings that can be displayed safely without further escaping in HTML. Marking something as a safe string means that the producer of the string has already turned characters that should not be interpreted by the HTML engine (e.g. <) into the appropriate entities. class SafeString() A string subclass that has been specically marked as safe (requires no further escaping) for HTML output purposes. class SafeUnicode() A unicode subclass that has been specically marked as safe for HTML output purposes. mark_safe(s) Explicitly mark a string as safe for (HTML) output purposes. The returned object can be used everywhere a string or unicode object is appropriate. Can be called multiple times on a single string. mark_for_escaping(s) Explicitly mark a string as requiring HTML escaping upon output. Has no effect on SafeData subclasses. Can be called multiple times on a single string (the resulting escaping is only applied once).
63.7 django.utils.translation
For a complete discussion on the usage of the following see the Internationalization documentation. gettext(message) Translates message and returns it in a UTF-8 bytestring ugettext(message) Translates message and returns it in a unicode string gettext_lazy(message) ugettext_lazy(message) Same as the non-lazy versions above, but using lazy execution. See lazy translations documentation. gettext_noop(message) Marks strings for translation but doesnt translate them now. This can be used to store strings in global variables that should stay in the base language (because they might be used externally) and will be translated later. ngettext(singular, plural, number) Translates singular and plural and returns the appropriate string based on number in a UTF-8 bytestring ungettext(singular, plural, number) Translates singular and plural and returns the appropriate string based on number in a unicode string ngettext_lazy(singular, plural, number) ungettext_lazy(singular, plural, number)
884
Same as the non-lazy versions above, but using lazy execution. See lazy translations documentation. string_concat(*strings) Lazy variant of string concatenation, needed for translations that are constructed from multiple parts. activate(language) Fetches the translation object for a given tuple of application name and language and installs it as the current translation object for the current thread. deactivate() De-installs the currently active translation object so that further _ calls will resolve against the default translation object, again. deactivate_all() Makes the active translation object a NullTranslations() instance. This is useful when we want delayed translations to appear as the original string for some reason. get_language() Returns the currently selected language code. get_language_bidi() Returns selected languages BiDi layout: False = left-to-right layout True = right-to-left layout get_date_formats() Checks whether translation les provide a translation for some technical message ID to store date and time formats. If it doesnt contain one, the formats provided in the settings will be used. get_language_from_request(request) Analyzes the request to nd what language the user wants the system to show. Only languages listed in settings.LANGUAGES are taken into account. If the user requests a sublanguage where we have a main language, we send out the main language. to_locale(language) Turns a language name (en-us) into a locale name (en_US). templatize(src) Turns a Django template into something that is understood by xgettext. It does so by translating the Django translation tags into standard gettext function invocations.
63.8 django.utils.tzinfo
class FixedOffset() Fixed offset in minutes east from UTC. class LocalTimezone() Proxy timezone information from time module.
63.8. django.utils.tzinfo
885
886
CHAPTER
SIXTYFOUR
VALIDATORS
New in version 1.2: Please, see the release notes
You can add this to a model eld via the elds validators argument:
from django.db import models class MyModel(models.Model): even_field = models.IntegerField(validators=[validate_even])
Because values are converted to Python before validators are run, you can even use the same validator with forms:
from django import forms class MyForm(forms.Form): even_field = forms.IntegerField(validators=[validate_even])
887
64.3.1 RegexValidator
class RegexValidator(regex, message=None, code=None) regex The regular expression pattern to search for the provided value, or a pre-compiled regular expression. Raises a ValidationError with message and code if no match is found. message=None The error message used by ValidationError if validation fails. If no message is specied, a generic "Enter a valid value" message is used. code=None The error code used by ValidationError if validation fails. If code is not specied, "invalid" is used.
64.3.2 URLValidator
class URLValidator(verify_exists=False, validator_user_agent=URL_VALIDATOR_USER_AGENT ) A RegexValidator that ensures a value looks like a URL and optionally veries that the URL actually exists (i.e., doesnt return a 404 status code). Raises an error code of invalid if it doesnt look like a URL, and a code of invalid_link if it doesnt exist. verify_exists=False If verify_exists is True, this validator checks that the URL actually exists. validator_user_agent=URL_VALIDATOR_USER_AGENT If verify_exists is True, it uses validator_user_agent as the User-agent for the request. This defaults to settings.URL_VALIDATOR_USER_AGENT.
64.3.3 validate_email
A RegexValidator instance that ensures a value looks like an e-mail address.
64.3.4 validate_slug
A RegexValidator instance that ensures a value consists of only letters, numbers, underscores or hyphens.
64.3.5 validate_ipv4_address
A RegexValidator instance that ensures a value looks like an IPv4 address.
888
64.3.6 validate_comma_separated_integer_list
A RegexValidator instance that ensures a value is a comma-separated list of integers.
64.3.7 MaxValueValidator
class MaxValueValidator(max_value) Raises a ValidationError with a code of max_value if value is greater than max_value.
64.3.8 MinValueValidator
class MinValueValidator(min_value) Raises a ValidationError with a code of min_value if value is less than min_value.
64.3.9 MaxLengthValidator
class MaxLengthValidator(max_length) Raises a ValidationError with a code of max_length if the length of value is greater than max_length.
64.3.10 MinLengthValidator
class MinLengthValidator(min_length) Raises a ValidationError with a code of min_length if the length of value is less than min_length.
889
890
Part VI
891
Documentation that we cant nd a more organized place for. Like that drawer in your kitchen with the scissors, batteries, duct tape, and other junk.
893
894
CHAPTER
SIXTYFIVE
API STABILITY
The release of Django 1.0 comes with a promise of API stability and forwards-compatibility. In a nutshell, this means that code you develop against Django 1.0 will continue to work against 1.1 unchanged, and you should need to make only minor changes for any 1.X release.
Generic views. Internationalization. Pagination Serialization Signals Templates, including the language, Python-level template APIs, and custom template tags and libraries. We may add new template tags in the future and the names may inadvertently clash with external template tags. Before adding any such tags, well ensure that Django raises an error if it tries to load tags with duplicate names. Testing django-admin utility. Built-in middleware Request/response objects. Settings. Note, though that while the list of built-in settings can be considered complete we may and probably will add new settings in future versions. This is one of those places where stable does not mean complete. Built-in signals. Like settings, well probably add new signals in the future, but the existing ones wont break. Unicode handling. Everything covered by the HOWTO guides.
65.2.1 django.utils
Most of the modules in django.utils are designed for internal use. Only the following parts of django.utils can be considered stable: django.utils.cache django.utils.datastructures.SortedDict only this single class; the rest of the module is for internal use. django.utils.encoding django.utils.feedgenerator django.utils.http django.utils.safestring django.utils.translation django.utils.tzinfo
65.3 Exceptions
There are a few exceptions to this stability and backwards-compatibility promise.
896
65.3. Exceptions
897
898
CHAPTER
SIXTYSIX
DESIGN PHILOSOPHIES
This document explains some of the fundamental philosophies Djangos developers have used in creating the framework. Its goal is to explain the past and guide the future.
66.1 Overall
66.1.1 Loose coupling
A fundamental goal of Djangos stack is loose coupling and tight cohesion. The various layers of the framework shouldnt know about each other unless absolutely necessary. For example, the template system knows nothing about Web requests, the database layer knows nothing about data display and the view system doesnt care which template system a programmer uses. Although Django comes with a full stack for convenience, the pieces of the stack are independent of another wherever possible.
899
66.1.6 Consistency
The framework should be consistent at all levels. Consistency applies to everything from low-level (the Python coding style used) to high-level (the experience of using Django).
66.2 Models
66.2.1 Explicit is better than implicit
Fields shouldnt assume certain behaviors based solely on the name of the eld. This requires too much knowledge of the system and is prone to errors. Instead, behaviors should be based on keyword arguments and, in some cases, on the type of the eld.
900
901
902
66.5.9 Extensibility
The template system should recognize that advanced template authors may want to extend its technology. This is the philosophy behind custom template tags and lters.
66.6 Views
66.6.1 Simplicity
Writing a view should be as simple as writing a Python function. Developers shouldnt have to instantiate a class when a function will do.
66.6. Views
903
904
CHAPTER
SIXTYSEVEN
905
906
Part VII
Glossary
907
eld An attribute on a model; a given eld usually maps directly to a single database column. See Models. generic view A higher-order view function that provides an abstract/generic implementation of a common idiom or pattern found in view development. See Generic views. model Models store your applications data. See Models. MTV See Django appears to be a MVC framework, but you call the Controller the view, and the View the template. How come you dont use the standard names?. MVC Model-view-controller; a software pattern. Django follows MVC to some extent. project A Python package i.e. a directory of code that contains all the settings for an instance of Django. This would include database conguration, Django-specic options and application-specic settings. property Also known as managed attributes, and a feature of Python since version 2.2. From the property documentation: Properties are a neat way to implement attributes whose usage resembles attribute access, but whose implementation uses method calls. [...] You could only do this by overriding __getattr__ and __setattr__; but overriding __setattr__ slows down all attribute assignments considerably, and overriding __getattr__ is always a bit tricky to get right. Properties let you do this painlessly, without having to override __getattr__ or __setattr__. queryset An object representing some set of rows to be fetched from the database. See Making queries. slug A short label for something, containing only letters, numbers, underscores or hyphens. Theyre generally used in URLs. For example, in a typical blog entry URL:
http://www.djangoproject.com/weblog/2008/apr/12/spring/
the last bit (spring) is the slug. template A chunk of text that acts as formatting for representing data. A template helps to abstract the presentation of data from the data itself. See The Django template language. view A function responsible for rending a page.
909
910
Part VIII
Release notes
911
Release notes for the ofcial Django releases. Each release note will tell you whats new in each version, and will also describe any backwards-incompatible changes made in that version. For those upgrading to a new version of Django, you will need to check all the backwards-incompatible changes and deprecated features for each nal release from the one after your current Django version, up to and including the new version.
913
914
CHAPTER
SIXTYEIGHT
FINAL RELEASES
68.1 1.2 release
68.1.1 Django 1.2 release notes
May 17, 2010. Welcome to Django 1.2! Nearly a year in the making, Django 1.2 packs an impressive list of new features and lots of bug xes. These release notes cover the new features, as well as important changes youll want to be aware of when upgrading from Django 1.1 or older versions. Overview Django 1.2 introduces several large, important new features, including: Support for multiple database connections in a single Django instance. Model validation inspired by Djangos form validation. Vastly improved protection against Cross-Site Request Forgery (CSRF). A new user messages framework with support for cookie- and session-based message for both anonymous and authenticated users. Hooks for object-level permissions, permissions for anonymous users, and more exible username requirements. Customization of e-mail sending via e-mail backends. New smart if template tag which supports comparison operators. These are just the highlights; full details and a complete list of features may be found below. See Also: Django Advent covered the release of Django 1.2 with a series of articles and tutorials that cover some of the new features in depth. Wherever possible these features have been introduced in a backwards-compatible manner per our API stability policy policy. However, a handful of features have changed in ways that, for some users, will be backwards-incompatible. The big changes are: Support for Python 2.3 has been dropped. See the full notes below.
915
The new CSRF protection framework is not backwards-compatible with the old system. Users of the old system will not be affected until the old system is removed in Django 1.4. However, upgrading to the new CSRF protection framework requires a few important backwards-incompatible changes, detailed in CSRF Protection, below. Authors of custom Field subclasses should be aware that a number of methods have had a change in prototype, detailed under get_db_prep_*() methods on Field, below. The internals of template tags have changed somewhat; authors of custom template tags that need to store state (e.g. custom control ow tags) should ensure that their code follows the new rules for stateful template tags The user_passes_test(), login_required(), and permission_required(), decorators from django.contrib.auth only apply to functions and no longer work on methods. Theres a simple one-line x detailed below. Again, these are just the big features that will affect the most users. Users upgrading from previous versions of Django are heavily encouraged to consult the complete list of backwards-incompatible changes and the list of deprecated features. Python compatibility While not a new feature, its important to note that Django 1.2 introduces the rst shift in our Python compatibility policy since Djangos initial public debut. Previous Django releases were tested and supported on 2.x Python versions from 2.3 up; Django 1.2, however, drops ofcial support for Python 2.3. As such, the minimum Python version required for Django is now 2.4, and Django is tested and supported on Python 2.4, 2.5 and 2.6, and will be supported on the as-yet-unreleased Python 2.7. This change should affect only a small number of Django users, as most operating-system vendors today are shipping Python 2.4 or newer as their default version. If youre still using Python 2.3, however, youll need to stick to Django 1.1 until you can upgrade; per our support policy, Django 1.1 will continue to receive security support until the release of Django 1.3. A roadmap for Djangos overall 2.x Python support, and eventual transition to Python 3.x, is currently being developed, and will be announced prior to the release of Django 1.3. Whats new in Django 1.2
Model validation
Model instances now have support for validating their own data, and both model and form elds now accept congurable lists of validators specifying reusable, encapsulated validation behavior. Note, however, that validation must still be performed explicitly. Simply invoking a model instances save() method will not perform any validation of the instances data.
916
Messages framework
Django now includes a robust and congurable messages framework with built-in support for cookie- and sessionbased messaging, for both anonymous and authenticated clients. The messages framework replaces the deprecated user message API and allows you to temporarily store messages in one request and retrieve them for display in a subsequent request (usually the next one).
Object-level permissions
A foundation for specifying permissions at the per-object level has been added. Although there is no implementation of this in core, a custom authentication backend can provide this implementation and it will be used by django.contrib.auth.models.User. See the authentication docs for more information.
E-mail backends
You can now congure the way that Django sends e-mail. Instead of using SMTP to send all e-mail, you can now choose a congurable e-mail backend to send messages. If your hosting provider uses a sandbox or some other nonSMTP technique for sending mail, you can now construct an e-mail backend that will allow Djangos standard mail sending methods to use those facilities. This also makes it easier to debug mail sending. Django ships with backend implementations that allow you to send e-mail to a le, to the console, or to memory. You can even congure all e-mail to be thrown away.
Smart if tag
The if tag has been upgraded to be much more powerful. First, weve added support for comparison operators. No longer will you have to type:
917
Theres really no reason to use {% ifequal %} or {% ifnotequal %} anymore, unless youre the nostalgic type. The operators supported are ==, !=, <, >, <=, >=, in and not in, all of which work like the Python operators, in addition to and, or and not, which were already supported. Also, lters may now be used in the if expression. For example:
<div {% if user.email|lower == message.recipient|lower %} class="highlight" {% endif %} >{{ message }}</div>
Template caching
In previous versions of Django, every time you rendered a template, it would be reloaded from disk. In Django 1.2, you can use a cached template loader to load templates once, then cache the result for every subsequent render. This can lead to a signicant performance improvement if your templates are broken into lots of smaller subtemplates (using the {% extends %} or {% include %} tags). As a side effect, it is now much easier to support non-Django template languages. For more details, see the notes on supporting non-Django template languages.
BigIntegerField
Models can now use a 64-bit BigIntegerField type.
918
Improved localization
Djangos internationalization framework has been expanded with locale-aware formatting and form processing. That means, if enabled, dates and numbers on templates will be displayed using the format specied for the current locale. Django will also use localized formats when parsing data in forms. See Format localization for more details.
readonly_fields in ModelAdmin
django.contrib.admin.ModelAdmin.readonly_fields has been added to enable non-editable elds in add/change pages for models and inlines. Field and calculated values can be displayed alongside editable elds.
GeoDjango
The most signicant new feature for ref:GeoDjango <ref-contrib-gis> in 1.2 is support for multiple spatial databases. As a result, the following spatial database backends are now included: django.contrib.gis.db.backends.postgis django.contrib.gis.db.backends.mysql django.contrib.gis.db.backends.oracle django.contrib.gis.db.backends.spatialite GeoDjango now supports the rich capabilities added in the PostGIS 1.5 release. New features include suppport for the the geography type and enabling of distance queries with non-point geometries on geographic coordinate systems. Support for 3D geometry elds was added, and may be enabled by setting the dim keyword to 3 in your GeometryField. The Extent3D aggregate and extent3d() GeoQuerySet method were added as a part of this feature. The following GeoQeurySet methods are new in 1.2: force_rhr() reverse_geom() geohash() The GEOS interface was updated to use thread-safe C library functions when available on the platform. The GDAL interface now allows the user to set a spatial_filter on the features returned when iterating over a Layer.
919
Finally, GeoDjangos documentation is now included with Djangos and is no longer hosted separately at geodjango.org.
CSRF Protection
Weve made large changes to the way CSRF protection works, detailed in the CSRF documentaton. Here are the major changes you should be aware of: CsrfResponseMiddleware and CsrfMiddleware have been deprecated and will be removed completely in Django 1.4, in favor of a template tag that should be inserted into forms. All contrib apps use a csrf_protect decorator to protect the view. This requires the use of the csrf_token template tag in the template. If you have used custom templates for contrib views, you MUST READ THE UPGRADE INSTRUCTIONS to x those templates. CsrfViewMiddleware is included in MIDDLEWARE_CLASSES by default. This turns on CSRF protection by default, so views that accept POST requests need to be written to work with the middleware. Instructions on how to do this are found in the CSRF docs. All of the CSRF has moved from contrib to core (with backwards compatible imports in the old locations, which are deprecated and will cease to be supported in Django 1.4).
920
class CustomModelField(models.Field): # ... def get_db_prep_save(self, value): # ... def get_db_prep_value(self, value): # ... def get_db_prep_lookup(self, lookup_type, value): # ...
In 1.2, these three methods have undergone a change in prototype, and two extra methods have been introduced:
class CustomModelField(models.Field): # ... def get_prep_value(self, value): # ... def get_prep_lookup(self, lookup_type, value): # ... def get_db_prep_save(self, value, connection): # ... def get_db_prep_value(self, value, connection, prepared=False): # ... def get_db_prep_lookup(self, lookup_type, value, connection, prepared=False): # ...
These changes are required to support multiple databases get_db_prep_* can no longer make any assumptions regarding the database for which it is preparing. The connection argument now provides the preparation methods with the specic connection for which the value is being prepared. The two new methods exist to differentiate general data-preparation requirements from requirements that are databasespecic. The prepared argument is used to indicate to the database-preparation methods whether generic value preparation has been performed. If an unprepared (i.e., prepared=False) value is provided to the get_db_prep_*() calls, they should invoke the corresponding get_prep_*() calls to perform generic data preparation. Weve provided conversion functions that will transparently convert functions adhering to the old prototype into functions compatible with the new prototype. However, these conversion functions will be removed in Django 1.4, so you should upgrade your Field denitions to use the new prototype as soon as possible. If your get_db_prep_*() methods made no use of the database connection, you should be able to upgrade by renaming get_db_prep_value() to get_prep_value() and get_db_prep_lookup() to get_prep_lookup(). If you require database specic conversions, then you will need to provide an implementation get_db_prep_* that uses the connection argument to resolve database-specic values.
921
All of the built-in Django template tags are safe to use with the cached loader, but if youre using custom template tags that come from third party packages, or from your own code, you should ensure that the Node implementation for each tag is thread-safe. For more information, see template tag thread safety considerations. You may also need to update your templates if you were relying on the implementation of Djangos template tags not being thread safe. The cycle tag is the most likely to be affected in this way, especially when used in conjunction with the include tag. Consider the following template fragment:
{% for object in object_list %} {% include "subtemplate.html" %} {% endfor %}
Using the thread-safe Django 1.2 renderer, you will instead get:
even even even even ...
This is because each rendering of the include tag is an independent rendering. When the cycle tag was not thread safe, the state of the cycle tag would leak between multiple renderings of the same include. Now that the cycle tag is thread safe, this leakage no longer occurs.
to this:
from django.utils.decorators import method_decorator class MyClass(object): @method_decorator(login_required) def my_view(self, request): pass
922
or:
from django.utils.decorators import method_decorator login_required_m = method_decorator(login_required) class MyClass(object): @login_required_m def my_view(self, request): pass
For those of you whove been following the development trunk, this change also applies to other decorators introduced since 1.1, including csrf_protect, cache_control and anything created using decorator_from_middleware.
if tag changes
Due to new features in the if template tag, it no longer accepts and, or and not as valid variable names. Previously, these strings could be used as variable names. Now, the keyword status is always enforced, and template code such as {% if not %} or {% if and %} will throw a TemplateSyntaxError. Also, in is a new keyword and so is not a valid variable name in this tag.
LazyObject
LazyObject is an undocumented-but-often-used utility class used for lazily wrapping other objects of unknown type. In Django 1.1 and earlier, it handled introspection in a non-standard way, depending on wrapped objects implementing a public method named get_all_members(). Since this could easily lead to name clashes, it has been changed to use the standard Python introspection method, involving __members__ and __dir__(). If you used LazyObject in your own code and implemented the get_all_members() method for wrapped objects, youll need to make a couple of changes: First, if your class does not have special requirements for introspection (i.e., you have not implemented __getattr__() or other methods that allow for attributes not discoverable by normal mechanisms), you can simply remove the get_all_members() method. The default implementation on LazyObject will do the right thing. If you have more complex requirements for introspection, rst rename the get_all_members() method to __dir__(). This is the standard introspection method for Python 2.6 and above. If you require support for Python versions earlier than 2.6, add the following code to the class:
__members__ = property(lambda self: self.__dir__())
923
Cookie encoding
To x bugs with cookies in Internet Explorer, Safari, and possibly other browsers, our encoding of cookie values was changed so that the comma and semicolon are treated as non-safe characters, and are therefore encoded as \054 and \073 respectively. This could produce backwards incompatibilities, especially if you are storing comma or semicolon in cookies and have javascript code that parses and manipulates cookie values client-side.
BooleanField on MySQL
In previous versions of Django, a models BooleanField under MySQL would return its value as either 1 or 0, instead of True or False; for most people this wasnt a problem because bool is a subclass of int in Python. In Django 1.2, however, BooleanField on MySQL correctly returns a real bool. The only time this should ever be an issue is if you were expecting the repr of a BooleanField to print 1 or 0.
924
Features deprecated in 1.2 Finally, Django 1.2 deprecates some features from earlier releases. These features are still supported, but will be gradually phased out over the next few release cycles. Code taking advantage of any of the features below will raise a PendingDeprecationWarning in Django 1.2. This warning will be silent by default, but may be turned on using Pythons warnings module, or by running Python with a -Wd or -Wall ag. In Django 1.3, these warnings will become a DeprecationWarning, which is not silent. In Django 1.4 support for these features will be removed entirely. See Also: For more details, see the documentation Djangos release process and our deprecation timeline.
Specifying databases
Prior to Django 1.2, Django used a number of settings to control access to a single database. Django 1.2 introduces support for multiple databases, and as a result the way you dene database settings has changed. Any existing Django settings le will continue to work as expected until Django 1.4. Until then, old-style database settings will be automatically translated to the new-style format. In the old-style (pre 1.2) format, you had a number of DATABASE_ settings in your settings le. For example:
DATABASE_NAME = test_db DATABASE_ENGINE = postgresql_psycopg2 DATABASE_USER = myusername DATABASE_PASSWORD = s3krit
These settings are now in a dictionary named DATABASES. Each item in the dictionary corresponds to a single database connection, with the name default describing the default database connection. The setting names have also been shortened. The previous sample settings would now look like this:
DATABASES = { default: { NAME: test_db, ENGINE: django.db.backends.postgresql_psycopg2, USER: myusername, PASSWORD: s3krit, } }
This affects the following settings: Old setting DATABASE_ENGINE DATABASE_HOST DATABASE_NAME DATABASE_OPTIONS DATABASE_PASSWORD DATABASE_PORT DATABASE_USER TEST_DATABASE_CHARSET TEST_DATABASE_COLLATION TEST_DATABASE_NAME New Setting ENGINE HOST NAME OPTIONS PASSWORD PORT USER TEST_CHARSET TEST_COLLATION TEST_NAME
925
These changes are also required if you have manually created a database connection using DatabaseWrapper() from your database backend of choice. In addition to the change in structure, Django 1.2 removes the special handling for the built-in database backends. All database backends must now be specied by a fully qualied module name (i.e., django.db.backends.postgresql_psycopg2, rather than just postgresql_psycopg2).
SMTPConnection
The SMTPConnection class has been deprecated in favor of a generic e-mail backend API. Old code that explicitly instantiated an instance of an SMTPConnection:
from django.core.mail import SMTPConnection connection = SMTPConnection() messages = get_notification_email() connection.send_messages(messages)
Depending on the value of the EMAIL_BACKEND setting, this may not return an SMTP connection. If you explicitly require an SMTP connection with which to send e-mail, you can explicitly request an SMTP connection:
from django.core.mail import get_connection connection = get_connection(django.core.mail.backends.smtp.EmailBackend) messages = get_notification_email() connection.send_messages(messages)
If your call to construct an instance of SMTPConnection required additional arguments, those arguments can be passed to the get_connection() call:
926
Additionally, if you make use of the method, you need to replace the following:
for message in user.get_and_delete_messages(): ...
...with:
from django.contrib import messages for message in messages.get_messages(request): ...
For more information, see the full messages documentation. You should begin to update your code to use the new API immediately.
django.utils.translation.get_date_formats() and django.utils.translation.get_partial_date_for have been deprecated in favor of the appropriate calls to django.utils.formats.get_format(), which is locale-aware when USE_L10N is set to True, and falls back to default settings if set to False. To get the different date formats, instead of writing this:
from django.utils.translation import get_date_formats date_format, datetime_format, time_format = get_date_formats()
...use:
from django.utils import formats date_format = formats.get_format(DATE_FORMAT) datetime_format = formats.get_format(DATETIME_FORMAT) time_format = formats.get_format(TIME_FORMAT)
927
The same applies to the globals found in django.forms.fields: DEFAULT_DATE_INPUT_FORMATS DEFAULT_TIME_INPUT_FORMATS DEFAULT_DATETIME_INPUT_FORMATS Use django.utils.formats.get_format() to get the appropriate formats.
email_re
An undocumented regular expression for validating email addresses has been moved from django.form.fields to django.core.validators. You will need to update your imports if you are using it.
Feed in django.contrib.syndication.feeds
The django.contrib.syndication.feeds.Feed class has been replaced by the django.contrib.syndication.views.Feed class. The old feeds.Feed class is deprecated, and will be removed in Django 1.4. The new class has an almost identical API, but allows instances to be used as views. For example, consider the use of the old framework in the following URLconf :
from django.conf.urls.defaults import * from myproject.feeds import LatestEntries, LatestEntriesByCategory feeds = { latest: LatestEntries, categories: LatestEntriesByCategory, } urlpatterns = patterns(, # ... (r^feeds/(?P<url>.*)/$, django.contrib.syndication.views.feed, {feed_dict: feeds}), # ... )
Using the new Feed class, these feeds can be deployed directly as views:
from django.conf.urls.defaults import * from myproject.feeds import LatestEntries, LatestEntriesByCategory urlpatterns = patterns(, # ... (r^feeds/latest/$, LatestEntries()), (r^feeds/categories/(?P<category_id>\d+)/$, LatestEntriesByCategory()), # ... )
928
If you currently use the feed() view, the LatestEntries class would often not need to be modied apart from subclassing the new Feed class. The exception is if Django was automatically working out the name of the template to use to render the feeds description and title elements (if you were not specifying the title_template and description_template attributes). You should ensure that you always specify title_template and description_template attributes, or provide item_title() and item_description() methods. However, LatestEntriesByCategory uses the get_object() method with the bits argument to specify a specic category to show. In the new Feed class, get_object() method takes a request and arguments from the URL, so it would look like this:
from django.contrib.syndication.views import Feed from django.shortcuts import get_object_or_404 from myproject.models import Category class LatestEntriesByCategory(Feed): def get_object(self, request, category_id): return get_object_or_404(Category, id=category_id) # ...
Additionally, the get_feed() method on Feed classes now take different arguments, which may impact you if you use the Feed classes directly. Instead of just taking an optional url argument, it now takes two arguments: the object returned by its own get_object() method, and the current request object. To take into account Feed classes not being initialized for each request, the __init__() method now takes no arguments by default. Previously it would have taken the slug from the URL and the request object. In accordance with RSS best practices, RSS feeds will now include an atom:link element. You may need to update your tests to take this into account. For more information, see the full syndication framework documentation.
GeoDjango
To allow support for multiple databases, the GeoDjango database internals were changed substantially. The largest backwards-incompatible change is that the module django.contrib.gis.db.backend was renamed to django.contrib.gis.db.backends, where the full-edged spatial database backends now exist. The following sections provide information on the most-popular APIs that were affected by these changes. SpatialBackend Prior to the creation of the separate spatial backends, the django.contrib.gis.db.backend.SpatialBackend object was provided as an abstraction to introspect on the capabilities of the spatial database. All of the attributes and routines provided by SpatialBackend are now a part of the ops attribute of the database backend. The old module django.contrib.gis.db.backend is still provided for backwards-compatibility access to a SpatialBackend object, which is just an alias to the ops module of the default spatial database connection.
929
Users that were relying on undocumented modules and objects within django.contrib.gis.db.backend, rather the abstractions provided by SpatialBackend, are required to modify their code. For example, the following import which would work in 1.1 and below:
from django.contrib.gis.db.backend.postgis import PostGISAdaptor
SpatialRefSys and GeometryColumns models In previous versions of GeoDjango, django.contrib.gis.db.models had SpatialRefSys and GeometryColumns models for querying the OGC spatial metadata tables spatial_ref_sys and geometry_columns, respectively. While these aliases are still provided, they are only for the default database connection and exist only if the default connection is using a supported spatial database backend. Note: Because the table structure of the OGC spatial metadata tables differs across spatial databases, the SpatialRefSys and GeometryColumns models can no longer be associated with the gis application name. Thus, no models will be returned when using the get_models method in the following example:
>>> from django.db.models import get_app, get_models >>> get_models(get_app(gis)) []
To get the correct SpatialRefSys and GeometryColumns for your spatial database use the methods provided by the spatial backend:
>>> from django.db import connections >>> SpatialRefSys = connections[my_spatialite].ops.spatial_ref_sys() >>> GeometryColumns = connections[my_postgis].ops.geometry_columns()
Note: When using the models returned from the spatial_ref_sys() and geometry_columns() method, youll still need to use the correct database alias when querying on the non-default connection. In other words, to ensure that the models in the example above use the correct database:
sr_qs = SpatialRefSys.objects.using(my_spatialite).filter(...) gc_qs = GeometryColumns.objects.using(my_postgis).filter(...)
Language code no
The currently used language code for Norwegian Bokml no is being replaced by the more common language code nb.
930
This is the second bugx release in the Django 1.1 series, improving the stability and performance of the Django 1.1 codebase. Django 1.1.2 maintains backwards compatibility with Django 1.1.0, but contain a number of xes and other improvements. Django 1.1.2 is a recommended upgrade for any development or deployment currently using or targeting Django 1.1. For full details on the new features, backwards incompatibilities, and deprecated features in the 1.1 branch, see the Django 1.1 release notes. Backwards-incompatible changes in 1.1.2
Cookie encoding
To x bugs with cookies in Internet Explorer, Safari, and possibly other browsers, our encoding of cookie values was changed so that the characters comma and semi-colon are treated as non-safe characters, and are therefore encoded as \054 and \073 respectively. This could produce backwards incompatibilities, especially if you are storing comma or semi-colon in cookies and have javascript code that parses and manipulates cookie values client-side. One new feature Ordinarily, a point release would not include new features, but in the case of Django 1.1.2, we have made an exception to this rule. Django 1.2 (the next major release of Django) will contain a feature that will improve protection against Cross-Site Request Forgery (CSRF) attacks. This feature requires the use of a new csrf_token template tag in all forms that Django renders. To make it easier to support both 1.1.X and 1.2.X versions of Django with the same templates, we have decided to introduce the csrf_token template tag to the 1.1.X branch. In the 1.1.X branch, csrf_token does nothing - it has no effect on templates or form processing. However, it means that the same template will work with Django 1.2.
Following this change, all platforms, regardless of word size, will generate a 32-bit, 8 character digest in the constraint name; for example:
ALTER TABLE myapp_sometable ADD CONSTRAINT object_id_refs_id_32091d1e FOREIGN KEY ...
As a result of this change, you will not be able to use the reset management command on any table made by a 64-bit machine. This is because the the new generated name will not match the historically generated name; as a result, the SQL constructed by the reset command will be invalid. If you need to reset an application that was created with 64-bit constraints, you will need to manually drop the old constraint prior to invoking reset.
For convenience, Django 1.0 included an optional middleware class django.middleware.http.SetRemoteAddrFromForwa which updated the value of REMOTE_ADDR based on the HTTP X-Forwarded-For header commonly set by some proxy congurations. It has been demonstrated that this mechanism cannot be made reliable enough for general-purpose use, and that (despite documentation to the contrary) its inclusion in Django may lead application developers to assume that the value of REMOTE_ADDR is safe or in some way reliable as a source of authentication. While not directly a security issue, weve decided to remove this middleware with the Django 1.1 release. It has been replaced with a class that does nothing other than raise a DeprecationWarning. If youve been relying on this middleware, the easiest upgrade path is: Examine the code as it existed before it was removed. Verify that it works correctly with your upstream proxy, modifying it to support your particular proxy (if necessary). Introduce your modied version of SetRemoteAddrFromForwardedFor as a piece of middleware in your own project.
932
You should begin to remove use of this feature from your code immediately. AdminSite.root will raise a PendingDeprecationWarning if used in Django 1.1. This warning is hidden by default. In Django 1.2, this warning will be upgraded to a DeprecationWarning, which will be displayed loudly. Django 1.3 will remove AdminSite.root() entirely. For more details on our deprecation policies and strategy, see Djangos release process.
933
Whats new in Django 1.1 Quite a bit: since Django 1.0, weve made 1,290 code commits, xed 1,206 bugs, and added roughly 10,000 lines of documentation. The major new features in Django 1.1 are:
ORM improvements
Two major enhancements have been added to Djangos object-relational mapper (ORM): aggregate support, and query expressions. Aggregate support Its now possible to run SQL aggregate queries (i.e. COUNT(), MAX(), MIN(), etc.) from within Djangos ORM. You can choose to either return the results of the aggregate directly, or else annotate the objects in a QuerySet with the results of the aggregate query. This feature is available as new QuerySet.aggregate()() and QuerySet.annotate()() methods, and is covered in detail in the ORM aggregation documentation. Query expressions Queries can now refer to a another eld on the query and can traverse relationships to refer to elds on related models. This is implemented in the new F object; for full details, including examples, consult the documentation for F expressions.
Model improvements
A number of features have been added to Djangos model layer: Unmanaged models You can now control whether or not Django manages the life-cycle of the database tables for a model using the managed model option. This defaults to True, meaning that Django will create the appropriate database tables in syncdb and remove them as part of the reset command. That is, Django manages the database tables lifecycle. If you set this to False, however, no database table creating or deletion will be automatically performed for this model. This is useful if the model represents an existing table or a database view that has been created by some other means. For more details, see the documentation for the managed option. Proxy models You can now create proxy models: subclasses of existing models that only add Python-level (rather than database-level) behavior and arent represented by a new table. That is, the new model is a proxy for some underlying model, which stores all the real data. All the details can be found in the proxy models documentation. This feature is similar on the surface to unmanaged models, so the documentation has an explanation of how proxy models differ from unmanaged models. Deferred elds In some complex situations, your models might contain elds which could contain a lot of data (for example, large text elds), or require expensive processing to convert them to Python objects. If you know you dont need those particular elds, you can now tell Django not to retrieve them from the database. Youll do this with the new queryset methods defer() and only().
934
Testing improvements
A few notable improvements have been made to the testing framework. Test performance improvements Tests written using Djangos testing framework now run dramatically faster (as much as 10 times faster in many cases). This was accomplished through the introduction of transaction-based tests: when using django.test.TestCase, your tests will now be run in a transaction which is rolled back when nished, instead of by ushing and re-populating the database. This results in an immense speedup for most types of unit tests. See the documentation for TestCase and TransactionTestCase for a full description, and some important notes on database support.
URL namespaces
Django 1.1 improves named URL patterns with the introduction of URL namespaces. In short, this feature allows the same group of URLs, from the same application, to be included in a Django URLConf multiple times, with varying (and potentially nested) named prexes which will be used when performing reverse resolution. In other words, reusable applications like Djangos admin interface may be registered multiple times without URL conicts.
935
GeoDjango
In Django 1.1, GeoDjango (i.e. django.contrib.gis) has several new features: Support for SpatiaLite a spatial database for SQLite as a spatial backend. Geographic aggregates (Collect, Extent, MakeLine, Union) and F expressions. New GeoQuerySet methods: collect, geojson, and snap_to_grid. A new list interface methods for GEOSGeometry objects. For more details, see the GeoDjango documentation.
Other improvements
Other new features and changes introduced since Django 1.0 include: The CSRF protection middleware has been split into two classes CsrfViewMiddleware checks incoming requests, and CsrfResponseMiddleware processes outgoing responses. The combined CsrfMiddleware class (which does both) remains for backwards-compatibility, but using the split classes is now recommended in order to allow ne-grained control of when and where the CSRF processing takes place. reverse() and code which uses it (e.g., the {% url %} template tag) now works with URLs in Djangos administrative site, provided that the admin URLs are set up via include(admin.site.urls) (sending admin requests to the admin.site.root view still works, but URLs in the admin will not be reversible when congured this way). The include() function in Django URLconf modules can now accept sequences of URL patterns (generated by patterns()) in addition to module names. Instances of Django forms (see the forms overview) now have two additional methods, hidden_fields() and visible_fields(), which return the list of hidden i.e., <input type="hidden"> and visible elds on the form, respectively. The redirect_to generic view (see the generic views documentation) now accepts an additional keyword argument permanent. If permanent is True, the view will emit an HTTP permanent redirect (status code 301). If False, the view will emit an HTTP temporary redirect (status code 302). A new database lookup type week_day has been added for DateField and DateTimeField. This type of lookup accepts a number between 1 (Sunday) and 7 (Saturday), and returns objects where the eld value matches that day of the week. See the full list of lookup types for details. The {% for %} tag in Djangos template language now accepts an optional {% empty %} clause, to be displayed when {% for %} is asked to loop over an empty sequence. See the list of built-in template tags for examples of this. The dumpdata management command now accepts individual model names as arguments, allowing you to export the data just from particular models. Theres a new safeseq template lter which works just like safe for lists, marking each item in the list as safe. Cache backends now support incr() and decr() commands to increment and decrement the value of a cache key. On cache backends that support atomic increment/decrement most notably, the memcached backend these operations will be atomic, and quite fast.
936
Django now can easily delegate authentication to the web server via a new authentication backend that supports the standard REMOTE_USER environment variable used for this purpose. Theres a new django.shortcuts.redirect() function that makes it easier to issue redirects given an object, a view name, or a URL. The postgresql_psycopg2 backend now supports native PostgreSQL autocommit. This is an advanced, PostgreSQL-specic feature, that can make certain read-heavy applications a good deal faster. Whats next? Well take a short break, and then work on Django 1.2 will begin no rest for the weary! If youd like to help, discussion of Django development, including progress toward the 1.2 release, takes place daily on the django-developers mailing list: http://groups.google.com/group/django-developers ... and in the #django-dev IRC channel on irc.freenode.net. Feel free to join the discussions! Djangos online documentation also includes pointers on how to contribute to Django: How to contribute to Django Contributions on any level developing code, writing documentation or simply triaging tickets and helping to test proposed bugxes are always welcome and appreciated. And thats the way it is.
937
A bug involving the interaction of Djangos SafeUnicode class and the MySQL adapter has been resolved; SafeUnicode instances (generated, for example, by template rendering) can now be assigned to model attributes and saved to MySQL without requiring an explicit intermediate cast to unicode. A bug affecting ltering on a nullable DateField in SQLite has been resolved. Several updates and improvements have been made to Djangos documentation.
938
Django 1.0 represents over three years of community development as an Open Source project. Djangos received contributions from hundreds of developers, been translated into fty languages, and today is used by developers on every continent and in every kind of job. An interesting historical note: when Django was rst released in July 2005, the initial released version of Django came from an internal repository at revision number 8825. Django 1.0 represents revision 8961 of our public repository. It seems tting that our 1.0 release comes at the moment where community contributions overtake those made privately. Stability and forwards-compatibility The release of Django 1.0 comes with a promise of API stability and forwards-compatibility. In a nutshell, this means that code you develop against Django 1.0 will continue to work against 1.1 unchanged, and you should need to make only minor changes for any 1.X release. See the API stability guide for full details. Backwards-incompatible changes Django 1.0 has a number of backwards-incompatible changes from Django 0.96. If you have apps written against Django 0.96 that you need to port, see our detailed porting guide:
939
Remove prepopulated_from Remove the prepopulated_from argument on model elds. Its no longer valid and has been moved to the ModelAdmin class in admin.py. See the admin, below, for more details about changes to the admin. Remove core Remove the core argument from your model elds. It is no longer necessary, since the equivalent functionality (part of inline editing) is handled differently by the admin interface now. You dont have to worry about inline editing until you get to the admin section, below. For now, remove all references to core. Replace class Admin: with admin.py Remove all your inner class Admin declarations from your models. They wont break anything if you leave them, but they also wont do anything. To register apps with the admin youll move those declarations to an admin.py le; see the admin below for more details. See Also: A contributor to djangosnippets has written a script thatll scan your models.py and generate a corresponding admin.py. Example Below is an example models.py le with all the changes youll need to make: Old (0.96) models.py:
class Author(models.Model): first_name = models.CharField(maxlength=30) last_name = models.CharField(maxlength=30) slug = models.CharField(maxlength=60, prepopulate_from=(first_name, last_name)) class Admin: list_display = [first_name, last_name] def __str__(self): return %s %s % (self.first_name, self.last_name)
940
The Admin One of the biggest changes in 1.0 is the new admin. The Django administrative interface (django.contrib.admin) has been completely refactored; admin denitions are now completely decoupled from model denitions, the framework has been rewritten to use Djangos new form-handling library and redesigned with extensibility and customization in mind. Practically, this means youll need to rewrite all of your class Admin declarations. Youve already seen in models above how to replace your class Admin with a admin.site.register() call in an admin.py le. Below are some more details on how to rewrite that Admin declaration into the new syntax. Use new inline syntax The new edit_inline options have all been moved to admin.py. Heres an example: Old (0.96):
class Parent(models.Model): ... class Child(models.Model): parent = models.ForeignKey(Parent, edit_inline=models.STACKED, num_in_admin=3)
New (1.0):
class ChildInline(admin.StackedInline): model = Child extra = 3 class ParentAdmin(admin.ModelAdmin): model = Parent inlines = [ChildInline] admin.site.register(Parent, ParentAdmin)
See InlineModelAdmin objects for more details. Simplify fields, or use fieldsets The old fields syntax was quite confusing, and has been simplied. The old syntax still works, but youll need to use fieldsets instead. Old (0.96):
class ModelOne(models.Model): ... class Admin: fields = ( (None, {fields: (foo,bar)}), ) class ModelTwo(models.Model): ... class Admin: fields = ( (group1, {fields: (foo,bar), classes: collapse}), (group2, {fields: (spam,eggs), classes: collapse wide}), )
New (1.0):
941
class ModelOneAdmin(admin.ModelAdmin): fields = (foo, bar) class ModelTwoAdmin(admin.ModelAdmin): fieldsets = ( (group1, {fields: (foo,bar), classes: collapse}), (group2, {fields: (spam,eggs), classes: collapse wide}), )
See Also: More detailed information about the changes and the reasons behind them can be found on the NewformsAdminBranch wiki page The new admin comes with a ton of new features; you can read about them in the admin documentation. URLs Update your root urls.py If youre using the admin site, you need to update your root urls.py. Old (0.96) urls.py:
from django.conf.urls.defaults import * urlpatterns = patterns(, (r^admin/, include(django.contrib.admin.urls)), # ... the rest of your URLs here ... )
Views Use django.forms instead of newforms Replace django.newforms with django.forms Django 1.0 renamed the newforms module (introduced in 0.96) to plain old forms. The oldforms module was also removed. If youre already using the newforms library, and you used our recommended import statement syntax, all you have to do is change your import statements. Old:
942
New:
from django import forms
If youre using the old forms system (formerly known as django.forms and django.oldforms), youll have to rewrite your forms. A good place to start is the forms documentation Handle uploaded les using the new API Replace use of uploaded les that is, entries in request.FILES as simple dictionaries with the new UploadedFile. The old dictionary syntax no longer works. Thus, in a view like:
def my_view(request): f = request.FILES[file_field_name] ...
...youd need to make the following changes: Old (0.96) f[content] f[filename] f[content-type] New (1.0) f.read() f.name f.content_type
Work with le elds using the new API The internal implementation of django.db.models.FileField have changed. A visible result of this is that the way you access special attributes (URL, lename, image size, etc) of these model elds has changed. You will need to make the following changes, assuming your models FileField is called myfile: Old (0.96) myfile.get_content_filename() myfile.get_content_url() myfile.get_content_size() myfile.save_content_file() myfile.get_content_width() myfile.get_content_height() New (1.0) myfile.content.path myfile.content.url myfile.content.size myfile.content.save() myfile.content.width myfile.content.height
Note that the width and height attributes only make sense for ImageField elds. More details can be found in the model API documentation. Use Paginator instead of ObjectPaginator The ObjectPaginator in 0.96 has been removed and replaced with an improved version, django.core.paginator.Paginator. Templates Learn to love autoescaping By default, the template system now automatically HTML-escapes the output of every variable. To learn more, see Automatic HTML escaping. To disable auto-escaping for an individual variable, use the safe lter:
943
To disable auto-escaping for an entire template, wrap the template (or just a particular section of the template) in the autoescape tag:
{% autoescape off %} ... unescaped template content here ... {% endautoescape %}
Less-common changes The following changes are smaller, more localized changes. They should only affect more advanced users, but its probably worth reading through the list and checking your code for these things. Signals Add **kwargs to any registered signal handlers. Connect, disconnect, and send signals via methods on the Signal object instead of through module methods in django.dispatch.dispatcher. Remove any use of the Anonymous and Any sender options; they no longer exist. You can still receive signals sent by any sender by using sender=None Make any custom signals youve declared into instances of django.dispatch.Signal instead of anonymous objects. Heres quick summary of the code changes youll need to make: Old (0.96) def callback(sender) sig = object() dispatcher.connect(callback, sig) dispatcher.send(sig, sender) dispatcher.connect(callback, sig, sender=Any) New (1.0) def callback(sender, **kwargs) sig = django.dispatch.Signal() sig.connect(callback) sig.send(sender) sig.connect(callback, sender=None)
Comments If you were using Django 0.96s django.contrib.comments app, youll need to upgrade to the new comments app introduced in 1.0. See Upgrading from Djangos previous comment system for details. Template tags spaceless tag The spaceless template tag now removes all spaces between HTML tags, instead of preserving a single space. Local avors U.S. local avor django.contrib.localflavor.usa has been renamed to django.contrib.localflavor.us. This change was made to match the naming scheme of other local avors. To migrate your code, all you need to do is change the imports. Sessions
944
Getting a new session key SessionBase.get_new_session_key() _get_new_session_key(). get_new_session_object() no longer exists. Fixtures
has
been
renamed
to
Loading a row no longer calls save() Previously, loading a row automatically ran the models save() method. This is no longer the case, so any elds (for example: timestamps) that were auto-populated by a save() now need explicit values in any xture. Settings Better exceptions The old EnvironmentError has split into an ImportError when Django fails to nd the settings module and a RuntimeError when you try to recongure settings after having already used them LOGIN_URL has moved The LOGIN_URL constant moved from django.contrib.auth into the settings module. Instead of using from django.contrib.auth import LOGIN_URL refer to settings.LOGIN_URL. APPEND_SLASH behavior has been updated In 0.96, if a URL didnt end in a slash or have a period in the nal component of its path, and APPEND_SLASH was True, Django would redirect to the same URL, but with a slash appended to the end. Now, Django checks to see whether the pattern without the trailing slash would be matched by something in your URL patterns. If so, no redirection takes place, because it is assumed you deliberately wanted to catch that pattern. For most people, this wont require any changes. Some people, though, have URL patterns that look like this:
r/some_prefix/(.*)$
Previously, those patterns would have been redirected to have a trailing slash. If you always want a slash on such URLs, rewrite the pattern as:
r/some_prefix/(.*/)$
Smaller model changes Different exception from get() Managers now return a MultipleObjectsReturned exception instead of AssertionError: Old (0.96):
try: Model.objects.get(...) except AssertionError: handle_the_error()
New (1.0):
945
LazyDate has been red The LazyDate helper class no longer exists. Default eld values and query arguments can both be callable objects, so instances of LazyDate can be replaced with a reference to datetime.datetime.now: Old (0.96):
class Article(models.Model): title = models.CharField(maxlength=100) published = models.DateField(default=LazyDate())
New (1.0):
import datetime class Article(models.Model): title = models.CharField(max_length=100) published = models.DateField(default=datetime.datetime.now)
New (1.0):
class MyModel(models.Model): field_name = models.DecimalField(max_digits=10, decimal_places=3) ...
If you forget to make this change, you will see errors about FloatField not taking a max_digits attribute in __init__, because the new FloatField takes no precision-related arguments. If youre using MySQL or PostgreSQL, no further changes are needed. DecimalField are the same as for the old FloatField. The database column types for
If youre using SQLite, you need to force the database to view the appropriate columns as decimal types, rather than oats. To do this, youll need to reload your data. Do this after you have made the change to using DecimalField in your code and updated the Django code. Warning: Back up your database rst! For SQLite, this means making a copy of the single le that stores the database (the name of that le is the DATABASE_NAME in your settings.py le). To upgrade each application to use a DecimalField, you can do the following, replacing <app> in the code below with each apps name:
946
$ ./manage.py dumpdata --format=xml <app> > data-dump.xml $ ./manage.py reset <app> $ ./manage.py loaddata data-dump.xml
Notes: 1. Its important that you remember to use XML format in the rst step of this process. We are exploiting a feature of the XML data dumps that makes porting oats to decimals with SQLite possible. 2. In the second step you will be asked to conrm that you are prepared to lose the data for the application(s) in question. Say yes; well restore this data in the third step, of course. 3. DecimalField is not used in any of the apps shipped with Django prior to this change being made, so you do not need to worry about performing this procedure for any of the standard Django models. If something goes wrong in the above process, just copy your backed up database le over the original le and start again. Internationalization django.views.i18n.set_language() now requires a POST request Previously, a GET request was used. The old behavior meant that state (the locale used to display the site) could be changed by a GET request, which is against the HTTP specications recommendations. Code calling this view must ensure that a POST request is now made, instead of a GET. This means you can no longer use a link to access the view, but must use a form submission of some kind (e.g. a button). _() is no longer in builtins _() (the callable object whose name is a single underscore) is no longer monkeypatched into builtins that is, its no longer available magically in every module. If you were previously relying on _() always being present, you should now explicitly import ugettext or ugettext_lazy, if appropriate, and alias it to _ yourself:
from django.utils.translation import ugettext as _
HTTP request/response objects Dictionary access to HttpRequest HttpRequest objects no longer directly support dictionary-style access; previously, both GET and POST data were directly available on the HttpRequest object (e.g., you could check for a piece of form data by using if some_form_key in request or by reading request[some_form_key]. This is no longer supported; if you need access to the combined GET and POST data, use request.REQUEST instead. It is strongly suggested, however, that you always explicitly look in the appropriate dictionary for the type of request you expect to receive (request.GET or request.POST); relying on the combined request.REQUEST dictionary can mask the origin of incoming data. Accessing HTTPResponse headers django.http.HttpResponse.headers has been renamed to _headers and HttpResponse now supports containment checking directly. So use if header in response: instead of if header in response.headers:. Generic relations
947
Generic relations have been moved out of core The generic relation classes GenericForeignKey and GenericRelation have moved into the django.contrib.contenttypes module. Testing django.test.Client.login() has changed Old (0.96):
from django.test import Client c = Client() c.login(/path/to/login,myuser,mypassword)
New (1.0):
# ... same as above, but then: c.login(username=myuser, password=mypassword)
Management commands Running management commands from your code django.core.management has been greatly refactored. Calls to management services in your code now need to use call_command. For example, if you have some test code that calls ush and load_data:
from django.core import management management.flush(verbosity=0, interactive=False) management.load_data([test_data], verbosity=0)
Subcommands must now precede options django-admin.py and manage.py now require subcommands to precede options. So:
$ django-admin.py --settings=foo.bar runserver
Syndication Feed.__init__ has changed The __init__() method of the syndication frameworks Feed class now takes an HttpRequest object as its second parameter, instead of the feeds URL. This allows the syndication framework to work without requiring the sites framework. This only affects code that subclasses Feed and overrides the __init__() method, and code that calls Feed.__init__() directly.
948
Data structures SortedDictFromList is gone django.newforms.forms.SortedDictFromList was removed. django.utils.datastructures.SortedDict can now be instantiated with a sequence of tuples. To update your code: 1. Use django.utils.datastructures.SortedDict django.newforms.forms.SortedDictFromList. wherever you were using
2. Because django.utils.datastructures.SortedDict.copy() doesnt return a deepcopy as SortedDictFromList.copy() did, you will need to update your code if you were relying on a deepcopy. Do this by using copy.deepcopy directly. Database backend functions Database backend functions have been renamed Almost all of the database backend-level functions have been renamed and/or relocated. None of these were documented, but youll need to change your code if youre using any of these functions, all of which are in django.db: Old (0.96) backend.get_autoinc_sql backend.get_date_extract_sql backend.get_date_trunc_sql backend.get_datetime_cast_sql backend.get_deferrable_sql backend.get_drop_foreignkey_sql backend.get_fulltext_search_sql backend.get_last_insert_id backend.get_limit_offset_sql backend.get_max_name_length backend.get_pk_default_value backend.get_random_function_sql backend.get_sql_flush backend.get_sql_sequence_reset backend.get_start_transaction_sql backend.get_tablespace_sql backend.quote_name backend.get_query_set_class backend.get_field_cast_sql backend.get_drop_sequence backend.OPERATOR_MAPPING backend.allows_group_by_ordinal backend.allows_unique_and_pk backend.autoindexes_primary_keys backend.needs_datetime_string_cast backend.needs_upper_for_iops backend.supports_constraints backend.supports_tablespaces backend.uses_case_insensitive_names backend.uses_custom_queryset New (1.0) connection.ops.autoinc_sql connection.ops.date_extract_sql connection.ops.date_trunc_sql connection.ops.datetime_cast_sql connection.ops.deferrable_sql connection.ops.drop_foreignkey_sql connection.ops.fulltext_search_sql connection.ops.last_insert_id connection.ops.limit_offset_sql connection.ops.max_name_length connection.ops.pk_default_value connection.ops.random_function_sql connection.ops.sql_flush connection.ops.sequence_reset_sql connection.ops.start_transaction_sql connection.ops.tablespace_sql connection.ops.quote_name connection.ops.query_set_class connection.ops.field_cast_sql connection.ops.drop_sequence_sql connection.operators connection.features.allows_group_by_ordinal connection.features.allows_unique_and_pk connection.features.autoindexes_primary_keys connection.features.needs_datetime_string_cast connection.features.needs_upper_for_iops connection.features.supports_constraints connection.features.supports_tablespaces connection.features.uses_case_insensitive_names connection.features.uses_custom_queryset
A complete list of backwards-incompatible changes can be found at http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges 68.3. 1.0 release 949
Whats new in Django 1.0 A lot! Since Django 0.96, weve made over 4,000 code commits, xed more than 2,000 bugs, and edited, added, or removed around 350,000 lines of code. Weve also added 40,000 lines of new documentation, and greatly improved what was already there. In fact, new documentation is one of our favorite features of Django 1.0, so we might as well start there. First, theres a new documentation site: http://docs.djangoproject.com/ The documentation has been greatly improved, cleaned up, and generally made awesome. Theres now dedicated search, indexes, and more. We cant possibly document everything thats new in 1.0, but the documentation will be your denitive guide. Anywhere you see something like: New in version 1.0: This feature is new in Django 1.0 Youll know that youre looking at something new or changed. The other major highlights of Django 1.0 are:
An improved ORM
Djangos object-relational mapper the component which provides the mapping between Django model classes and your database, and which mediates your database queries has been dramatically improved by a massive refactoring. For most users of Django this is backwards-compatible; the public-facing API for database querying underwent a few minor changes, but most of the updates took place in the ORMs internals. A guide to the changes, including backwards-incompatible modications and mentions of new features opened up by this refactoring, is available on the Django wiki.
950
django.contrib.gis (GeoDjango)
A project over a year in the making, this adds world-class GIS (Geographic Information Systems) support to Django, in the form of a contrib application. Its documentation is currently being maintained externally, and will be merged into the main Django documentation shortly. Huge thanks go to Justin Bronn, Jeremy Dunck, Brett Hoerner and Travis Pinney for their efforts in creating and completing this feature. See http://geodjango.org/ for details.
Pluggable le storage
Djangos built-in FileField and ImageField now can take advantage of pluggable le-storage backends, allowing extensive customization of where and how uploaded les get stored by Django. For details, see the les documentation; big thanks go to Marty Alchin for putting in the hard work to get this completed.
Jython compatibility
Thanks to a lot of work from Leo Soto during a Google Summer of Code project, Djangos codebase has been refactored to remove incompatibilities with Jython, an implementation of Python written in Java, which runs Python code on the Java Virtual Machine. Django is now compatible with the forthcoming Jython 2.5 release. See Running Django on Jython.
INSERT/UPDATE distinction
Although Djangos default behavior of having a models save() method automatically determine whether to perform an INSERT or an UPDATE at the SQL level is suitable for the majority of cases, there are occasional situations where forcing one or the other is useful. As a result, models can now support an additional parameter to save() which can force a specic operation. See Forcing an INSERT or UPDATE for details.
Split CacheMiddleware
Djangos CacheMiddleware has been split into three classes: CacheMiddleware itself still exists and retains all of its previous functionality, but it is now built from two separate middleware classes which handle the two parts
951
of caching (inserting into and reading from the cache) separately, offering additional exibility for situations where combining these functions into a single middleware posed problems. Full details, including updated notes on appropriate use, are in the caching documentation.
Refactored django.contrib.comments
As part of a Google Summer of Code project, Thejaswi Puthraya carried out a major rewrite and refactoring of Djangos bundled comment system, greatly increasing its exibility and customizability. Full documentation is available, as well as an upgrade guide if you were using the previous incarnation of the comments application.
952
to this:
DATABASE_ENGINE = "mysql_old"
However, we strongly encourage MySQL users to upgrade to a more recent version of MySQLdb as soon as possible, The mysql_old backend is provided only to ease this transition, and is considered deprecated; aside from any necessary security xes, it will not be actively maintained, and it will be removed in a future release of Django. Also, note that some features, like the new DATABASE_OPTIONS setting (see the databases documentation for details), are only available on the mysql backend, and will not be made available for mysql_old.
953
1. Redirect the output of manage.py to a le, and edit the generated SQL to use the correct constraint names before executing it. 2. Examine the output of manage.py sqlall to see the new-style constraint names, and use that as a guide to rename existing constraints in your database.
954
Weve copied the current django.forms to django.oldforms. This allows you to upgrade your code now rather than waiting for the backwards-incompatible change and rushing to x your code after the fact. Just change your import statements like this:
from django import forms # 0.95-style from django import oldforms as forms # 0.96-style
The next ofcial release of Django will move the current django.newforms to django.forms. This will be a backwards-incompatible change, and anyone still using the old version of django.forms at that time will need to change their import statements as described above. The next release after that will completely remove django.oldforms. Although the newforms library will continue to evolve, its ready for use for most common cases. We recommend that anyone new to form handling skip the old forms system and start with the new. For more information about django.newforms, read the newforms documentation.
URLconf improvements
You can now use any callable as the callback in URLconfs (previously, only strings that referred to callables were allowed). This allows a much more natural use of URLconfs. For example, this URLconf:
from django.conf.urls.defaults import * urlpatterns = patterns(, (^myview/$, mysite.myapp.views.myview) )
One useful application of this can be seen when using decorators; this change allows you to apply decorators to views in your URLconf. Thus, you can make a generic view require login very easily:
from from from from django.conf.urls.defaults import * django.contrib.auth.decorators import login_required django.views.generic.list_detail import object_list mysite.myapp.models import MyModel
Note that both syntaxes (strings and callables) are valid, and will continue to be valid for the foreseeable future.
955
956
Changes and new features The major changes in this release (for developers currently using the 0.91 release) are a result of merging the magicremoval branch of development. This branch removed a number of constraints in the way Django code had to be written that were a consequence of decisions made in the early days of Django, prior to its open-source release. Its now possible to write more natural, Pythonic code that works as expected, and theres less black magic happening behind the scenes. Aside from that, another main theme of this release is a dramatic increase in usability. Weve made countless improvements in error messages, documentation, etc., to improve developers quality of life. The new features and changes introduced in 0.95 include: Django now uses a more consistent and natural ltering interface for retrieving objects from the database. User-dened models, functions and constants now appear in the module namespace they were dened in. (Previously everything was magically transferred to the django.models.* namespace.) Some optional applications, such as the FlatPage, Sites and Redirects apps, have been decoupled and moved into django.contrib. If you dont want to use these applications, you no longer have to install their database tables. Django now has support for managing database transactions. Weve added the ability to write custom authentication and authorization backends for authenticating users against alternate systems, such as LDAP. Weve made it easier to add custom table-level functions to models, through a new Manager API. Its now possible to use Django without a database. This simply means that the framework no longer requires you to have a working database set up just to serve dynamic pages. In other words, you can just use URLconfs/views on their own. Previously, the framework required that a database be congured, regardless of whether you actually used it. Its now more explicit and natural to override save() and delete() methods on models, rather than needing to hook into the pre_save() and post_save() method hooks. Individual pieces of the framework now can be congured without requiring the setting of an environment variable. This permits use of, for example, the Django templating system inside other applications. More and more parts of the framework have been internationalized, as weve expanded internationalization (i18n) support. The Django codebase, including code and templates, has now been translated, at least in part, into 31 languages. From Arabic to Chinese to Hungarian to Welsh, it is now possible to use Djangos admin site in your native language. The number of changes required to port from 0.91-compatible code to the 0.95 code base are signicant in some cases. However, they are, for the most part, reasonably routine and only need to be done once. A list of the necessary changes is described in the Removing The Magic wiki page. There is also an easy checklist for reference when undertaking the porting operation. Problem reports and getting help Need help resolving a problem with Django? The documentation in the distribution is also available online at the Django Web site. The FAQ document is especially recommended, as it contains a number of issues that come up time and again. For more personalized help, the django-users mailing list is a very active list, with more than 2,000 subscribers who can help you solve any sort of Django problem. We recommend you search the archives rst, though, because many common questions appear with some regularity, and any particular problem may already have been answered.
957
Finally, for those who prefer the more immediate feedback offered by IRC, theres a #django channel on irc.freenode.net that is regularly populated by Django users and developers from around the world. Friendly people are usually available at any hour of the day to help, or just to chat. Thanks for using Django! The Django Team July 2006
958
CHAPTER
SIXTYNINE
DEVELOPMENT RELEASES
These notes are retained for historical purposes. If you are upgrading between formal Django releases, you dont need to worry about these notes.
959
that Djangos localization infrastructure has been expanded for 1.2, and translation packages should now include a formats.py le containing data for localized formatting of numbers and dates. If no critical bugs are discovered, Django 1.2 will be released approximately one week after this release candidate, on or about May 12, 2010.
960
Unit test runners Django 1.2 changes the test runner tools to use a class-based approach. Old style function-based test runners will still work, but should be updated to use the new class-based runners. Syndication feeds The django.contrib.syndication.feeds.Feed class is being replaced by django.contrib.syndication.views.Feed class. The old feeds.Feed class is deprecated. new class has an almost identical API, but allows instances to be used as views. the The
Also, in accordance with RSS best practices, RSS feeds will now include an atom:link element. You may need to update your tests to take this into account. For more information, see the full syndication framework documentation. Cookie encoding Due to cookie-handling bugs in Internet Explorer, Safari, and possibly other browsers, Djangos encoding of cookie values was changed so that the characters comma (,) and semi-colon (;) are treated as non-safe characters, and are therefore encoded as \054 and \073 respectively. This could produce backwards incompatibilities if you are relying on the ability to set these characters directly in cookie values.
961
962
__dict__ on Model instances Historically, the __dict__ attribute of a model instance has only contained attributes corresponding to the elds on a model. In order to support multiple database congurations, Django 1.2 has added a _state attribute to object instances. This attribute will appear in __dict__ for a model instance. If your code relies on iterating over __dict__ to obtain a list of elds, you must now lter the _state attribute of out __dict__.
963
get_db_prep_*() methods on Field Prior to v1.2, a custom eld had the option of dening several functions to support conversion of Python values into database-compatible values. A custom eld might look something like:
class CustomModelField(models.Field): # ... def get_db_prep_save(self, value): # ... def get_db_prep_value(self, value): # ... def get_db_prep_lookup(self, lookup_type, value): # ...
In 1.2, these three methods have undergone a change in prototype, and two extra methods have been introduced:
class CustomModelField(models.Field): # ... def get_prep_value(self, value): # ... def get_prep_lookup(self, lookup_type, value): # ... def get_db_prep_save(self, value, connection): # ... def get_db_prep_value(self, value, connection, prepared=False): # ... def get_db_prep_lookup(self, lookup_type, value, connection, prepared=False): # ...
These changes are required to support multiple databases: get_db_prep_* can no longer make any assumptions regarding the database for which it is preparing. The connection argument now provides the preparation methods with the specic connection for which the value is being prepared. The two new methods exist to differentiate general data preparation requirements, and requirements that are databasespecic. The prepared argument is used to indicate to the database preparation methods whether generic value preparation has been performed. If an unprepared (i.e., prepared=False) value is provided to the get_db_prep_*() calls, they should invoke the corresponding get_prep_*() calls to perform generic data preparation. Conversion functions has been provided which will transparently convert functions adhering to the old prototype into functions compatible with the new prototype. However, this conversion function will be removed in Django 1.4, so you should upgrade your Field denitions to use the new prototype. If your get_db_prep_*() methods made no use of the database connection, you should be able to upgrade by renaming get_db_prep_value() to get_prep_value() and get_db_prep_lookup() to get_prep_lookup(). If you require database specific conversions, then you will need to provide an implementation get_db_prep_* that uses the connection argument to resolve database-specic values.
964
Stateful template tags Template tags that store rendering state on the node itself may experience problems if they are used with the new cached template loader. All of the built-in Django template tags are safe to use with the cached loader, but if youre using custom template tags that come from third party packages, or that you wrote yourself, you should ensure that the Node implementation for each tag is thread-safe. For more information, see template tag thread safety considerations. Test runner exit status code The exit status code of the test runners (tests/runtests.py and python manage.py test) no longer represents the number of failed tests, since a failure of 256 or more tests resulted in a wrong exit status code. The exit status code for the test runner is now 0 for success (no failing tests) and 1 for any number of test failures. If needed, the number of test failures can be found at the end of the test runners output.
Depending on the value of the EMAIL_BACKEND setting, this may not return an SMTP connection. If you explicitly require an SMTP connection with which to send e-mail, you can explicitly request an SMTP connection:
from django.core.mail import get_connection connection = get_connection(django.core.mail.backends.smtp.EmailBackend) messages = get_notification_email() connection.send_messages(messages)
965
If your call to construct an instance of SMTPConnection required additional arguments, those arguments can be passed to the get_connection() call:
Specifying databases Prior to Django 1.1, Django used a number of settings to control access to a single database. Django 1.2 introduces support for multiple databases, and as a result, the way you dene database settings has changed. Any existing Django settings le will continue to work as expected until Django 1.4. Old-style database settings will be automatically translated to the new-style format. In the old-style (pre 1.2) format, there were a number of DATABASE_ settings at the top level of your settings le. For example:
DATABASE_NAME = test_db DATABASE_ENGINE = postgresql_psycopg2 DATABASE_USER = myusername DATABASE_PASSWORD = s3krit
These settings are now contained inside a dictionary named DATABASES. Each item in the dictionary corresponds to a single database connection, with the name default describing the default database connection. The setting names have also been shortened to reect the fact that they are stored in a dictionary. The sample settings given previously would now be stored using:
DATABASES = { default: { NAME: test_db, ENGINE: django.db.backends.postgresql_psycopg2, USER: myusername, PASSWORD: s3krit, } }
This affects the following settings: Old setting DATABASE_ENGINE DATABASE_HOST DATABASE_NAME DATABASE_OPTIONS DATABASE_PASSWORD DATABASE_PORT DATABASE_USER TEST_DATABASE_CHARSET TEST_DATABASE_COLLATION TEST_DATABASE_NAME New Setting ENGINE HOST NAME OPTIONS PASSWORD PORT USER TEST_CHARSET TEST_COLLATION TEST_NAME
These changes are also required if you have manually created a database connection using DatabaseWrapper() from your database backend of choice. In addition to the change in structure, Django 1.2 removes the special handling for the built-in database backends. All database backends must now be specied by a fully qualied module name (i.e., django.db.backends.postgresql_psycopg2, rather than just postgresql_psycopg2).
966
User Messages API The API for storing messages in the user Message model (via user.message_set.create) is now deprecated and will be removed in Django 1.4 according to the standard release process. To upgrade your code, you need to replace any instances of:
user.message_set.create(a message)
Additionally, if you make use of the method, you need to replace the following:
for message in user.get_and_delete_messages(): ...
with:
from django.contrib import messages for message in messages.get_messages(request): ...
For more information, see the full messages documentation. You should begin to update your code to use the new API immediately. Date format helper functions
django.utils.translation.get_date_formats() and django.utils.translation.get_partial_date_for have been deprecated in favor of the appropriate calls to django.utils.formats.get_format() which is locale aware when USE_L10N is set to True, and falls back to default settings if set to False. To get the different date formats, instead of writing:
from django.utils.translation import get_date_formats date_format, datetime_format, time_format = get_date_formats()
use:
from django.utils import formats date_format = formats.get_format(DATE_FORMAT) datetime_format = formats.get_format(DATETIME_FORMAT) time_format = formats.get_format(TIME_FORMAT)
The same applies to the globals found in django.forms.fields: DEFAULT_DATE_INPUT_FORMATS DEFAULT_TIME_INPUT_FORMATS 69.3. Django 1.2 alpha 1 release notes 967
...as you can now do: 968 Chapter 69. Development releases
{% if a != b %} ... {% endif %}
The operators supported are ==, !=, <, >, <=, >= and in, all of which work like the Python operators, in addition to and, or and not which were already supported. Also, lters may now be used in the if expression. For example:
<div {% if user.email|lower == message.recipient|lower %} class="highlight" {% endif %} >{{ message }}</div>
Template caching In previous versions of Django, every time you rendered a template it would be reloaded from disk. In Django 1.2, you can use a cached template loader to load templates once, then use the cached result for every subsequent render. This can lead to a signicant performance improvement if your templates are broken into lots of smaller subtemplates (using the {% extends %} or {% include %} tags). As a side effect, it is now much easier to support non-Django template languages. For more details, see the notes on supporting non-Django template languages. Natural keys in xtures Fixtures can refer to remote objects using Natural keys. This lookup scheme is an alternative to the normal primary-key based object references in a xture, improving readability, and resolving problems referring to objects whose primary key value may not be predictable or known. BigIntegerField Models can now use a 64 bit BigIntegerField type. Fast Failure for Tests The test subcommand of django-admin.py, and the runtests.py script used to run Djangos own test suite, support a new --failfast option. When specied, this option causes the test runner to exit after encountering a failure instead of continuing with the test run. In addition, the handling of Ctrl-C during a test run has been improved to trigger a graceful exit from the test run that reports details of the tests run before the interruption. Improved localization Djangos internationalization framework has been expanded by locale aware formatting and form processing. That means, if enabled, dates and numbers on templates will be displayed using the format specied for the current locale. Django will also use localized formats when parsing data in forms. See Format localization for more details.
969
Added readonly_fields to ModelAdmin django.contrib.admin.ModelAdmin.readonly_fields has been added to enable non-editable elds in add/change pages for models and inlines. Field and calculated values can be displayed along side editable elds. Customizable syntax highlighting You can now use the DJANGO_COLORS environment variable to modify or disable the colors used by django-admin.py to provide syntax highlighting.
970
971
Please open a new ticket only if no existing ticket corresponds to a problem youre running into. Additionally, discussion of Django development, including progress toward the 1.1 release, takes place daily on the django-developers mailing list: http://groups.google.com/group/django-developers ... and in the #django-dev IRC channel on irc.freenode.net. If youre interested in helping out with Djangos development, feel free to join the discussions there. Djangos online documentation also includes pointers on how to contribute to Django: How to contribute to Django Contributions on any level developing code, writing documentation or simply triaging tickets and helping to test proposed bugxes are always welcome and appreciated.
Unmanaged models
You can now control whether or not Django creates database tables for a model using the managed model option. This defaults to True, meaning that Django will create the appropriate database tables in syncdb and remove them as part of reset command. That is, Django manages the database tables lifecycle. If you set this to False, however, no database table creating or deletion will be automatically performed for this model. This is useful if the model represents an existing table or a database view that has been created by some other means. For more details, see the documentation for the managed option.
972
Proxy models
You can now create proxy models: subclasses of existing models that only add Python behavior and arent represented by a new table. That is, the new model is a proxy for some underlying model, which stores all the real data. All the details can be found in the proxy models documentation. This feature is similar on the surface to unmanaged models, so the documentation has an explanation of how proxy models differ from unmanaged models.
Deferred elds
In some complex situations, your models might contain elds which could contain a lot of data (for example, large text elds), or require expensive processing to convert them to Python objects. If you know you dont need those particular elds, you can now tell Django not to retrieve them from the database. Youll do this with the new queryset methods defer() and only(). New admin features Since 1.1 alpha, a couple of new features have been added to Djangos admin application:
Admin actions
You can now dene admin actions that can perform some action to a group of models in bulk. Users will be able to select objects on the change list page and then apply these bulk actions to all selected objects. Django ships with one pre-dened admin action to delete a group of objects in one fell swoop. Testing improvements A couple of small but very useful improvements have been made to the testing framework: The test Client now can automatically follow redirects with the follow argument to Client.get() and Client.post(). This makes testing views that issue redirects simpler. Its now easier to get at the template context in the response returned the test client: youll simply access the context as request.context[key]. The old way, which treats request.context as a list of contexts, one for each rendered template, is still available if you need it. Conditional view processing Django now has much better support for conditional view processing using the standard ETag and Last-Modified HTTP headers. This means you can now easily short-circuit view processing by testing less-expensive conditions. For many views this can lead to a serious improvement in speed and reduction in bandwidth.
973
Other improvements Finally, a grab-bag of other neat features made their way into this beta release, including: The dumpdata management command now accepts individual model names as arguments, allowing you to export the data just from particular models. Theres a new safeseq template lter which works just like safe for lists, marking each item in the list as safe. Cache backends now support incr() and decr() commands to increment and decrement the value of a cache key. On cache backends that support atomic increment/decrement most notably, the memcached backend these operations will be atomic, and quite fast. Django now can easily delegate authentication to the web server via a new authentication backend that supports the standard REMOTE_USER environment variable used for this purpose. Theres a new django.shortcuts.redirect() function that makes it easier to issue redirects given an object, a view name, or a URL. The postgresql_psycopg2 backend now supports native PostgreSQL autocommit. This is an advanced, PostgreSQL-specic feature, that can make certain read-heavy applications a good deal faster.
974
Development sprints for Django 1.1 will also be taking place at PyCon US 2009, on the dedicated sprint days (March 30 through April 2), and anyone who wants to help out is welcome to join in, either in person at PyCon or virtually in the IRC channel or on the mailing list.
Aggregate support
Its now possible to run SQL aggregate queries (i.e. COUNT(), MAX(), MIN(), etc.) from within Djangos ORM. You can choose to either return the results of the aggregate directly, or else annotate the objects in a QuerySet with the results of the aggregate query. This feature is available as new QuerySet.aggregate()() and QuerySet.annotate()() methods, and is covered in detail in the ORM aggregation documentation
Query expressions
Queries can now refer to a another eld on the query and can traverse relationships to refer to elds on related models. This is implemented in the new F object; for full details, including examples, consult the documentation for F expressions. Performance improvements Tests written using Djangos testing framework now run dramatically faster (as much as 10 times faster in many cases). This was accomplished through the introduction of transaction-based tests: when using django.test.TestCase, your tests will now be run in a transaction which is rolled back when nished, instead of by ushing and re-populating the database. This results in an immense speedup for most types of unit tests. See the documentation for TestCase and TransactionTestCase for a full description, and some important notes on database support.
975
Other improvements Other new features and changes introduced since Django 1.0 include: The CSRF protection middleware has been split into two classes CsrfViewMiddleware checks incoming requests, and CsrfResponseMiddleware processes outgoing responses. The combined CsrfMiddleware class (which does both) remains for backwards-compatibility, but using the split classes is now recommended in order to allow ne-grained control of when and where the CSRF processing takes place. reverse() and code which uses it (e.g., the {% url %} template tag) now works with URLs in Djangos administrative site, provided that the admin URLs are set up via include(admin.site.urls) (sending admin requests to the admin.site.root view still works, but URLs in the admin will not be reversible when congured this way). The include() function in Django URLconf modules can now accept sequences of URL patterns (generated by patterns()) in addition to module names. Instances of Django forms (see the forms overview) now have two additional methods, hidden_fields() and visible_fields(), which return the list of hidden i.e., <input type="hidden"> and visible elds on the form, respectively. The redirect_to generic view (see the generic views documentation) now accepts an additional keyword argument permanent. If permanent is True, the view will emit an HTTP permanent redirect (status code 301). If False, the view will emit an HTTP temporary redirect (status code 302). A new database lookup type week_day has been added for DateField and DateTimeField. This type of lookup accepts a number between 1 (Sunday) and 7 (Saturday), and returns objects where the eld value matches that day of the week. See the full list of lookup types for details. The {% for %} tag in Djangos template language now accepts an optional {% empty %} clause, to be displayed when {% for %} is asked to loop over an empty sequence. See the list of built-in template tags for examples of this.
976
Additionally, discussion of Django development, including progress toward the 1.1 release, takes place daily on the django-developers mailing list: http://groups.google.com/group/django-developers ... and in the #django-dev IRC channel on irc.freenode.net. If youre interested in helping out with Djangos development, feel free to join the discussions there. Djangos online documentation also includes pointers on how to contribute to Django: How to contribute to Django Contributions on any level developing code, writing documentation or simply triaging tickets and helping to test proposed bugxes are always welcome and appreciated. Development sprints for Django 1.1 will also be taking place at PyCon US 2009, on the dedicated sprint days (March 30 through April 2), and anyone who wants to help out is welcome to join in, either in person at PyCon or virtually in the IRC channel or on the mailing list.
977
Generic relations in forms and admin Classes are now included in django.contrib.contenttypes which can be used to support generic relations in both the admin interface and in end-user forms. See the documentation for generic relations for details. Improved exibility in the admin Following up on the refactoring of Djangos administrative interface (django.contrib.admin), introduced in Django 1.0 alpha 1, two new hooks have been added to allow customized pre- and post-save handling of model instances in the admin. Full details are in the admin documentation. INSERT/UPDATE distinction Although Djangos default behavior of having a models save() method automatically determine whether to perform an INSERT or an UPDATE at the SQL level is suitable for the majority of cases, there are occasional situations where forcing one or the other is useful. As a result, models can now support an additional parameter to save() which can force a specic operation. Consult the database API documentation for details and important notes about appropriate use of this parameter. Split CacheMiddleware Djangos CacheMiddleware has been split into three classes: CacheMiddleware itself still exists and retains all of its previous functionality, but it is now built from two separate middleware classes which handle the two parts of caching (inserting into and reading from the cache) separately, offering additional exibility for situations where combining these functions into a single middleware posed problems. Full details, including updated notes on appropriate use, are in the caching documentation. Removal of deprecated features A number of features and methods which had previously been marked as deprecated, and which were scheduled for removal prior to the 1.0 release, are no longer present in Django. These include imports of the form library from django.newforms (now located simply at django.forms), the form_for_model and form_for_instance helper functions (which have been replaced by ModelForm) and a number of deprecated features which were replaced by the dispatcher, le-uploading and le-storage refactorings introduced in the Django 1.0 alpha releases. A full list of these and all other backwardsincompatible changes is available on the Django wiki. A number of other improvements and bugxes have also been included: some tricky cases involving case-sensitivity in differing MySQL collations have been resolved, Windows packaging and installation has been improved and the method by which Django generates unique session identiers has been made much more robust.
979
http://code.djangoproject.com/wiki/VersionOneRoadmap
980
Java, which runs Python code on the Java Virtual Machine. Django is now compatible with the forthcoming Jython 2.5 release. There are many other new features and improvements in this release, including two major performance boosts: strings marked for translation using Djangos internationalization system now consume far less memory, and Djangos internal dispatcher which is invoked frequently during request/response processing and when working with Djangos object-relational mapper is now signicantly faster.
981
Contributions on any level developing code, writing documentation or simply triaging tickets and helping to test proposed bugxes are always welcome and appreciated.
982
to these changes will be available as part of the nal Django 1.0 release, and a comprehensive list of backwardsincompatible changes is also available on the Django wiki for those who want to begin developing and testing their upgrade process: http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges
983
984
Part IX
Django internals
985
Documentation for people hacking on Django itself. This is the place to go if youd like to help improve Django, learn or learn about how Django works under the hood. Warning: Elsewhere in the Django documentation, coverage of a feature is a sort of a contract: once an API is in the ofcial documentation, we consider it stable and dont change it without a good reason. APIs covered here, however, are considered internal-only: we reserve the right to change these internals if we must.
987
988
CHAPTER
SEVENTY
CONTRIBUTING TO DJANGO
If you think working with Django is fun, wait until you start working on it. Were passionate about helping Django users make the jump to contributing members of the community, so there are many ways you can help Djangos development: Blog about Django. We syndicate all the Django blogs we know about on the community page; contact [email protected] if youve got a blog youd like to see on that page. Report bugs and request features in our ticket tracker. Please read Reporting bugs, below, for the details on how we like our bug reports served up. Submit patches for new and/or xed behavior. Please read Submitting patches, below, for details on how to submit a patch. Join the django-developers mailing list and share your ideas for how to improve Django. Were always open to suggestions, although were likely to be skeptical of large-scale suggestions without some code to back it up. Triage patches that have been submitted by other users. Please read Ticket triage below, for details on the triage process. Thats all you need to know if youd like to join the Django development community. The rest of this document describes the details of how our community works and how it handles bugs, mailing lists, and all the other minutiae of Django development.
989
Dont use the ticket system to make large-scale feature requests. We like to discuss any big changes to Djangos core on the django-developers list before actually working on them. Dont reopen issues that have been marked wontx. This mark means that the decision has been made that we cant or wont x this particular issue. If youre not sure why, please ask on django-developers. Dont use the ticket tracker for lengthy discussions, because theyre likely to get lost. If a particular ticket is controversial, please move discussion to django-developers. Dont post to django-developers just to announce that you have led a bug report. All the tickets are mailed to another list (django-updates), which is tracked by developers and triagers, so we see them as they are led.
990
If a ticket for this issue already exists, make sure nobody else has claimed it. To do this, look at the Assigned to section of the ticket. If its assigned to nobody, then its available to be claimed. Otherwise, somebody else is working on this ticket, and you either nd another bug/feature to work on, or contact the developer working on the ticket to offer your help. Log into your account, if you havent already, by clicking Login in the upper right of the ticket page. Claim the ticket by clicking the radio button next to Accept ticket near the bottom of the page, then clicking Submit changes. Ticket claimers responsibility Once youve claimed a ticket, you have a responsibility to work on that ticket in a reasonably timely fashion. If you dont have time to work on it, either unclaim it or dont claim it in the rst place! Ticket triagers go through the list of claimed tickets from time to time, checking whether any progress has been made. If theres no sign of progress on a particular claimed ticket for a week or two, a triager may ask you to relinquish the ticket claim so that its no longer monopolized and somebody else can claim it. If youve claimed a ticket and its taking a long time (days or weeks) to code, keep everybody updated by posting comments on the ticket. If you dont provide regular updates, and you dont respond to a request for a progress report, your claim on the ticket may be revoked. As always, more communication is better than less communication! Which tickets should be claimed? Of course, going through the steps of claiming tickets is overkill in some cases. In the case of small changes, such as typos in the documentation or small bugs that will only take a few minutes to x, you dont need to jump through the hoops of claiming tickets. Just submit your patch and be done with it.
991
Weve got two ofcial roles here: Core developers: people with commit access who make the big decisions and write the bulk of the code.
992
Ticket triagers: trusted community members with a proven history of working with the Django community. As a result of this history, they have been entrusted by the core developers to make some of the smaller decisions about tickets. Second, note the ve triage stages: 1. A ticket starts as Unreviewed, meaning that nobody has examined the ticket. 2. Design decision needed means this concept requires a design decision, which should be discussed either in the ticket comments or on django-developers. The Design decision needed step will generally only be used for feature requests. It can also be used for issues that might be bugs, depending on opinion or interpretation. Obvious bugs (such as crashes, incorrect query results, or non-compliance with a standard) skip this step and move straight to Accepted. 3. Once a ticket is ruled to be approved for xing, its moved into the Accepted stage. This stage is where all the real work gets done. 4. In some cases, a ticket might get moved to the Someday/Maybe state. This means the ticket is an enhancement request that we might consider adding to the framework if an excellent patch is submitted. These tickets are not a high priority. 5. If a ticket has an associated patch (see below), a triager will review the patch. If the patch is complete, itll be marked as ready for checkin so that a core developer knows to review and check in the patches. The second part of this workow involves a set of ags the describe what the ticket has or needs in order to be ready for checkin: Has patch This means the ticket has an associated patch. These will be reviewed by the triage team to see if the patch is good. Needs documentation This ag is used for tickets with patches that need associated documentation. Complete documentation of features is a prerequisite before we can check a x into the codebase. Needs tests This ags the patch as needing associated unit tests. Again, this is a required part of a valid patch. Patch needs improvement This ag means that although the ticket has a patch, its not quite ready for checkin. This could mean the patch no longer applies cleanly, or that the code doesnt live up to our standards. A ticket can be resolved in a number of ways: xed Used by one of the core developers once a patch has been rolled into Django and the issue is xed. invalid Used if the ticket is found to be incorrect. This means that the issue in the ticket is actually the result of a user error, or describes a problem with something other than Django, or isnt a bug report or feature request at all (for example, some new users submit support queries as tickets). wontx Used when a core developer decides that this request is not appropriate for consideration in Django. This is usually chosen after discussion in the django-developers mailing list, and you should feel free to join in when its something you care about. duplicate Used when another ticket covers the same issue. By closing duplicate tickets, we keep all the discussion in one place, which helps everyone. worksforme Used when the ticket doesnt contain enough detail to replicate the original bug. If you believe that the ticket was closed in error because youre still having the issue, or its popped up somewhere else, or the triagers have made a mistake, please reopen the ticket and tell us why. Please do not reopen tickets that have been marked as wontx by core developers.
993
994
Repeat the last two steps for the djangojs domain (by appending the -d djangojs command line option to the django-admin.py invocations). Optionally, review and update the conf/locale/<locale>/formats.py le to describe the date, time and numbers formatting particularities of your locale. See Format localization for details. Create a diff against the current Subversion trunk. Open a ticket in Djangos ticket system, set its Component eld to Translations, and attach the patch to it.
995
However, if any setting is accessed before the settings.configure line, this will not work. (Internally, settings is a LazyObject which congures itself automatically when the settings are accessed if it has not already been congured). So, if there is a module containing some code as follows:
from django.conf import settings from django.core.urlresolvers import get_callable default_foo_view = get_callable(settings.FOO_VIEW)
...then importing this module will cause the settings object to be congured. That means that the ability for third parties to import the module at the top level is incompatible with the ability to congure the settings object manually, or makes it very difcult in some circumstances. Instead of the above code, a level of laziness or indirection must be used, such django.utils.functional.LazyObject, django.utils.functional.lazy() or lambda. as
Use InitialCaps for class names (or for factory functions that return classes). Mark all strings for internationalization; see the i18n documentation for details. In docstrings, use action words such as:
def foo(): """ Calculates something and returns the result. """ pass
Please dont put your name in the code you contribute. Our policy is to keep contributors names in the AUTHORS le distributed with Django not scattered throughout the codebase itself. Feel free to include a change to the AUTHORS le in your patch if you make more than a single trivial change.
996
Dont do this:
{{foo}}
Dont do this:
def my_view(req, foo): # ...
Dont do this:
class Person(models.Model): FirstName = models.CharField(max_length=20) Last_Name = models.CharField(max_length=40)
The class Meta should appear after the elds are dened, with a single blank line separating the elds and the class denition. Do this:
class Person(models.Model): first_name = models.CharField(max_length=20) last_name = models.CharField(max_length=40) class Meta: verbose_name_plural = people
Dont do this:
997
class Person(models.Model): first_name = models.CharField(max_length=20) last_name = models.CharField(max_length=40) class Meta: verbose_name_plural = people
The order of model inner classes and standard methods should be as follows (noting that these are not all required): All database elds Custom manager attributes class Meta def __unicode__() def __str__() def save() def get_absolute_url() Any custom methods If choices is dened for a given model eld, dene the choices as a tuple of tuples, with an all-uppercase name, either near the top of the model module or just above the model class. Example:
GENDER_CHOICES = ( (M, Male), (F, Female), )
998
New features Documentation of features that have been added to the framework since the last release. Our policy is: All documentation of new features should be written in a way that clearly designates the features are only available in the Django development version. Assume documentation readers are using the latest release, not the development version. Our preferred way for marking new features is by prefacing the features documentation with: .. versionadded:: X.Y, followed by an optional one line comment and a mandatory blank line. General improvements, or other changes to the APIs that should be emphasized should use the .. versionchanged:: X.Y directive (with the same format as the versionadded mentioned above. Theres a full page of information about the Django documentation system that you should read prior to working on the documentation.
999
1000
We appreciate any and all contributions to the test suite! The Django tests all use the testing infrastructure that ships with Django for testing applications. See Testing Django applications for an explanation of how to write new tests.
Yes, the unit tests need a settings module, but only for database connection info. Your DATABASES setting needs to dene two databases: A default database. This database should use the backend that you want to use for primary testing A database with the alias other. The other database is used to establish that queries can be directed to different databases. As a result, this database can use any backend you want. It doesnt need to use the same backend as the default database (although it can use the same backend if you want to). If youre using the SQLite database backend, you need to dene ENGINE for both databases, plus a TEST_NAME for the other database. The following is a minimal settings le that can be used to test SQLite:
DATABASES = { default: { ENGINE: django.db.backends.sqlite3 }, other: { ENGINE: django.db.backends.sqlite3, TEST_NAME: other_db } }
As a convenience, this settings le is included in your Django distribution. It is called test_sqlite, and is included in the tests directory. This allows you to get started running the tests against the sqlite database without doing anything on your lesystem. However it should be noted that running against other database backends is recommended for certain types of test cases. To run the tests with this included settings le, cd to the tests/ directory and type:
./runtests.py --settings=test_sqlite
If youre using another backend, you will need to provide other details for each database: The USER option for each of your databases needs to specify an existing user account for the database. The PASSWORD option needs to provide the password for the USER that has been specied. The NAME option must be the name of an existing database to which the given user has permission to connect. The unit tests will not touch this database; the test runner creates a new database whose name is NAME prexed with test_, and this test database is deleted when the tests are nished. This means your user account needs permission to execute CREATE DATABASE. You will also need to ensure that your database uses UTF-8 as the default character set. If your database server doesnt use UTF-8 as a default charset, you will need to include a value for TEST_CHARSET in the settings dictionary for the applicable database. If you want to run the full suite of tests, youll need to install a number of dependencies:
1001
PyYAML Markdown Textile Docutils setuptools memcached, plus the either the python-memcached or cmemcached Python binding gettext (gettext on Windows) If you want to test the memcached cache backend, you will also need to dene a CACHE_BACKEND setting that points at your memcached instance. Each of these dependencies is optional. If youre missing any of them, the associated tests will be skipped. To run a subset of the unit tests, append the names of the test modules to the runtests.py command line. See the list of directories in tests/modeltests and tests/regressiontests for module names. As an example, if Django is not in your PYTHONPATH, you placed settings.py in the tests/ directory, and youd like to only run tests for generic relations and internationalization, type:
PYTHONPATH=pwd/.. ./runtests.py --settings=settings generic_relations i18n
1002
1003
...where <branch> is the branchs name. See the list of branch names. Alternatively, you can automatically convert an existing directory of the Django source code as long as youve checked it out via Subversion. To do the conversion, execute this command from within your django directory:
svn switch http://code.djangoproject.com/svn/django/branches/<branch>/
The advantage of using svn switch instead of svn co is that the switch command retains any changes you might have made to your local copy of the code. It attempts to merge those changes into the switched code. The disadvantage is that it may cause conicts with your local changes if the switched code has altered the same lines of code. (Note that if you use svn switch, you dont need to point Python at the new version, as explained in the next section.) Pointing Python at the new Django version Once youve retrieved the branchs code, youll need to change your Python site-packages directory so that it points to the branch version of the django directory. (The site-packages directory is somewhere such as /usr/lib/python2.4/site-packages or /usr/local/lib/python2.4/site-packages or C:\Python\site-packages.) The simplest way to do this is by renaming the old django directory to django.OLD and moving the trunk version of the code into the directory and calling it django. Alternatively, you can use a symlink called django that points to the location of the branchs django package. If you want to switch back, just change the symlink to point to the old code. A third option is to use a path le (<something>.pth) which should work on all systems (including Windows, which doesnt have symlinks available). First, make sure there are no les, directories or symlinks named django in your site-packages directory. Then create a text le named django.pth and save it to your site-packages directory. That le should contain a path to your copy of Django on a single line and optional comments. Here is an example that points to multiple branches. Just uncomment the line for the branch you want to use (Trunk in this example) and make sure all other lines are commented:
# Trunk is a svn checkout of: # http://code.djangoproject.com/svn/django/trunk/ # /path/to/trunk # <branch> is a svn checkout of:
1004
If youre using Django 0.95 or earlier and installed it using python setup.py install, youll have a directory called something like Django-0.95-py2.4.egg instead of django. In this case, edit the le setuptools.pth and remove the line that references the Django .egg le. Then copy the branchs version of the django directory into site-packages.
1005
To request commit access, please contact an existing committer privately. Public requests for commit access are potential ame-war starters, and will be ignored.
1006
CHAPTER
SEVENTYONE
This is because Sphinx will generate proper links for the latter, which greatly helps readers. Theres basically no limit to the amount of useful markup you can add.
Template lters:
.. templatefilter:: linebreaksbr
71.2 An example
For a quick example of how it all ts together, check this out: First, the ref/settings.txt document starts out like this:
.. _ref-settings: Available settings ================== ...
Next, if you look at the topics/settings.txt document, you can see how a link to ref/settings works:
Available settings ================== For a full list of available settings, see the :ref:settings reference <ref-settings>.
Next, notice how the settings (right now just the top few) are annotated:
.. setting:: ADMIN_FOR ADMIN_FOR --------Default: () (Empty tuple) Used for admin-site settings modules, this should be a tuple of settings
1008
modules (in the format foo.bar.baz) for which this site is an admin. The admin site uses this in its automatically-introspected documentation of models, views and template tags.
This marks up the following header as the canonical target for the setting ADMIN_FOR This means any time I talk about ADMIN_FOR, I can reference it using :setting:ADMIN_FOR. Thats basically how everything ts together.
71.3 TODO
The work is mostly done, but heres whats left, in rough order of priority. Most of the various index.txt documents have very short or even non-existent intro text. Each of those documents needs a good short intro the content below that point. The glossary is very perfunctory. It needs to be lled out. Add more metadata targets: theres lots of places that look like:
File.close() ~~~~~~~~~~~~~~~~
That is, use metadata instead of titles. Add more links nearly everything thats an inline code literal right now can probably be turned into a xref. See the literals_to_xrefs.py le in _ext its a shell script to help do this work. This will probably be a continuing, never-ending project. Add info eld lists where appropriate. Add .. code-block:: <lang> to literal blocks so that they get highlighted.
71.4 Hints
Some hints for making things look/read better: Whenever possible, use links. So, use :setting:ADMIN_FOR instead of ADMIN_FOR. Some directives (.. setting::, for one) are prex-style directives; they go before the unit theyre describing. These are known as crossref directives. Others (.. class::, e.g.) generate their own markup; these should go inside the section theyre describing. These are called description units. You can tell which are which by looking at in _ext/djangodocs.py; it registers roles as one of the other. When referring to classes/functions/modules, etc., youll want to use the fully-qualied name of the target (:class:django.contrib.contenttypes.models.ContentType). Since this doesnt look all that awesome in the output it shows the entire path to the object you can prex the target with a ~ (thats a tilde) to get just the last bit of that path. So 71.3. TODO 1009
1010
CHAPTER
SEVENTYTWO
DJANGO COMMITTERS
72.1 The original team
Django originally started at World Online, the Web department of the Lawrence Journal-World of Lawrence, Kansas, USA. Adrian Holovaty Adrian is a Web developer with a background in journalism. Hes 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 Onlines sites. Hes now the leader and founder of EveryBlock, a news feed for your block. Adrian lives in Chicago, USA. Simon Willison Simon is a well-respected web developer from England. He had a one-year internship at World Online, during which time he and Adrian developed Django from scratch. The most enthusiastic Brit youll ever meet, hes passionate about best practices in web development and maintains a well-read web-development blog. Simon lives in Brighton, England. Jacob Kaplan-Moss Jacob is a partner at Revolution Systems which provides support services around Django and related open source technologies. A good deal of Jacobs work time is devoted to working on Django. 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. Wilson Miner Wilsons design-fu is what makes Django look so nice. He designed the website youre looking at right now, as well as Djangos acclaimed admin interface. Wilson is the designer for EveryBlock. Wilson lives in San Francisco, USA.
72.2.1 BDFLs
Adrian and Jacob are the Co-Benevolent Dictators for Life of Django. When rough consensus and working code fails, theyre the ones who make the tough decisions.
1011
1012
In 2007, Justin began developing django.contrib.gis in a branch, a.k.a. GeoDjango, which was merged in time for Django 1.0. While implementing GeoDjango, Justin obtained a deep knowledge of Djangos internals including the ORM, the admin, and Oracle support. Justin lives in Houston, Texas. Karen Tracey Karen has a background in distributed operating systems (graduate school), communications software (industry) and crossword puzzle construction (freelance). The last of these brought her to Django, in late 2006, when she set out to put a web front-end on her crossword puzzle database. That done, she stuck around in the community answering questions, debugging problems, etc. because coding puzzles are as much fun as word puzzles. Karen lives in Apex, NC, USA. Jannis Leidel Jannis graduated in media design from Bauhaus-University Weimar, is the author of a number of pluggable Django apps and likes to contribute to Open Source projects like Pinax. He currently works as a freelance web developer and designer. Jannis lives in Berlin, Germany. James Tauber James is the lead developer of Pinax and the CEO and founder of Eldarion. He has been doing open source software since 1993, Python since 1998 and Django since 2006. He serves on the board of the Python Software Foundation and is currently on a leave of absence from a PhD in linguistics. James currently lives in Boston, MA, USA but originally hails from Perth, Western Australia where he attended the same high school as Russell Keith-Magee.
72.2.3 Specialists
James Bennett James is Djangos release manager; he also contributes to the documentation. James came to web development from philosophy when he discovered that programmers get to argue just as much while collecting much better pay. He lives in Lawrence, Kansas, where he works for the Journal-World developing Ellington. He keeps a blog, has written a book on Django, and enjoys ne port and talking to his car. Ian Kelly Ian is responsible for Djangos support for Oracle. Matt Boersma Matt is also responsible for Djangos Oracle support. Jeremy Dunck Jeremy the lead developer of Pegasus News, a personalized local site based in Dallas, Texas. An early contributor to Greasemonkey and Django, he sees technology as a tool for communication and access to knowledge. Jeremy helped kick off GeoDjango development, and is mostly responsible for the serious speed improvements that signals received in Django 1.0. Jeremy lives in Dallas, Texas, USA.
1013
1014
CHAPTER
SEVENTYTHREE
1015
Django 1.1 will contain a backwards-compatible replica of the function which will raise a PendingDeprecationWarning. This warning is silent by default; you need to explicitly turn on display of these warnings. Django 1.2 will contain the backwards-compatible replica, but the warning will be promoted to a full-edged DeprecationWarning. This warning is loud by default, and will likely be quite annoying. Django 1.3 will remove the feature outright.
Phase one: feature proposal The rst phase of the release process will be devoted to guring out what features to include in the next version. This should include a good deal of preliminary work on those features working code trumps grand design. At the end of part one, the core developers will propose a feature list for the upcoming release. This will be broken into: Must-have: critical features that will delay the release if not nished Maybe features: that will be pushed to the next release if not nished Not going to happen: features explicitly deferred to a later release. Anything that hasnt got at least some work done by the end of the rst third isnt eligible for the next release; a design alone isnt sufcient. Phase two: development The second third of the release schedule is the heads-down working period. Using the roadmap produced at the end of phase one, well all work very hard to get everything on it done. Longer release schedules will likely spend more than a third of the time in this phase. At the end of phase two, any unnished maybe features will be postponed until the next release. Though it shouldnt happen, any must-have features will extend phase two, and thus postpone the nal release. Phase two will culminate with an alpha release. Phase three: bugxes The last third of a release is spent xing bugs no new features will be accepted during this time. Well release a beta release about halfway through, and an rc complete with string freeze two weeks before the end of the schedule.
1017
On feature branches, development of major features is done. These branches will be merged into trunk before the end of phase two.
1018
CHAPTER
SEVENTYFOUR
1019
Authentication backends need to support the AnonymousUser being passed to all methods dealing with permissions. The supports_anonymous_user variable is not checked any longer and can be removed. The ability to specify a callable template loader rather than a Loader class will be removed, as will the load_template_source functions that are included with the built in template loaders for backwards compatibility. These have been deprecated since the 1.2 release. django.utils.translation.get_date_formats() and django.utils.translation.get_partial_date_formats(). These functions are replaced by the new locale aware formatting; use django.utils.formats.get_format() to get the appropriate formats. In django.forms.fields: DEFAULT_DATE_INPUT_FORMATS, DEFAULT_TIME_INPUT_FORMATS and DEFAULT_DATETIME_INPUT_FORMATS. Use django.utils.formats.get_format() to get the appropriate formats. The ability to use a function-based test runners will be removed, django.test.simple.run_tests() test runner. along with the
The views.feed() view and feeds.Feed class in django.contrib.syndication have been deprecated since the 1.2 release. The class-based view views.Feed should be used instead. django.core.context_processors.auth. This release will remove the old method in favor of the new method in django.contrib.auth.context_processors.auth. This has been deprecated since the 1.2 release. The postgresql database backend has been deprecated in favor of the postgresql_psycopg2 backend. The no language code has been deprecated in favor of the nb language code. 2.0 django.views.defaults.shortcut(). This function has been moved to django.contrib.contenttypes.views.shortcut() as part of the goal of removing all django.contrib references from the core Django codebase. The old shortcut will be removed in the 2.0 release.
1020
CHAPTER
SEVENTYFIVE
1021
svn co http://code.djangoproject.com/svn/django/trunk/
Note that this will get all of Django: in addition to the top-level django module containing Python code, youll also get a copy of Djangos documentation, unit-test suite, packaging scripts and other miscellaneous bits. Djangos code will be present in your checkout as a directory named django. To try out the in-development trunk code with your own applications, simply place the directory containing your checkout on your Python import path. Then import statements which look for Django will nd the django module within your checkout. If youre going to be working on Djangos code (say, to x a bug or develop a new feature), you can probably stop reading here and move over to the documentation for contributing to Django, which covers things like the preferred coding style and how to generate and submit a patch.
75.3 Branches
Django uses branches for two main purposes: 1. Development of major or experimental features, to keep them from affecting progress on other work in trunk. 2. Security and bug-x support for older releases of Django, during their support lifetimes.
1022
unicode: A refactoring of Djangos internals to consistently use Unicode-based strings in most places within Django and Django applications. This became part of Django as of the 1.0 release. Additionally, the following branches are closed, but their code was never merged into Django and the features they aimed to implement were never nished: full-history generic-auth multiple-db-support per-object-permissions schema-evolution schema-evolution-ng search-api sqlalchemy All of the above-mentioned branches now reside in django/branches/attic.
75.4 Tags
The directory django/tags within the repository contains complete copies of the Django source code as it existed at various points in its history. These tagged copies of Django are never changed or updated; new tags may be added as needed, but once added they are considered read-only and serve as useful guides to Djangos development history.
75.4. Tags
1023
Within django/tags/releases are copies of the code which formed each packaged release of Django, and each tag is named with the version number of the release to which it corresponds. So, for example, django/tags/releases/1.1 is a complete copy of the code which was packaged as the Django 1.1 release. Within django/tags/notable_moments are copies of the Django code from points which do not directly correspond to releases, but which are nonetheless important historical milestones for Django development. The current notable moments marked there are: ipo: Djangos code as it existed at the moment Django was rst publicly announced in 2005. pre-magic-removal: The state of Djangos code just before the merging of the magic-removal branch (described above), which signicantly updated Djangos object-relational mapper. pre-newforms-admin: The state of Djangos code just before the merging of the newforms-admin branch (see above), which signicantly updated Djangos bundled administrative application. Tags corresponding to each of the alpha, beta and release-candidate packages in the run up to the Django 1.0 release.
1024
Part X
1025
1027
1028
Part XI
Deprecated/obsolete documentation
1029
The following documentation covers features that have been deprecated or that have been replaced in newer versions of Django.
1031
1032
CHAPTER
SEVENTYSIX
DEPRECATED/OBSOLETE DOCUMENTATION
These documents cover features that have been deprecated or that have been replaced in newer versions of Django. Theyre preserved here for folks using old versions of Django or those still using deprecated APIs. No new code based on these APIs should be written.
76.1.1 Modules
The .module class is a basic building block for grouping content in the admin. Its generally applied to a div or a fieldset. It wraps the content group in a box and applies certain styles to the elements within. An h2 within a div.module will align to the top of the div as a header for the whole group.
1033
1034
1035
Labels Form labels should always precede the eld, except in the case of checkboxes and radio buttons, where the input should come rst. Any explanation or help text should follow the label in a p with class .help.
1036
MODULE INDEX
django.core.mail, 291 django.core.paginator, 319 django.contrib.admin, 441 django.core.signals, 829 django.contrib.auth, 251 django.core.urlresolvers, 127 django.contrib.auth.backends, 439 django.db.models, 61 django.contrib.auth.forms, 263 django.db.models.fields, 739 django.contrib.auth.middleware, 737 django.db.models.fields.related, 750 django.contrib.comments, 470 django.db.models.signals, 825 django.contrib.comments.forms, 480 django.dispatch, 339 django.contrib.comments.models, 474 django.forms.fields, 695 django.contrib.comments.moderation, 481 django.forms.forms, 683 django.contrib.comments.signals, 476 django.forms.widgets, 709 django.contrib.contenttypes, 487 django.http, 793 django.contrib.databrowse, 497 django.middleware, 735 django.contrib.flatpages, 498 django.middleware.cache, 735 django.contrib.formtools, 500 django.middleware.common, 735 django.contrib.formtools.wizard, 502 django.middleware.csrf, 491, 737 django.contrib.gis, 506 django.middleware.doc, 736 django.contrib.gis.admin, 596 django.middleware.gzip, 736 django.contrib.gis.db.models, 533, 537 django.middleware.http, 736 django.contrib.gis.feeds, 597 django.middleware.locale, 736 django.contrib.gis.gdal, 573 django.middleware.transaction, 737 django.contrib.gis.geos, 561 django.shortcuts, 147 django.contrib.gis.measure, 558 django.test, 231 django.contrib.gis.utils, 589 django.test.client, 237 django.contrib.gis.utils.geoip, 589 django.test.signals, 830 django.contrib.gis.utils.layermapping, django.test.utils, 250 592 django.contrib.gis.utils.ogrinspect, 595 django.utils, 879 django.utils.cache, 879 django.contrib.humanize, 603 django.utils.datastructures, 880 django.contrib.localflavor, 604 django.utils.encoding, 881 django.contrib.messages, 614 django.utils.feedgenerator, 881 django.contrib.messages.middleware, 736 django.utils.http, 883 django.contrib.redirects, 620 django.utils.safestring, 884 django.contrib.sessions, 154 django.utils.translation, 884 django.contrib.sessions.middleware, 736 django.utils.tzinfo, 885 django.contrib.sitemaps, 621 django.views.i18n, 308 django.contrib.sites, 626 django.views.static, 415 django.contrib.syndication, 632 django.contrib.webdesign, 646 django.core.exceptions, 677 django.core.files, 679
1037
1038
Module Index
INDEX
Symbols
addrport django-admin command-line option, 672 adminmedia django-admin command-line option, 668 all django-admin command-line option, 666 blank django-admin command-line option, 595 database django-admin command-line option, 674 decimal django-admin command-line option, 595 domain django-admin command-line option, 667 email django-admin command-line option, 663 exclude django-admin command-line option, 674 extension django-admin command-line option, 667 failfast django-admin command-line option, 672 format django-admin command-line option, 664 geom-name django-admin command-line option, 595 help django-admin command-line option, 661 ignore django-admin command-line option, 667 indent django-admin command-line option, 664 layer django-admin command-line option, 596 locale django-admin command-line option, 674 mapping django-admin command-line option, 596 multi-geom django-admin command-line option, 596
name-eld django-admin command-line option, 596 natural django-admin command-line option, 664 no-default-ignore django-admin command-line option, 667 no-imports django-admin command-line option, 596 noinput django-admin command-line option, 674 noreload django-admin command-line option, 668 null django-admin command-line option, 596 pythonpath django-admin command-line option, 673 settings django-admin command-line option, 673 srid django-admin command-line option, 596 symlinks django-admin command-line option, 667 traceback django-admin command-line option, 673 username django-admin command-line option, 663 verbosity django-admin command-line option, 673 version django-admin command-line option, 662 __contains__() (QueryDict method), 796 __delitem__() (HttpResponse method), 799 __getattr__() (Area method), 560 __getattr__() (Distance method), 560 __getitem__() (HttpResponse method), 799 __getitem__() (OGRGeometry method), 580 __getitem__() (QueryDict method), 796 __getitem__() (SpatialReference method), 586 __init__() (HttpResponse method), 799 __init__() (SyndicationFeed method), 644 __iter__() (File method), 679 __iter__() (OGRGeometry method), 580 1039
__len__() (OGRGeometry method), 580 __setitem__() (HttpResponse method), 799 __setitem__() (QueryDict method), 796 __str__() (Model method), 762 __unicode__() (Model method), 762
A
A (class in django.contrib.gis.measure), 561 ABSOLUTE_URL_OVERRIDES setting, 803 abstract (Options attribute), 754 actions (ModelAdmin attribute), 457 actions_on_bottom (ModelAdmin attribute), 457 actions_on_top (ModelAdmin attribute), 457 actions_selection_counter (ModelAdmin attribute), 457 activate() (in module django.utils.translation), 885 add template lter, 846 add() (GeometryCollection method), 585 add() (RelatedManager method), 752 add_action() (AdminSite method), 446 add_form_template (ModelAdmin attribute), 457 add_item() (in module django.utils.feedgenerator), 882 add_item() (SyndicationFeed method), 645 add_item_elements() (in module django.utils.feedgenerator), 882 add_never_cache_headers() (in module django.utils.cache), 880 add_root_elements() (in module django.utils.feedgenerator), 882 add_view() (ModelAdmin method), 459 addslashes template lter, 846 ADMIN_FOR setting, 803 ADMIN_MEDIA_PREFIX setting, 803 AdminPasswordChangeForm (class in django.contrib.auth.forms), 263 ADMINS setting, 804 AdminSite (class in django.contrib.admin), 467 aggregate() (in module django.db.models.QuerySet), 782 all() (in module django.db.models.QuerySet), 773 allow() (CommentModerator method), 483 allow_relation(), 115 allow_syncdb(), 115 ALLOWED_INCLUDE_ROOTS setting, 804 angular_name (SpatialReference attribute), 588 angular_units (SpatialReference attribute), 588 annotate() (in module django.db.models.QuerySet), 768 app_label (models.ContentType attribute), 487 app_label (Options attribute), 754 1040
AppCommand (built-in class), 353 APPEND_SLASH setting, 804 appendlist() (QueryDict method), 797 ar.forms.ARCUITField (class in django.contrib.localavor), 606 ar.forms.ARDNIField (class in django.contrib.localavor), 606 ar.forms.ARPostalCodeField (class in django.contrib.localavor), 606 ar.forms.ARProvinceSelect (class in django.contrib.localavor), 606 Area (class in django.contrib.gis.measure), 560 area (GEOSGeometry attribute), 567 area (OGRGeometry attribute), 581 area() (GeoQuerySet method), 551 args (BaseCommand attribute), 352 as_datetime() (Field method), 579 as_double() (Field method), 579 as_int() (Field method), 579 as_p() (Form method), 688 as_string() (Field method), 579 as_table() (Form method), 688 as_ul() (Form method), 688 assertContains() (TestCase method), 247 assertFormError() (TestCase method), 247 assertNotContains() (TestCase method), 247 assertRedirects() (TestCase method), 247 assertTemplateNotUsed() (TestCase method), 247 assertTemplateUsed() (TestCase method), 247 at.forms.ATSocialSecurityNumberField (class in django.contrib.localavor), 606 at.forms.ATStateSelect (class in django.contrib.localavor), 606 at.forms.ATZipCodeField (class in django.contrib.localavor), 606 Atom1Feed (class in django.utils.feedgenerator), 883 attr_value() (SpatialReference method), 587 attrs (Widget attribute), 712 au.forms.AUPhoneNumberField (class in django.contrib.localavor), 606 au.forms.AUPostCodeField (class in django.contrib.localavor), 606 au.forms.AUStateSelect (class in django.contrib.localavor), 606 auth_code() (SpatialReference method), 587 auth_name() (SpatialReference method), 587 AUTH_PROFILE_MODULE setting, 804 authenticate() (in module django.contrib.auth), 257 AUTHENTICATION_BACKENDS setting, 804 AuthenticationForm (class in django.contrib.auth.forms), 263
Index
auto_close_eld (CommentModerator attribute), 482 auto_moderate_eld (CommentModerator attribute), 482 auto_now (DateField attribute), 744 auto_now_add (DateField attribute), 744 autoescape template tag, 831 AutoField (class in django.db.models), 743 Avg (class in django.db.models.QuerySet), 790
B
base36_to_int() (in module django.utils.http), 883 BaseCommand (built-in class), 352 bbcontains eld lookup type, 542 bboverlaps eld lookup type, 542 BigIntegerField (class in django.db.models), 743 blank (Field attribute), 740 block template tag, 831 BooleanField (class in django.db.models), 743 BooleanField (class in django.forms), 700 boundary (GEOSGeometry attribute), 566 boundary() (OGRGeometry method), 583 br.forms.BRPhoneNumberField (class django.contrib.localavor), 607 br.forms.BRStateSelect (class django.contrib.localavor), 607 br.forms.BRZipCodeField (class django.contrib.localavor), 607 buffer() (GEOSGeometry method), 566 build_absolute_uri() (HttpRequest method), 795 build_suite() (DjangoTestSuiteRunner method), 249 byteorder (WKBWriter attribute), 572
in in in
C
ca.forms.CAPhoneNumberField (class django.contrib.localavor), 607 ca.forms.CAPostalCodeField (class django.contrib.localavor), 607 ca.forms.CAProvinceField (class django.contrib.localavor), 607 ca.forms.CAProvinceSelect (class django.contrib.localavor), 607 ca.forms.CASocialInsuranceNumberField (class django.contrib.localavor), 607 CACHE_BACKEND setting, 804 CACHE_MIDDLEWARE_KEY_PREFIX setting, 804 CACHE_MIDDLEWARE_SECONDS setting, 805 can_import_settings (BaseCommand attribute), 352 caprst Index in in in in in
template lter, 847 cascaded_union (MultiPolygon attribute), 569 center template lter, 847 centroid (GEOSGeometry attribute), 566 centroid (Polygon attribute), 584 centroid() (GeoQuerySet method), 552 ch.forms.CHIdentityCardNumberField (class in django.contrib.localavor), 613 ch.forms.CHPhoneNumberField (class in django.contrib.localavor), 613 ch.forms.CHStateSelect (class in django.contrib.localavor), 613 ch.forms.CHZipCodeField (class in django.contrib.localavor), 613 change_form_template (ModelAdmin attribute), 457 change_list_template (ModelAdmin attribute), 457 change_view() (ModelAdmin method), 459 changefreq (Sitemap attribute), 624 changelist_view() (ModelAdmin method), 460 CharField (class in django.db.models), 744 CharField (class in django.forms), 700 check_password() (in module django.contrib.auth), 258 check_password() (models.User method), 253 check_test (CheckboxInput attribute), 710 CheckboxInput (class in django.forms), 710 CheckboxSelectMultiple (class in django.forms), 711 ChoiceField (class in django.forms), 700 choices (ChoiceField attribute), 701 choices (Field attribute), 740 chunks() (File method), 679 city() (GeoIP method), 591 city_info (GeoIP attribute), 591 cl.forms.CLRegionSelect (class in django.contrib.localavor), 607 cl.forms.CLRutField (class in django.contrib.localavor), 607 clean() (Field method), 695 clean() (Model method), 758 clean_elds() (Model method), 758 clean_username() (RemoteUserBackend method), 350 cleaned_data (Form attribute), 685 cleanup django-admin command, 662 clear() (RelatedManager method), 753 clear_cache() (models.ContentTypeManager method), 488 Client (class in django.test.client), 238 client (Response attribute), 241 client (TestCase attribute), 244 clone() (GEOSGeometry method), 567 clone() (OGRGeometry method), 582 clone() (SpatialReference method), 587 close() (FieldFile method), 746
1041
close() (File method), 680 close_after (CommentModerator attribute), 482 close_rings() (OGRGeometry method), 582 codename (models.Permission attribute), 266 coerce (TypedChoiceField attribute), 701 Collect (class in django.contrib.gis.db.models), 558 collect() (GeoQuerySet method), 556 ComboField (class in django.forms), 707 CommandError (built-in class), 354 CommaSeparatedIntegerField (class in django.db.models), 744 comment template tag, 831 Comment (class in django.contrib.comments.models), 474 comment (Comment attribute), 475 comment_form_target template tag, 473 COMMENT_MAX_LENGTH setting, 475 CommentDetailsForm (class in django.contrib.comments.forms), 481 CommentForm (class in django.contrib.comments.forms), 480 CommentModerator (class in django.contrib.comments.moderation), 482 COMMENTS_APP setting, 475 COMMENTS_HIDE_REMOVED setting, 475 CommentSecurityForm (class in django.contrib.comments.forms), 481 compilemessages django-admin command, 662 congure_user() (RemoteUserBackend method), 350 connect() (Moderator method), 483 contained eld lookup type, 542 contains eld lookup type, 784 contains() (GEOSGeometry method), 565 contains() (OGRGeometry method), 583 contains() (PreparedGeometry method), 570 contains_properly eld lookup type, 543 contains_properly() (PreparedGeometry method), 570 content (HttpResponse attribute), 799 content (Response attribute), 242 content_object (Comment attribute), 474 content_type (Comment attribute), 474 content_type (models.Permission attribute), 266 context (Response attribute), 242 convex_hull (GEOSGeometry attribute), 566 convex_hull (OGRGeometry attribute), 583
cookie_date() (in module django.utils.http), 883 cookies (Client attribute), 242 COOKIES (HttpRequest attribute), 794 coord_dim (OGRGeometry attribute), 580 coords (GEOSGeometry attribute), 563 coords (OGRGeometry attribute), 583 coords() (GeoIP method), 591 CoordTransform (class in django.contrib.gis.gdal), 589 copy() (QueryDict method), 797 Count (class in django.db.models.QuerySet), 790 count (Paginator attribute), 321 count() (in module django.db.models.QuerySet), 781 country_code() (GeoIP method), 591 country_code_by_addr() (GeoIP method), 592 country_code_by_name() (GeoIP method), 592 country_info (GeoIP attribute), 591 country_name() (GeoIP method), 591 country_name_by_addr() (GeoIP method), 592 country_name_by_name() (GeoIP method), 592 coupling loose, 899 coveredby eld lookup type, 543 covers eld lookup type, 544 covers() (PreparedGeometry method), 570 create() (in module django.db.models.QuerySet), 779 create() (models.User.message_set method), 268 create() (RelatedManager method), 753 create_test_db() (in module django.test.utils), 250 create_unknown_user (RemoteUserBackend attribute), 350 create_user() (models.UserManager method), 254 createcachetable django-admin command, 662 createsuperuser django-admin command, 663 crosses eld lookup type, 544 crosses() (GEOSGeometry method), 565 crosses() (OGRGeometry method), 583 CSRF_COOKIE_DOMAIN setting, 805 CSRF_COOKIE_NAME setting, 805 CSRF_FAILURE_VIEW setting, 805 csrf_token template tag, 831 ct_eld (generic.GenericInlineModelAdmin attribute), 491 ct_fk_eld (generic.GenericInlineModelAdmin attribute), 491 cut
1042
Index
template lter, 847 cycle template tag, 831 cz.forms.CZBirthNumberField (class django.contrib.localavor), 607 cz.forms.CZICNumberField (class django.contrib.localavor), 607 cz.forms.CZPostalCodeField (class django.contrib.localavor), 607 cz.forms.CZRegionSelect (class django.contrib.localavor), 607
in in in in
D
D (class in django.contrib.gis.measure), 560 DATABASE_ENGINE setting, 823 DATABASE_HOST setting, 823 DATABASE_NAME setting, 823 DATABASE_OPTIONS setting, 823 DATABASE_PASSWORD setting, 823 DATABASE_PORT setting, 824 DATABASE_ROUTERS setting, 808 DATABASE_USER setting, 824 DATABASES setting, 805 DataSource (class in django.contrib.gis.gdal), 574 date template lter, 847 DATE_FORMAT setting, 808 date_hierarchy (ModelAdmin attribute), 448 DATE_INPUT_FORMATS setting, 808 date_joined (models.User attribute), 252 DateField (class in django.db.models), 744 DateField (class in django.forms), 701 DateInput (class in django.forms), 710 dates() (in module django.db.models.QuerySet), 772 DATETIME_FORMAT setting, 808 DATETIME_INPUT_FORMATS setting, 808 DateTimeField (class in django.db.models), 744 DateTimeField (class in django.forms), 702 DateTimeInput (class in django.forms), 710 day eld lookup type, 788 Index
db_column (Field attribute), 741 db_for_read(), 114 db_for_write(), 114 db_index (Field attribute), 741 db_table (ManyToManyField attribute), 752 db_table (Options attribute), 754 db_tablespace (Field attribute), 741 db_tablespace (Options attribute), 754 db_type() (in module django.db.models), 359 dbshell django-admin command, 663 de.forms.DEIdentityCardNumberField (class in django.contrib.localavor), 608 de.forms.DEStateSelect (class in django.contrib.localavor), 608 de.forms.DEZipCodeField (class in django.contrib.localavor), 608 deactivate() (in module django.utils.translation), 885 deactivate_all() (in module django.utils.translation), 885 DEBUG setting, 809 debug template tag, 833 decimal_places (DecimalField attribute), 702, 745 DECIMAL_SEPARATOR setting, 809 DecimalField (class in django.db.models), 745 DecimalField (class in django.forms), 702 decorators.login_required() (in module django.contrib.auth), 259 decorators.permission_required() (in module django.contrib.auth), 264 decorators.user_passes_test() (in module django.contrib.auth), 263 default template lter, 848 default (Field attribute), 741 DEFAULT_CHARSET setting, 809 DEFAULT_CONTENT_TYPE setting, 809 DEFAULT_FROM_EMAIL setting, 810 default_if_none template lter, 848 DEFAULT_INDEX_TABLESPACE setting, 810 default_lat (GeoModelAdmin attribute), 596 default_lon (GeoModelAdmin attribute), 596 DEFAULT_TABLESPACE setting, 810 default_zoom (GeoModelAdmin attribute), 596 defer() (in module django.db.models.QuerySet), 777 delete() (Client method), 240
1043
delete() (FieldFile method), 746 inspectdb, 664 delete() (File method), 680 loaddata, 665 delete() (Model method), 762 makemessages, 666 delete_conrmation_template (ModelAdmin attribute), ogrinspect, 595 457 reset, 667 delete_cookie() (HttpResponse method), 800 runfcgi, 668 delete_selected_conrmation_template (ModelAdmin atrunserver, 668 tribute), 457 shell, 669 delete_view() (ModelAdmin method), 460 sql, 669 description (in module django.db.models), 359 sqlall, 669 destroy_test_db() (in module django.test.utils), 250 sqlclear, 670 dictsort sqlcustom, 670 template lter, 848 sqlush, 670 dictsortreversed sqlindexes, 670 template lter, 849 sqlreset, 670 difference() (GeoQuerySet method), 554 sqlsequencereset, 670 difference() (GEOSGeometry method), 566 startapp, 671 difference() (OGRGeometry method), 583 startproject, 671 diffsettings syncdb, 671 django-admin command, 663 test, 672 dim (GeometryField attribute), 535 testserver, 672 dimension (OGRGeometry attribute), 580 validate, 673 disable_action() (AdminSite method), 446 django-admin command-line option DISALLOWED_USER_AGENTS addrport, 672 setting, 810 adminmedia, 668 disjoint all, 666 eld lookup type, 544 blank, 595 disjoint() (GEOSGeometry method), 565 database, 674 disjoint() (OGRGeometry method), 583 decimal, 595 Distance (class in django.contrib.gis.measure), 560 domain, 667 distance() (GeoQuerySet method), 551 email, 663 distance() (GEOSGeometry method), 567 exclude, 674 distance_gt extension, 667 eld lookup type, 549 failfast, 672 distance_gte format, 664 eld lookup type, 549 geom-name, 595 distance_lt help, 661 eld lookup type, 550 ignore, 667 distance_lte indent, 664 eld lookup type, 550 layer, 596 distinct (in module django.db.models.QuerySet), 791 locale, 674 distinct() (in module django.db.models.QuerySet), 770 mapping, 596 divisibleby multi-geom, 596 template lter, 849 name-eld, 596 django (OGRGeomType attribute), 585 natural, 664 django-admin command no-default-ignore, 667 cleanup, 662 no-imports, 596 compilemessages, 662 noinput, 674 createcachetable, 662 noreload, 668 createsuperuser, 663 null, 596 dbshell, 663 pythonpath, 673 diffsettings, 663 settings, 673 dumpdata, 663 srid, 596 ush, 664 symlinks, 667
1044
Index
traceback, 673 django.contrib.sitemaps (module), 621 username, 663 django.contrib.sites (module), 626 verbosity, 673 django.contrib.sites.managers.CurrentSiteManager (class version, 662 in django.contrib.sites), 630 django.conf.settings.congure() (built-in function), 336 django.contrib.sites.models.Site (class in django.contrib.admin (module), 441 django.contrib.sites), 626 django.contrib.auth (module), 251 django.contrib.syndication (module), 632 django.contrib.auth.backends (module), 439 django.contrib.syndication.views.Feed (class in django.contrib.auth.forms (module), 263 django.contrib.syndication), 636 django.contrib.auth.middleware (module), 737 django.contrib.webdesign (module), 646 django.contrib.auth.middleware.AuthenticationMiddleware django.core.exceptions (module), 677 (class in django.contrib.auth.middleware), 737 django.core.les (module), 679 django.contrib.backends.RemoteUserBackend (class in django.core.mail (module), 291 django.contrib.backends), 350 django.core.mail.outbox (in module django.core.mail), django.contrib.comments (module), 470 247 django.contrib.comments.forms (module), 480 django.core.paginator (module), 319 django.contrib.comments.models (module), 474 django.core.signals (module), 829 django.contrib.comments.moderation (module), 481 django.core.signals.got_request_exception (built-in varidjango.contrib.comments.signals (module), 476 able), 829 django.contrib.comments.signals.comment_was_agged django.core.signals.request_nished (built-in variable), (built-in variable), 476 829 django.contrib.comments.signals.comment_was_posted django.core.signals.request_started (built-in variable), (built-in variable), 476 829 django.contrib.comments.signals.comment_will_be_posted django.core.urlresolvers (module), 127 (built-in variable), 476 django.db.models (module), 61 django.contrib.contenttypes (module), 487 django.db.models.Field (class in django.db.models), 359 django.contrib.databrowse (module), 497 django.db.models.elds (module), 739 django.contrib.atpages (module), 498 django.db.models.elds.related (module), 750 django.contrib.formtools (module), 500 django.db.models.signals (module), 825 django.contrib.formtools.wizard (module), 502 django.db.models.signals.class_prepared (built-in varidjango.contrib.gis (module), 506 able), 828 django.contrib.gis.admin (module), 596 django.db.models.signals.m2m_changed (built-in varidjango.contrib.gis.db.models (module), 533, 537 able), 827 django.contrib.gis.feeds (module), 597 django.db.models.signals.post_delete (built-in variable), django.contrib.gis.gdal (module), 573 827 django.contrib.gis.geos (module), 561 django.db.models.signals.post_init (built-in variable), 826 django.contrib.gis.measure (module), 558 django.db.models.signals.post_save (built-in variable), django.contrib.gis.utils (module), 589 826 django.contrib.gis.utils.geoip (module), 589 django.db.models.signals.post_syncdb (built-in variable), django.contrib.gis.utils.layermapping (module), 592 828 django.contrib.gis.utils.ogrinspect (module), 595 django.db.models.signals.pre_delete (built-in variable), django.contrib.humanize (module), 603 826 django.contrib.localavor (module), 604 django.db.models.signals.pre_save (built-in variable), 826 django.contrib.messages (module), 614 django.db.models.SubeldBase (class in django.contrib.messages.middleware (module), 736 django.db.models), 358 django.contrib.messages.middleware.MessageMiddleware django.dispatch (module), 339 (class in django.contrib.messages.middleware), django.forms.elds (module), 695 736 django.forms.forms (module), 683 django.contrib.redirects (module), 620 django.forms.widgets (module), 709 django.contrib.sessions (module), 154 django.http (module), 793 django.contrib.sessions.middleware (module), 736 django.middleware (module), 735 django.contrib.sessions.middleware.SessionMiddleware django.middleware.cache (module), 735 (class in django.contrib.sessions.middleware), django.middleware.cache.FetchFromCacheMiddleware 736 (class in django.middleware.cache), 735
Index
1045
django.middleware.cache.UpdateCacheMiddleware django.utils.tzinfo (module), 885 (class in django.middleware.cache), 735 django.views.i18n (module), 308 django.middleware.common (module), 735 django.views.static (module), 415 django.middleware.common.CommonMiddleware (class DJANGO_SETTINGS_MODULE, 661 in django.middleware.common), 735 DjangoTestSuiteRunner (class in django.test.simple), 248 django.middleware.csrf (module), 491, 737 Dont repeat yourself, 899 django.middleware.csrf.CsrfMiddleware (class in done() (FormWizard method), 503 django.middleware.csrf), 737 Driver (class in django.contrib.gis.gdal), 579 django.middleware.doc (module), 736 driver_count (Driver attribute), 579 django.middleware.doc.XViewMiddleware (class in DRY, 899 django.middleware.doc), 736 dumpdata django.middleware.gzip (module), 736 django-admin command, 663 django.middleware.gzip.GZipMiddleware (class in dwithin django.middleware.gzip), 736 eld lookup type, 550 django.middleware.http (module), 736 E django.middleware.http.ConditionalGetMiddleware (class in django.middleware.http), 736 editable (Field attribute), 741 django.middleware.http.SetRemoteAddrFromForwardedForellisoid (SpatialReference attribute), 588 (class in django.middleware.http), 736 email (models.User attribute), 252 django.middleware.locale (module), 736 email() (CommentModerator method), 483 django.middleware.locale.LocaleMiddleware (class in EMAIL_BACKEND django.middleware.locale), 736 setting, 810 django.middleware.transaction (module), 737 EMAIL_FILE_PATH django.middleware.transaction.TransactionMiddleware setting, 810 (class in django.middleware.transaction), 737 EMAIL_HOST django.shortcuts (module), 147 setting, 810 django.template.loader.get_template() (built-in function), EMAIL_HOST_PASSWORD 868 setting, 811 django.template.loader.select_template() (built-in func- EMAIL_HOST_USER tion), 868 setting, 811 django.test (module), 231 email_notication (CommentModerator attribute), 482 django.test.client (module), 237 EMAIL_PORT django.test.signals (module), 830 setting, 811 django.test.signals.template_rendered (built-in variable), EMAIL_SUBJECT_PREFIX 830 setting, 811 django.test.utils (module), 250 EMAIL_USE_TLS django.utils (module), 879 setting, 811 django.utils.cache (module), 879 email_user() (models.User method), 254 django.utils.datastructures (module), 880 EmailField (class in django.db.models), 745 django.utils.datastructures.SortedDict (class in EmailField (class in django.forms), 703 django.utils.datastructures), 880 EmailMessage (class in django.core.mail), 294 django.utils.encoding (module), 881 empty (GEOSGeometry attribute), 563 django.utils.feedgenerator (module), 881 empty_label (ModelChoiceField attribute), 709 django.utils.feedgenerator.Atom1Feed (class in empty_value (TypedChoiceField attribute), 701 django.contrib.syndication), 644 enable_eld (CommentModerator attribute), 482 django.utils.feedgenerator.Rss201rev2Feed (class in Enclosure (class in django.utils.feedgenerator), 882 django.contrib.syndication), 644 encoding (HttpRequest attribute), 793 django.utils.feedgenerator.RssUserland091Feed (class in end_index() (Page method), 322 django.contrib.syndication), 644 endswith django.utils.feedgenerator.SyndicationFeed (class in eld lookup type, 786 django.contrib.syndication), 644 ENGINE django.utils.http (module), 883 setting, 806 django.utils.safestring (module), 884 Envelope (class in django.contrib.gis.gdal), 585 django.utils.translation (module), 884 envelope (GEOSGeometry attribute), 567 1046 Index
envelope (OGRGeometry attribute), 581 envelope() (GeoQuerySet method), 552 environment variable DJANGO_SETTINGS_MODULE, 661 equals eld lookup type, 550 equals() (GEOSGeometry method), 565 equals() (OGRGeometry method), 583 equals_exact() (GEOSGeometry method), 565 error_messages (Field attribute), 699, 742 errors (Form attribute), 684 es.forms.ESCCCField (class in django.contrib.localavor), 612 es.forms.ESIdentityCardNumberField (class in django.contrib.localavor), 612 es.forms.ESPhoneNumberField (class in django.contrib.localavor), 612 es.forms.ESPostalCodeField (class in django.contrib.localavor), 612 es.forms.ESProvinceSelect (class in django.contrib.localavor), 612 es.forms.ESRegionSelect (class in django.contrib.localavor), 612 escape template lter, 849 escapejs template lter, 849 ewkb (GEOSGeometry attribute), 565 ewkt (GEOSGeometry attribute), 564 ewkt (OGRGeometry attribute), 582 exact eld lookup type, 545, 783 exclude (ModelAdmin attribute), 450 exclude() (in module django.db.models.QuerySet), 767 execute() (BaseCommand method), 353 exists() (in module django.db.models.QuerySet), 783 expand_to_include() (Envelope method), 586 extends template tag, 833 Extent (class in django.contrib.gis.db.models), 558 extent (GEOSGeometry attribute), 567 extent (Layer attribute), 576 extent (OGRGeometry attribute), 581 extent() (GeoQuerySet method), 556 Extent3D (class in django.contrib.gis.db.models), 558 extent3d() (GeoQuerySet method), 557 exterior_ring (Polygon attribute), 584 extra() (in module django.db.models.QuerySet), 775 extra_js (GeoModelAdmin attribute), 596
F
Feature (class in django.contrib.gis.gdal), 577 Feed (class in django.contrib.gis.feeds), 597
.forms.FIMunicipalitySelect (class django.contrib.localavor), 608 .forms.FISocialSecurityNumber (class django.contrib.localavor), 608 .forms.FIZipCodeField (class django.contrib.localavor), 608 d (Feature attribute), 578 Field, 163 eld, 909 Field (class in django.contrib.gis.gdal), 578 Field (class in django.forms), 695 eld lookup type bbcontains, 542 bboverlaps, 542 contained, 542 contains, 784 contains_properly, 543 coveredby, 543 covers, 544 crosses, 544 day, 788 disjoint, 544 distance_gt, 549 distance_gte, 549 distance_lt, 550 distance_lte, 550 dwithin, 550 endswith, 786 equals, 550 exact, 545, 783 gis-contains, 543 gt, 785 gte, 786 icontains, 784 iendswith, 787 iexact, 783 in, 784 intersects, 545 iregex, 790 isnull, 789 istartswith, 786 left, 546 lt, 786 lte, 786 month, 788 overlaps, 545 overlaps_above, 548 overlaps_below, 548 overlaps_left, 547 overlaps_right, 547 range, 787 regex, 789 relate, 545 right, 547
in in in
Index
1047
same_as, 545 search, 789 startswith, 786 strictly_above, 548 strictly_below, 548 touches, 546 week_day, 788 within, 546 year, 787 eld_precisions (Layer attribute), 576 eld_widths (Layer attribute), 575 elds (ComboField attribute), 707 elds (Feature attribute), 577 elds (Layer attribute), 575 elds (ModelAdmin attribute), 450 elds (MultiValueField attribute), 708 eldsets (ModelAdmin attribute), 448 File (class in django.core.les), 679 FILE_CHARSET setting, 811 FILE_UPLOAD_HANDLERS setting, 811 FILE_UPLOAD_MAX_MEMORY_SIZE setting, 812 FILE_UPLOAD_PERMISSIONS setting, 812 FILE_UPLOAD_TEMP_DIR setting, 812 FileField (class in django.db.models), 745 FileField (class in django.forms), 703 FileInput (class in django.forms), 710 FilePathField (class in django.db.models), 747 FilePathField (class in django.forms), 703 FILES (HttpRequest attribute), 794 lesizeformat template lter, 850 lter template tag, 833 lter() (in module django.db.models.QuerySet), 767 lter_horizontal (ModelAdmin attribute), 450 lter_vertical (ModelAdmin attribute), 451 rst template lter, 850 FIRST_DAY_OF_WEEK setting, 812 rst_name (models.User attribute), 252 rstof template tag, 833 x_ampersands template lter, 850 FixedOffset (class in django.utils.tzinfo), 885 FIXTURE_DIRS setting, 812 xtures (TestCase attribute), 245
FlatPageSitemap (class in django.contrib.sitemaps), 624 FloatField (class in django.db.models), 747 oatformat template lter, 850 ush django-admin command, 664 ush() (HttpResponse method), 800 for template tag, 834 force_escape template lter, 851 force_rhr() (GeoQuerySet method), 552 force_unicode() (in module django.utils.encoding), 881 ForeignKey (class in django.db.models), 750 Form, 163 Form (class in django.forms), 683 form (ModelAdmin attribute), 448 Form Media, 163 format (DateInput attribute), 710 format (DateTimeInput attribute), 710 format (TimeInput attribute), 710 FORMAT_MODULE_PATH setting, 813 formeld() (in module django.db.models), 363 formeld_for_foreignkey() (ModelAdmin method), 459 formeld_overrides (ModelAdmin attribute), 456 FormPreview (class in django.contrib.formtools), 502 FormWizard (class in django.contrib.formtools.wizard), 505 fr.forms.FRDepartmentSelect (class in django.contrib.localavor), 608 fr.forms.FRPhoneNumberField (class in django.contrib.localavor), 608 fr.forms.FRZipCodeField (class in django.contrib.localavor), 608 from_bbox() (django.contrib.gis.gdal.OGRGeometry class method), 580 from_bbox() (django.contrib.gis.geos.Polygon class method), 568 from_esri() (SpatialReference method), 587 fromle() (in module django.contrib.gis.geos), 570 fromstr() (in module django.contrib.gis.geos), 570 full_clean() (Model method), 758
G
GDAL_LIBRARY_PATH setting, 589 generic view, 909 generic.GenericInlineModelAdmin (class in django.contrib.contenttypes), 491 GenericSitemap (class in django.contrib.sitemaps), 624 GeoAtom1Feed (class in django.contrib.gis.feeds), 598 geographic (SpatialReference attribute), 588 geography (GeometryField attribute), 536 Index
1048
geohash() (GeoQuerySet method), 554 GeoIP (class in django.contrib.gis.utils), 590 GEOIP_CITY setting, 590 GEOIP_COUNTRY setting, 590 GEOIP_LIBRARY_PATH setting, 590 GEOIP_PATH setting, 590 GeoIPcountry() (in module django.contrib.gis.utils), 591 geojson (GEOSGeometry attribute), 565 geojson() (GeoQuerySet method), 554 geom (Feature attribute), 577 geom_count (OGRGeometry attribute), 580 geom_name (OGRGeometry attribute), 581 geom_type (Feature attribute), 577 geom_type (GEOSGeometry attribute), 563 geom_type (Layer attribute), 575 geom_type (OGRGeometry attribute), 581 geom_typeid (GEOSGeometry attribute), 563 GeoManager (class in django.contrib.gis.db.models), 536 geometry() (Feed method), 598 GeometryCollection (class in django.contrib.gis.gdal), 585 GeometryCollection (class in django.contrib.gis.geos), 570 GeometryCollectionField (class in django.contrib.gis.db.models), 534 GeometryField (class in django.contrib.gis.db.models), 533 GeoModelAdmin (class in django.contrib.gis.admin), 596 GeoQuerySet (class in django.contrib.gis.db.models), 542 GeoRSSFeed (class in django.contrib.gis.feeds), 598 geos (OGRGeometry attribute), 581 geos() (GeoIP method), 591 GEOS_LIBRARY_PATH setting, 573 GEOSGeometry (class in django.contrib.gis.geos), 563 get (Feature attribute), 577 GET (HttpRequest attribute), 793 get() (Client method), 238 get() (in module django.db.models.QuerySet), 779 get() (QueryDict method), 796 get_absolute_url() (Model method), 763 get_actions() (ModelAdmin method), 447 get_all_permissions() (models.User method), 253 get_and_delete_messages() (models.User method), 254 get_approve_url() (in module django.contrib.comments), 480 get_cache_key() (in module django.utils.cache), 880 get_comment_count template tag, 472 get_comment_form
template tag, 473 get_comment_list template tag, 471 get_comment_permalink template tag, 472 get_connection() (in module django.core.mail), 296 get_date_formats() (in module django.utils.translation), 885 get_db_prep_lookup() (in module django.db.models), 363 get_db_prep_save() (in module django.db.models), 362 get_db_prep_value() (in module django.db.models), 362 get_delete_url() (in module django.contrib.comments), 480 get_digit template lter, 851 get_elds() (Layer method), 576 get_ag_url() (in module django.contrib.comments), 480 get_FOO_display() (Model method), 765 get_for_model() (models.ContentTypeManager method), 489 get_form() (in module django.contrib.comments), 480 get_form_target() (in module django.contrib.comments), 480 get_full_name() (models.User method), 253 get_full_path() (HttpRequest method), 795 get_geoms() (Layer method), 577 get_group_permissions() (models.User method), 253 get_host() (HttpRequest method), 795 get_internal_type() (in module django.db.models), 364 get_language() (in module django.utils.translation), 885 get_language_bidi() (in module django.utils.translation), 885 get_language_from_request() (in module django.utils.translation), 885 get_latest_by (Options attribute), 755 get_list_or_404() (in module django.shortcuts), 150 get_max_age() (in module django.utils.cache), 879 get_model() (in module django.contrib.comments), 479 get_next_by_FOO() (Model method), 765 get_object_for_this_type() (models.ContentType method), 488 get_object_or_404() (in module django.shortcuts), 149 get_or_create() (in module django.db.models.QuerySet), 780 get_prep_lookup() (in module django.db.models), 362 get_prep_value() (in module django.db.models), 361 get_previous_by_FOO() (Model method), 765 get_prole() (models.User method), 254 get_readonly_elds() (ModelAdmin method), 458 get_tag_uri() (in module django.utils.feedgenerator), 882 get_template() (FormWizard method), 506 get_urls() (ModelAdmin method), 458 get_version() (BaseCommand method), 353 getlist() (QueryDict method), 797
Index
1049
gettext() (in module django.utils.translation), 884 gettext_lazy() (in module django.utils.translation), 884 gettext_noop() (in module django.utils.translation), 884 gis-contains eld lookup type, 543 gml (OGRGeometry attribute), 581 gml() (GeoQuerySet method), 555 gt eld lookup type, 785 gte eld lookup type, 786
icontains eld lookup type, 784 id.forms.IDLicensePlateField (class in django.contrib.localavor), 609 id.forms.IDLicensePlatePrexSelect (class in django.contrib.localavor), 609 id.forms.IDNationalIdentityNumberField (class in django.contrib.localavor), 609 id.forms.IDPhoneNumberField (class in django.contrib.localavor), 609 id.forms.IDPostCodeField (class in H django.contrib.localavor), 609 handle() (BaseCommand method), 353 id.forms.IDProvinceSelect (class in handle_app() (AppCommand method), 353 django.contrib.localavor), 609 handle_label() (LabelCommand method), 354 identify_epsg() (SpatialReference method), 587 handle_noargs() (NoArgsCommand method), 354 ie.forms.IECountySelect (class in handler404 (in module django.core.urlresolvers), 130 django.contrib.localavor), 609 handler500 (in module django.core.urlresolvers), 131 iendswith has_header() (HttpResponse method), 799 eld lookup type, 787 has_module_perms() (models.User method), 254 iexact has_next() (Page method), 322 eld lookup type, 783 has_other_pages() (Page method), 322 if has_perm() (models.User method), 253 template tag, 835 has_perms() (models.User method), 253 ifchanged has_previous() (Page method), 322 template tag, 838 has_usable_password() (models.User method), 253 ifequal hasz (GEOSGeometry attribute), 564 template tag, 839 head() (Client method), 240 ifnotequal height (File attribute), 680 template tag, 839 height_eld (ImageField attribute), 747 IGNORABLE_404_ENDS help (BaseCommand attribute), 352 setting, 813 help_text (Field attribute), 698, 742 IGNORABLE_404_STARTS hex (GEOSGeometry attribute), 564 setting, 813 hex (OGRGeometry attribute), 582 ImageField (class in django.db.models), 747 hexewkb (GEOSGeometry attribute), 564 ImageField (class in django.forms), 704 HiddenInput (class in django.forms), 710 import_epsg() (SpatialReference method), 587 history_view() (ModelAdmin method), 460 import_proj() (SpatialReference method), 587 HOST import_user_input() (SpatialReference method), 587 setting, 806 import_wkt() (SpatialReference method), 587 http_date() (in module django.utils.http), 883 import_xml() (SpatialReference method), 588 HttpRequest (class in django.http), 793 in HttpResponse (class in django.http), 798 eld lookup type, 784 HttpResponseBadRequest (class in django.http), 800 in.forms.INStateField (class in HttpResponseForbidden (class in django.http), 800 django.contrib.localavor), 609 HttpResponseGone (class in django.http), 800 in.forms.INStateSelect (class in HttpResponseNotAllowed (class in django.http), 800 django.contrib.localavor), 609 HttpResponseNotFound (class in django.http), 800 in.forms.INZipCodeField (class in HttpResponseNotModied (class in django.http), 800 django.contrib.localavor), 609 HttpResponsePermanentRedirect (class in django.http), in_bulk() (in module django.db.models.QuerySet), 781 800 include HttpResponseRedirect (class in django.http), 800 template tag, 839 HttpResponseServerError (class in django.http), 801 include() (in module django.core.urlresolvers), 131 index (Feature attribute), 578 1050 Index
index_template (AdminSite attribute), 468 info (GeoIP attribute), 591 initial (Field attribute), 697 initial (Form attribute), 685 inlines (ModelAdmin attribute), 454 input_date_formats (SplitDateTimeField attribute), 708 input_formats (DateField attribute), 701 input_formats (DateTimeField attribute), 702 input_formats (TimeField attribute), 706 input_time_formats (SplitDateTimeField attribute), 708 insert() (in module django.utils.datastructures), 880 inspectdb django-admin command, 664 INSTALLED_APPS setting, 813 int_to_base36() (in module django.utils.http), 883 IntegerField (class in django.db.models), 748 IntegerField (class in django.forms), 704 INTERNAL_IPS setting, 814 intersection() (GeoQuerySet method), 554 intersection() (OGRGeometry method), 583 intersects eld lookup type, 545 intersects() (GEOSGeometry method), 565 intersects() (OGRGeometry method), 582 intersects() (PreparedGeometry method), 570 inverse_attening (SpatialReference attribute), 588 ip_address (Comment attribute), 475 IPAddressField (class in django.db.models), 748 IPAddressField (class in django.forms), 705 iregex eld lookup type, 790 iri_to_uri() (in module django.utils.encoding), 881 iriencode template lter, 851 is_.forms.ISIdNumberField (class in django.contrib.localavor), 608 is_.forms.ISPhoneNumberField (class in django.contrib.localavor), 608 is_.forms.ISPostalCodeSelect (class in django.contrib.localavor), 609 is_active (models.User attribute), 252 is_ajax() (HttpRequest method), 796 is_anonymous() (models.User method), 253 is_authenticated() (models.User method), 253 is_bound (Form attribute), 683 is_protected_type() (in module django.utils.encoding), 881 is_public (Comment attribute), 475 is_removed (Comment attribute), 475 is_secure() (HttpRequest method), 796 is_staff (models.User attribute), 252 is_superuser (models.User attribute), 252
is_valid() (Form method), 684 isnull eld lookup type, 789 istartswith eld lookup type, 786 it.forms.ITProvinceSelect (class in django.contrib.localavor), 609 it.forms.ITRegionSelect (class in django.contrib.localavor), 610 it.forms.ITSocialSecurityNumberField (class in django.contrib.localavor), 609 it.forms.ITVatNumberField (class in django.contrib.localavor), 609 it.forms.ITZipCodeField (class in django.contrib.localavor), 609 item_attributes() (in module django.utils.feedgenerator), 882 item_geometry() (Feed method), 598 items (Sitemap attribute), 623 items() (QueryDict method), 797 iterator() (in module django.db.models.QuerySet), 781 iteritems() (QueryDict method), 797 iterlists() (QueryDict method), 797 itervalues() (QueryDict method), 797
J
Java, 405 javascript_catalog() (in module django.views.i18n), 308 join template lter, 851 jp.forms.JPPostalCodeField (class in django.contrib.localavor), 610 jp.forms.JPPrefectureSelect (class in django.contrib.localavor), 610 json (GEOSGeometry attribute), 564 json (OGRGeometry attribute), 582 JVM, 405 Jython, 405 JYTHONPATH, 406
K
kml (GEOSGeometry attribute), 565 kml (OGRGeometry attribute), 582 kml() (GeoQuerySet method), 555 kw.forms.KWCivilIDNumberField (class django.contrib.localavor), 610
in
L
label (Field attribute), 696 LabelCommand (built-in class), 353 language code, 317 LANGUAGE_CODE setting, 814 LANGUAGE_COOKIE_NAME 1051
Index
setting, 814 LANGUAGES setting, 814 last template lter, 852 last_login (models.User attribute), 252 last_name (models.User attribute), 252 lastmod (Sitemap attribute), 623 lat_lon() (GeoIP method), 591 latest() (in module django.db.models.QuerySet), 782 latest_post_date() (in module django.utils.feedgenerator), 882 Layer (class in django.contrib.gis.gdal), 574 layer_count (DataSource attribute), 574 layer_name (Feature attribute), 578 LayerMapping (class in django.contrib.gis.utils), 593 learn_cache_key() (in module django.utils.cache), 880 left eld lookup type, 546 length template lter, 852 length (GEOSGeometry attribute), 567 length() (GeoQuerySet method), 552 length_is template lter, 852 limit_choices_to (ForeignKey attribute), 750 limit_choices_to (ManyToManyField attribute), 751 linear_name (SpatialReference attribute), 588 linear_units (SpatialReference attribute), 588 LinearRing (class in django.contrib.gis.geos), 568 linebreaks template lter, 852 linebreaksbr template lter, 852 linenumbers template lter, 853 LineString (class in django.contrib.gis.gdal), 584 LineString (class in django.contrib.gis.geos), 568 LineStringField (class in django.contrib.gis.db.models), 534 list_display (ModelAdmin attribute), 451 list_display_links (ModelAdmin attribute), 453 list_editable (ModelAdmin attribute), 453 list_lter (ModelAdmin attribute), 453 list_per_page (ModelAdmin attribute), 454 list_select_related (ModelAdmin attribute), 454 lists() (QueryDict method), 797 ljust template lter, 853 ll (Envelope attribute), 586 load template tag, 840 loaddata django-admin command, 665
local (SpatialReference attribute), 588 locale name, 317 LOCALE_PATHS setting, 815 localize (Field attribute), 699 LocalTimezone (class in django.utils.tzinfo), 885 location (Sitemap attribute), 623 login() (Client method), 241 login() (in module django.contrib.auth), 257 LOGIN_REDIRECT_URL setting, 815 login_template (AdminSite attribute), 468 LOGIN_URL setting, 815 logout() (Client method), 241 logout() (in module django.contrib.auth), 258 logout_template (AdminSite attribute), 468 LOGOUT_URL setting, 815 lon_lat() (GeoIP method), 591 lower template lter, 853 lt eld lookup type, 786 lte eld lookup type, 786
M
mail_admins() (in module django.core.mail), 292 mail_managers() (in module django.core.mail), 293 make_line() (GeoQuerySet method), 557 make_list template lter, 853 make_random_password() (models.UserManager method), 254 MakeLine (class in django.contrib.gis.db.models), 558 makemessages django-admin command, 666 managed (Options attribute), 755 Manager (class in django.db.models), 99 MANAGERS setting, 815 ManyToManyField (class in django.db.models), 751 map_height (GeoModelAdmin attribute), 596 map_template (GeoModelAdmin attribute), 596 map_width (GeoModelAdmin attribute), 596 mapping() (in module django.contrib.gis.utils), 595 mark_for_escaping() (in module django.utils.safestring), 884 mark_safe() (in module django.utils.safestring), 884 match (FilePathField attribute), 704, 747 Max (class in django.db.models.QuerySet), 791 max_digits (DecimalField attribute), 702, 745 max_length (CharField attribute), 700, 744 Index
1052
max_length (URLField attribute), 707 max_value (DecimalField attribute), 702 max_value (IntegerField attribute), 704 max_x (Envelope attribute), 585 max_y (Envelope attribute), 586 MaxLengthValidator (built-in class), 889 MaxValueValidator (built-in class), 889 MEDIA_ROOT setting, 815 MEDIA_URL setting, 815 mem_size() (GeoQuerySet method), 556 merged (MultiLineString attribute), 569 message le, 317 META (HttpRequest attribute), 794 method (HttpRequest attribute), 793 MIDDLEWARE_CLASSES setting, 816 Min (class in django.db.models.QuerySet), 791 min_length (CharField attribute), 700 min_length (URLField attribute), 707 min_value (DecimalField attribute), 702 min_value (IntegerField attribute), 704 min_x (Envelope attribute), 585 min_y (Envelope attribute), 585 MinLengthValidator (built-in class), 889 MinValueValidator (built-in class), 889 model, 909 Model (class in django.db.models), 757 model (models.ContentType attribute), 487 model_class() (models.ContentType method), 488 ModelAdmin (class in django.contrib.admin), 447 ModelBackend (class in django.contrib.auth.backends), 439 ModelChoiceField (class in django.forms), 708 ModelMultipleChoiceField (class in django.forms), 709 models.AnonymousUser (class in django.contrib.auth), 256 models.ContentType (class in django.contrib.contenttypes), 487, 488 models.ContentTypeManager (class in django.contrib.contenttypes), 488 models.FlatPage (class in django.contrib.atpages), 500 models.Permission (class in django.contrib.auth), 266 models.Redirect (class in django.contrib.redirects), 621 models.User (class in django.contrib.auth), 252 models.UserManager (class in django.contrib.auth), 254 moderate() (CommentModerator method), 483 moderate_after (CommentModerator attribute), 482 Moderator (class in django.contrib.comments.moderation), 483 moderator.register() (in module django.contrib.comments.moderation), 483
moderator.unregister() (in module django.contrib.comments.moderation), 483 modiable (GeoModelAdmin attribute), 597 month eld lookup type, 788 MONTH_DAY_FORMAT setting, 816 MTV, 909 multi_db (TestCase attribute), 246 MultiLineString (class in django.contrib.gis.geos), 569 MultiLineStringField (class in django.contrib.gis.db.models), 534 multiple_chunks() (File method), 680 MultipleChoiceField (class in django.forms), 705 MultipleHiddenInput (class in django.forms), 710 MultiPoint (class in django.contrib.gis.geos), 569 MultiPointField (class in django.contrib.gis.db.models), 534 MultiPolygon (class in django.contrib.gis.geos), 569 MultiPolygonField (class in django.contrib.gis.db.models), 534 MultiValueField (class in django.forms), 707 MultiWidget (class in django.forms), 711 MVC, 909 mx.forms.MXStateSelect (class in django.contrib.localavor), 610
N
NAME setting, 806 name (DataSource attribute), 574 name (Field attribute), 578 name (File attribute), 679 name (Layer attribute), 575 name (models.ContentType attribute), 487 name (models.Permission attribute), 266 name (OGRGeomType attribute), 585 name (SpatialReference attribute), 588 next_page_number() (Page method), 322 ngettext() (in module django.utils.translation), 884 ngettext_lazy() (in module django.utils.translation), 884 nl.forms.NLPhoneNumberField (class in django.contrib.localavor), 608 nl.forms.NLProvinceSelect (class in django.contrib.localavor), 608 nl.forms.NLSoNumberField (class in django.contrib.localavor), 608 nl.forms.NLZipCodeField (class in django.contrib.localavor), 608 no.forms.NOMunicipalitySelect (class in django.contrib.localavor), 610 no.forms.NOSocialSecurityNumber (class in django.contrib.localavor), 610
Index
1053
no.forms.NOZipCodeField (class in django.contrib.localavor), 610 NoArgsCommand (built-in class), 354 none() (in module django.db.models.QuerySet), 773 now template tag, 840 null (Field attribute), 739 NullBooleanField (class in django.db.models), 748 NullBooleanField (class in django.forms), 705 NullBooleanSelect (class in django.forms), 711 num (OGRGeomType attribute), 585 num_coords (GEOSGeometry attribute), 563 num_coords (OGRGeometry attribute), 581 num_feat (Layer attribute), 575 num_elds (Feature attribute), 577 num_elds (Layer attribute), 575 num_geom (GEOSGeometry attribute), 563 num_geom() (GeoQuerySet method), 556 num_interior_rings (Polygon attribute), 568 num_items() (in module django.utils.feedgenerator), 882 num_pages (Paginator attribute), 322 num_points (OGRGeometry attribute), 581 num_points() (GeoQuerySet method), 556 number (Page attribute), 323 NUMBER_GROUPING setting, 817
overlaps eld lookup type, 545 overlaps() (GEOSGeometry method), 565 overlaps() (OGRGeometry method), 583 overlaps_above eld lookup type, 548 overlaps_below eld lookup type, 548 overlaps_left eld lookup type, 547 overlaps_right eld lookup type, 547
P
Page (class in django.core.paginator), 322 page() (Paginator method), 321 page_range (Paginator attribute), 322 Paginator (class in django.core.paginator), 321 paginator (Page attribute), 323 parent_link (OneToOneField attribute), 752 parse_params() (FormWizard method), 505 PASSWORD setting, 807 password (models.User attribute), 252 password_change_done_template (AdminSite attribute), 468 password_change_template (AdminSite attribute), 468 password_reset_complete() (in module django.contrib.auth), 263 password_reset_conrm() (in module django.contrib.auth), 262 PasswordChangeForm (class in django.contrib.auth.forms), 263 PasswordInput (class in django.forms), 709 PasswordResetForm (class in django.contrib.auth.forms), 263 patch_cache_control() (in module django.utils.cache), 879 patch_response_headers() (in module django.utils.cache), 879 patch_vary_headers() (in module django.utils.cache), 880 path (File attribute), 679 path (FilePathField attribute), 703, 747 path (HttpRequest attribute), 793 patterns() (in module django.core.urlresolvers), 129 pe.forms.PEDepartmentSelect (class in django.contrib.localavor), 610 pe.forms.PEDNIField (class in django.contrib.localavor), 610 pe.forms.PERUCField (class in django.contrib.localavor), 610 perimeter() (GeoQuerySet method), 552 permalink() (in module django.db.models), 763 permissions (Options attribute), 756 Index
O
object_history_template (ModelAdmin attribute), 457 object_list (Page attribute), 323 object_pk (Comment attribute), 474 ogr (GEOSGeometry attribute), 565 OGRGeometry (class in django.contrib.gis.gdal), 580 OGRGeomType (class in django.contrib.gis.gdal), 585 ogrinspect django-admin command, 595 ogrinspect() (in module django.contrib.gis.utils), 595 OneToOneField (class in django.db.models), 752 only() (in module django.db.models.QuerySet), 778 open() (django.contrib.gis.utils.GeoIP class method), 592 open() (FieldFile method), 746 open() (File method), 679 openlayers_url (GeoModelAdmin attribute), 596 option_list (BaseCommand attribute), 353 OPTIONS setting, 806 options() (Client method), 240 order_by() (in module django.db.models.QuerySet), 768 order_with_respect_to (Options attribute), 755 ordering (ModelAdmin attribute), 454 ordering (Options attribute), 756 OSMGeoAdmin (class in django.contrib.gis.admin), 597 outdim (WKBWriter attribute), 572 output_transaction (BaseCommand attribute), 353 1054
phone2numeric template lter, 854 ping_google() (in module django.contrib.sitemaps), 625 pk (Model attribute), 759 pl.forms.PLCountySelect (class in django.contrib.localavor), 611 pl.forms.PLNIPField (class in django.contrib.localavor), 611 pl.forms.PLPESELField (class in django.contrib.localavor), 611 pl.forms.PLPostalCodeField (class in django.contrib.localavor), 611 pl.forms.PLProvinceSelect (class in django.contrib.localavor), 611 pl.forms.PLREGONField (class in django.contrib.localavor), 611 pluralize template lter, 854 Point (class in django.contrib.gis.gdal), 584 Point (class in django.contrib.gis.geos), 568 point_count (OGRGeometry attribute), 580 point_on_surface (GEOSGeometry attribute), 567 point_on_surface() (GeoQuerySet method), 552 PointField (class in django.contrib.gis.db.models), 533 Polygon (class in django.contrib.gis.gdal), 584 Polygon (class in django.contrib.gis.geos), 568 PolygonField (class in django.contrib.gis.db.models), 534 PORT setting, 807 PositiveIntegerField (class in django.db.models), 748 PositiveSmallIntegerField (class in django.db.models), 748 POST (HttpRequest attribute), 794 post() (Client method), 239 post_save_moderation() (Moderator method), 483 POSTGIS_TEMPLATE setting, 599 POSTGIS_VERSION setting, 599 pprint template lter, 854 pre_init (django.db.models.signals attribute), 825 pre_save() (in module django.db.models), 362 pre_save_moderation() (Moderator method), 483 precision (Field attribute), 579 prex (Form attribute), 695 prex_for_step() (FormWizard method), 505 prepared (GEOSGeometry attribute), 567 PreparedGeometry (class in django.contrib.gis.geos), 570 PREPEND_WWW setting, 817 prepopulated_elds (ModelAdmin attribute), 454 pretty_wkt (SpatialReference attribute), 588 previous_page_number() (Page method), 322
primary_key (Field attribute), 742 priority() (Sitemap method), 624 process_exception(), 153 process_preview() (FormPreview method), 502 process_request(), 152 process_response(), 153 process_step() (FormWizard method), 506 process_view(), 153 PROFANITIES_LIST setting, 817 proj (SpatialReference attribute), 589 proj4 (SpatialReference attribute), 589 project, 909 projected (SpatialReference attribute), 588 property, 909 proxy (Options attribute), 756 pt.forms.PTPhoneNumberField (class django.contrib.localavor), 611 pt.forms.PTZipCodeField (class django.contrib.localavor), 611 put() (Client method), 240 Python Enhancement Proposals PEP 257, 232 PEP 8, 996
in in
Q
QueryDict (class in django.http), 796 queryset, 909 QuerySet (class in django.db.models.QuerySet), 767 queryset (ModelChoiceField attribute), 708 queryset (ModelMultipleChoiceField attribute), 709 queryset() (ModelAdmin method), 459
R
radio_elds (ModelAdmin attribute), 455 RadioSelect (class in django.forms), 711 random template lter, 854 range eld lookup type, 787 raw() (Manager method), 104 raw_id_elds (ModelAdmin attribute), 455 raw_post_data (HttpRequest attribute), 795 read() (File method), 679 readonly_elds (ModelAdmin attribute), 455 record_by_addr() (GeoIP method), 592 record_by_name() (GeoIP method), 592 recursive (FilePathField attribute), 703, 747 redirect() (in module django.shortcuts), 148 regex, 888 eld lookup type, 789 regex (RegexField attribute), 705 RegexField (class in django.forms), 705 RegexValidator (built-in class), 888 1055
Index
region_by_addr() (GeoIP method), 592 region_by_name() (GeoIP method), 592 regroup template tag, 841 relate eld lookup type, 545 relate() (GEOSGeometry method), 566 relate_pattern() (GEOSGeometry method), 566 related_name (ForeignKey attribute), 750 related_name (ManyToManyField attribute), 751 RelatedManager (class in django.db.models.elds.related), 752 RemoteUserBackend (class in django.contrib.auth.backends), 439 remove() (RelatedManager method), 753 removetags template lter, 855 render_comment_form template tag, 473 render_comment_list template tag, 471 render_hash_failure() (FormWizard method), 505 render_template() (FormWizard method), 506 render_to_response() (in module django.shortcuts), 147 render_value (PasswordInput attribute), 710 REQUEST (HttpRequest attribute), 794 request (Response attribute), 242 required (Field attribute), 696 requires_model_validation (BaseCommand attribute), 353 reset django-admin command, 667 resolve() (in module django.core.urlresolvers), 139 Response (class in django.test.client), 241 reverse() (in module django.core.urlresolvers), 138 reverse() (in module django.db.models.QuerySet), 769 reverse_geom() (GeoQuerySet method), 553 right eld lookup type, 547 ring (GEOSGeometry attribute), 564 rjust template lter, 855 ro.forms.ROCIFField (class in django.contrib.localavor), 611 ro.forms.ROCNPField (class in django.contrib.localavor), 611 ro.forms.ROCountyField (class in django.contrib.localavor), 611 ro.forms.ROCountySelect (class in django.contrib.localavor), 611 ro.forms.ROIBANField (class in django.contrib.localavor), 611 ro.forms.ROPhoneNumberField (class in django.contrib.localavor), 611
ro.forms.ROPostalCodeField (class in django.contrib.localavor), 611 root_attributes() (in module django.utils.feedgenerator), 882 ROOT_URLCONF setting, 817 Rss201rev2Feed (class in django.utils.feedgenerator), 883 RssFeed (class in django.utils.feedgenerator), 883 run_suite() (DjangoTestSuiteRunner method), 249 run_tests() (DjangoTestSuiteRunner method), 249 runfcgi django-admin command, 668 runserver django-admin command, 668
S
safe template lter, 855 safeseq template lter, 855 SafeString (class in django.utils.safestring), 884 SafeUnicode (class in django.utils.safestring), 884 same_as eld lookup type, 545 sample (in module django.db.models.QuerySet), 791, 792 save() (FieldFile method), 746 save() (File method), 680 save() (LayerMapping method), 594 save() (Model method), 759 save_as (ModelAdmin attribute), 455 save_formset() (ModelAdmin method), 458 save_model() (ModelAdmin method), 457 save_on_top (ModelAdmin attribute), 455 savepoint() (transaction method), 111 savepoint_commit() (transaction method), 111 savepoint_rollback() (transaction method), 111 scale() (GeoQuerySet method), 553 schema_path (in module django.db.models), 749 se.forms.SECountySelect (class in django.contrib.localavor), 612 se.forms.SEOrganisationNumber (class in django.contrib.localavor), 612 se.forms.SEPersonalIdentityNumber (class in django.contrib.localavor), 613 se.forms.SEPostalCodeField (class in django.contrib.localavor), 613 search eld lookup type, 789 search_elds (ModelAdmin attribute), 455 SECRET_KEY setting, 817 security_hash() (FormWizard method), 505 Select (class in django.forms), 710 Index
1056
select_related() (in module django.db.models.QuerySet), 773 SelectDateWidget (class in django.forms), 711 SelectMultiple (class in django.forms), 711 semi_major (SpatialReference attribute), 588 semi_minor (SpatialReference attribute), 588 send() (Signal method), 341 SEND_BROKEN_LINK_EMAILS setting, 817 send_mail() (in module django.core.mail), 291 send_mass_mail() (in module django.core.mail), 292 SERIALIZATION_MODULES setting, 818 SERVER_EMAIL setting, 818 session (Client attribute), 243 session (HttpRequest attribute), 795 SESSION_COOKIE_AGE setting, 818 SESSION_COOKIE_DOMAIN setting, 818 SESSION_COOKIE_NAME setting, 818 SESSION_COOKIE_PATH setting, 819 SESSION_COOKIE_SECURE setting, 819 SESSION_ENGINE setting, 818 SESSION_EXPIRE_AT_BROWSER_CLOSE setting, 819 SESSION_FILE_PATH setting, 819 SESSION_SAVE_EVERY_REQUEST setting, 819 set_cookie() (HttpResponse method), 800 set_language() (in module django.views.i18n), 310 set_password() (models.User method), 253 set_unusable_password() (models.User method), 253 setdefault() (QueryDict method), 796 setlist() (QueryDict method), 797 setlistdefault() (QueryDict method), 797 SetPasswordForm (class in django.contrib.auth.forms), 263 setting ABSOLUTE_URL_OVERRIDES, 803 ADMIN_FOR, 803 ADMIN_MEDIA_PREFIX, 803 ADMINS, 804 ALLOWED_INCLUDE_ROOTS, 804 APPEND_SLASH, 804 AUTH_PROFILE_MODULE, 804 AUTHENTICATION_BACKENDS, 804 CACHE_BACKEND, 804
CACHE_MIDDLEWARE_KEY_PREFIX, 804 CACHE_MIDDLEWARE_SECONDS, 805 COMMENT_MAX_LENGTH, 475 COMMENTS_APP, 475 COMMENTS_HIDE_REMOVED, 475 CSRF_COOKIE_DOMAIN, 805 CSRF_COOKIE_NAME, 805 CSRF_FAILURE_VIEW, 805 DATABASE_ENGINE, 823 DATABASE_HOST, 823 DATABASE_NAME, 823 DATABASE_OPTIONS, 823 DATABASE_PASSWORD, 823 DATABASE_PORT, 824 DATABASE_ROUTERS, 808 DATABASE_USER, 824 DATABASES, 805 DATE_FORMAT, 808 DATE_INPUT_FORMATS, 808 DATETIME_FORMAT, 808 DATETIME_INPUT_FORMATS, 808 DEBUG, 809 DECIMAL_SEPARATOR, 809 DEFAULT_CHARSET, 809 DEFAULT_CONTENT_TYPE, 809 DEFAULT_FROM_EMAIL, 810 DEFAULT_INDEX_TABLESPACE, 810 DEFAULT_TABLESPACE, 810 DISALLOWED_USER_AGENTS, 810 EMAIL_BACKEND, 810 EMAIL_FILE_PATH, 810 EMAIL_HOST, 810 EMAIL_HOST_PASSWORD, 811 EMAIL_HOST_USER, 811 EMAIL_PORT, 811 EMAIL_SUBJECT_PREFIX, 811 EMAIL_USE_TLS, 811 ENGINE, 806 FILE_CHARSET, 811 FILE_UPLOAD_HANDLERS, 811 FILE_UPLOAD_MAX_MEMORY_SIZE, 812 FILE_UPLOAD_PERMISSIONS, 812 FILE_UPLOAD_TEMP_DIR, 812 FIRST_DAY_OF_WEEK, 812 FIXTURE_DIRS, 812 FORMAT_MODULE_PATH, 813 GDAL_LIBRARY_PATH, 589 GEOIP_CITY, 590 GEOIP_COUNTRY, 590 GEOIP_LIBRARY_PATH, 590 GEOIP_PATH, 590 GEOS_LIBRARY_PATH, 573 HOST, 806 IGNORABLE_404_ENDS, 813
Index
1057
IGNORABLE_404_STARTS, 813 INSTALLED_APPS, 813 INTERNAL_IPS, 814 LANGUAGE_CODE, 814 LANGUAGE_COOKIE_NAME, 814 LANGUAGES, 814 LOCALE_PATHS, 815 LOGIN_REDIRECT_URL, 815 LOGIN_URL, 815 LOGOUT_URL, 815 MANAGERS, 815 MEDIA_ROOT, 815 MEDIA_URL, 815 MIDDLEWARE_CLASSES, 816 MONTH_DAY_FORMAT, 816 NAME, 806 NUMBER_GROUPING, 817 OPTIONS, 806 PASSWORD, 807 PORT, 807 POSTGIS_TEMPLATE, 599 POSTGIS_VERSION, 599 PREPEND_WWW, 817 PROFANITIES_LIST, 817 ROOT_URLCONF, 817 SECRET_KEY, 817 SEND_BROKEN_LINK_EMAILS, 817 SERIALIZATION_MODULES, 818 SERVER_EMAIL, 818 SESSION_COOKIE_AGE, 818 SESSION_COOKIE_DOMAIN, 818 SESSION_COOKIE_NAME, 818 SESSION_COOKIE_PATH, 819 SESSION_COOKIE_SECURE, 819 SESSION_ENGINE, 818 SESSION_EXPIRE_AT_BROWSER_CLOSE, 819 SESSION_FILE_PATH, 819 SESSION_SAVE_EVERY_REQUEST, 819 SHORT_DATE_FORMAT, 819 SHORT_DATETIME_FORMAT, 819 SITE_ID, 820 SPATIALITE_SQL, 601 TEMPLATE_CONTEXT_PROCESSORS, 820 TEMPLATE_DEBUG, 820 TEMPLATE_DIRS, 820 TEMPLATE_LOADERS, 821 TEMPLATE_STRING_IF_INVALID, 821 TEST_CHARSET, 807 TEST_COLLATION, 807 TEST_DATABASE_CHARSET, 824 TEST_DATABASE_COLLATION, 824 TEST_DATABASE_NAME, 824 TEST_MIRROR, 807 TEST_NAME, 807
TEST_RUNNER, 821 THOUSAND_SEPARATOR, 821 TIME_FORMAT, 821 TIME_INPUT_FORMATS, 821 TIME_ZONE, 822 URL_VALIDATOR_USER_AGENT, 822 USE_ETAGS, 822 USE_I18N, 822 USE_L10N, 822 USE_THOUSAND_SEPARATOR, 823 USER, 807 YEAR_MONTH_FORMAT, 823 setup_databases() (DjangoTestSuiteRunner method), 249 setup_test_environment() (DjangoTestSuiteRunner method), 249 setup_test_environment() (in module django.test.utils), 250 shell django-admin command, 669 shell (Polygon attribute), 584 SHORT_DATE_FORMAT setting, 819 SHORT_DATETIME_FORMAT setting, 819 shortcuts, 147 Signal (class in django.dispatch), 341 simple (GEOSGeometry attribute), 564 simplify() (GEOSGeometry method), 566 site (Comment attribute), 474 SITE_ID setting, 820 Sitemap (class in django.contrib.sitemaps), 623 size (File attribute), 679 sk.forms.SKDistrictSelect (class in django.contrib.localavor), 612 sk.forms.SKPostalCodeField (class in django.contrib.localavor), 612 sk.forms.SKRegionSelect (class in django.contrib.localavor), 612 slice template lter, 855 slug, 909 SlugField (class in django.db.models), 748 SlugField (class in django.forms), 706 slugify template lter, 856 SmallIntegerField (class in django.db.models), 749 smart_str() (in module django.utils.encoding), 881 smart_unicode() (in module django.utils.encoding), 881 SMTPConnection (class in django.core.mail), 299 snap_to_grid() (GeoQuerySet method), 553 spaceless template tag, 843 spatial_lter (Layer attribute), 576
1058
Index
spatial_index (GeometryField attribute), 535 SPATIALITE_SQL setting, 601 SpatialReference (class in django.contrib.gis.gdal), 586 SplitDateTimeField (class in django.forms), 708 SplitDateTimeWidget (class in django.forms), 711 sql django-admin command, 669 sqlall django-admin command, 669 sqlclear django-admin command, 670 sqlcustom django-admin command, 670 sqlush django-admin command, 670 sqlindexes django-admin command, 670 sqlreset django-admin command, 670 sqlsequencereset django-admin command, 670 srid (GeometryField attribute), 534 srid (GEOSGeometry attribute), 564 srid (OGRGeometry attribute), 581 srid (SpatialReference attribute), 588 srid (WKBWriter attribute), 572 srs (GEOSGeometry attribute), 567 srs (Layer attribute), 576 srs (OGRGeometry attribute), 581 ssi template tag, 843 start_index() (Page method), 322 startapp django-admin command, 671 startproject django-admin command, 671 startswith eld lookup type, 786 status_code (HttpResponse attribute), 799 status_code (Response attribute), 242 StdDev (class in django.db.models.QuerySet), 791 storage (FileField attribute), 746 StrAndUnicode (class in django.utils.encoding), 881 strictly_above eld lookup type, 548 strictly_below eld lookup type, 548 string_concat() (in module django.utils.translation), 885 stringformat template lter, 856 striptags template lter, 856 submit_date (Comment attribute), 475
suite_result() (DjangoTestSuiteRunner method), 250 Sum (class in django.db.models.QuerySet), 791 svg() (GeoQuerySet method), 555 sym_difference() (GeoQuerySet method), 554 sym_difference() (GEOSGeometry method), 566 sym_difference() (OGRGeometry method), 583 symmetrical (ManyToManyField attribute), 751 syncdb django-admin command, 671 SyndicationFeed (class in django.utils.feedgenerator), 882
T
teardown_databases() (DjangoTestSuiteRunner method), 249 teardown_test_environment() (DjangoTestSuiteRunner method), 250 teardown_test_environment() (in module django.test.utils), 250 tell() (HttpResponse method), 800 template, 909 template (Response attribute), 242 template lter add, 846 addslashes, 846 caprst, 847 center, 847 cut, 847 date, 847 default, 848 default_if_none, 848 dictsort, 848 dictsortreversed, 849 divisibleby, 849 escape, 849 escapejs, 849 lesizeformat, 850 rst, 850 x_ampersands, 850 oatformat, 850 force_escape, 851 get_digit, 851 iriencode, 851 join, 851 last, 852 length, 852 length_is, 852 linebreaks, 852 linebreaksbr, 852 linenumbers, 853 ljust, 853 lower, 853 make_list, 853 phone2numeric, 854 1059
Index
pluralize, 854 pprint, 854 random, 854 removetags, 855 rjust, 855 safe, 855 safeseq, 855 slice, 855 slugify, 856 stringformat, 856 striptags, 856 time, 856 timesince, 857 timeuntil, 857 title, 858 truncatewords, 858 truncatewords_html, 858 unordered_list, 858 upper, 859 urlencode, 859 urlize, 859 urlizetrunc, 859 wordcount, 860 wordwrap, 860 yesno, 860 template tag autoescape, 831 block, 831 comment, 831 comment_form_target, 473 csrf_token, 831 cycle, 831 debug, 833 extends, 833 lter, 833 rstof, 833 for, 834 get_comment_count, 472 get_comment_form, 473 get_comment_list, 471 get_comment_permalink, 472 if, 835 ifchanged, 838 ifequal, 839 ifnotequal, 839 include, 839 load, 840 now, 840 regroup, 841 render_comment_form, 473 render_comment_list, 471 spaceless, 843 ssi, 843 templatetag, 844
url, 844 widthratio, 845 with, 846 TEMPLATE_CONTEXT_PROCESSORS setting, 820 TEMPLATE_DEBUG setting, 820 TEMPLATE_DIRS setting, 820 TEMPLATE_LOADERS setting, 821 TEMPLATE_STRING_IF_INVALID setting, 821 templatetag template tag, 844 templatize() (in module django.utils.translation), 885 test django-admin command, 672 test_capability() (Layer method), 577 TEST_CHARSET setting, 807 TEST_COLLATION setting, 807 TEST_DATABASE_CHARSET setting, 824 TEST_DATABASE_COLLATION setting, 824 TEST_DATABASE_NAME setting, 824 TEST_MIRROR setting, 807 TEST_NAME setting, 807 TEST_RUNNER setting, 821 TestCase (class in django.test), 243 testserver django-admin command, 672 Textarea (class in django.forms), 710 TextField (class in django.db.models), 749 TextInput (class in django.forms), 709 THOUSAND_SEPARATOR setting, 821 through (ManyToManyField attribute), 751 time template lter, 856 TIME_FORMAT setting, 821 TIME_INPUT_FORMATS setting, 821 TIME_ZONE setting, 822 TimeField (class in django.db.models), 749 TimeField (class in django.forms), 706
1060
Index
TimeInput (class in django.forms), 710 timesince template lter, 857 timeuntil template lter, 857 title template lter, 858 to_esri() (SpatialReference method), 587 to_eld (ForeignKey attribute), 751 to_locale() (in module django.utils.translation), 885 to_python() (in module django.db.models), 360 touches eld lookup type, 546 touches() (GEOSGeometry method), 566 touches() (OGRGeometry method), 583 TransactionTestCase (class in django.test), 243 transform() (GeoQuerySet method), 553 transform() (in module django.contrib.gis.geos), 567 transform() (OGRGeometry method), 582 translate() (GeoQuerySet method), 553 translation string, 317 truncatewords template lter, 858 truncatewords_html template lter, 858 tuple (Envelope attribute), 586 tuple (OGRGeometry attribute), 583 type (Field attribute), 578 type_name (Field attribute), 578 TypedChoiceField (class in django.forms), 701
U
ugettext() (in module django.utils.translation), 884 ugettext_lazy() (in module django.utils.translation), 884 uk.forms.UKCountySelect (class in django.contrib.localavor), 613 uk.forms.UKNationSelect (class in django.contrib.localavor), 613 uk.forms.UKPostcodeField (class in django.contrib.localavor), 613 ungettext() (in module django.utils.translation), 884 ungettext_lazy() (in module django.utils.translation), 884 Union (class in django.contrib.gis.db.models), 558 union() (GeoQuerySet method), 554 union() (GEOSGeometry method), 566 union() (OGRGeometry method), 583 unionagg() (GeoQuerySet method), 557 unique (Field attribute), 742 unique_for_date (Field attribute), 742 unique_for_month (Field attribute), 743 unique_for_year (Field attribute), 743 unique_together (Options attribute), 756 unit_attname() (django.contrib.gis.measure.Area class method), 561 Index
unit_attname() (django.contrib.gis.measure.Distance class method), 560 units (SpatialReference attribute), 588 unordered_list template lter, 858 update() (QueryDict method), 796 upload_to (FileField attribute), 745 UploadedFile (class in django.core.les), 145 upper template lter, 859 ur (Envelope attribute), 586 url template tag, 844 url (File attribute), 679 url() (in module django.core.urlresolvers), 130 URL_VALIDATOR_USER_AGENT setting, 822 urlconf (HttpRequest attribute), 795 urlencode template lter, 859 urlencode() (in module django.utils.http), 883 urlencode() (QueryDict method), 798 URLField (class in django.db.models), 749 URLField (class in django.forms), 706 urlize template lter, 859 urlizetrunc template lter, 859 urlquote() (in module django.utils.http), 883 urlquote_plus() (in module django.utils.http), 883 urls denitive, 901 urls (TestCase attribute), 245 URLValidator (built-in class), 888 us.forms.USPhoneNumberField (class in django.contrib.localavor), 614 us.forms.USSocialSecurityNumberField (class in django.contrib.localavor), 614 us.forms.USStateField (class in django.contrib.localavor), 614 us.forms.USStateSelect (class in django.contrib.localavor), 614 us.forms.USZipCodeField (class in django.contrib.localavor), 614 us.models.PhoneNumberField (class in django.contrib.localavor), 614 us.models.USStateField (class in django.contrib.localavor), 614 USE_ETAGS setting, 822 USE_I18N setting, 822 USE_L10N setting, 822
1061
USE_THOUSAND_SEPARATOR setting, 823 USER setting, 807 user (Comment attribute), 475 user (HttpRequest attribute), 795 user_email (Comment attribute), 475 user_name (Comment attribute), 475 user_url (Comment attribute), 475 UserChangeForm (class in django.contrib.auth.forms), 263 UserCreationForm (class in django.contrib.auth.forms), 263 username (models.User attribute), 252 using() (in module django.db.models.QuerySet), 778 uy.forms.UYCIField (class in django.contrib.localavor), 614 uy.forms.UYDepartamentSelect (class in django.contrib.localavor), 614
module
W3CGeoFeed (class in django.contrib.gis.feeds), 598 week_day eld lookup type, 788 Widget, 163 widget (Field attribute), 698 widget (Form attribute), 711 width (Field attribute), 579 width (File attribute), 680 width_eld (ImageField attribute), 748 widthratio template tag, 845 with template tag, 846 within eld lookup type, 546 within() (GEOSGeometry method), 566 V within() (OGRGeometry method), 583 valid (GEOSGeometry attribute), 564 wkb (GEOSGeometry attribute), 565 validate wkb (OGRGeometry attribute), 582 django-admin command, 673 wkb_size (OGRGeometry attribute), 582 validate() (SpatialReference method), 587 WKBReader (class in django.contrib.gis.geos), 571 validate_unique() (Model method), 759 WKBWriter (class in django.contrib.gis.geos), 571 validator_user_agent (URLField attribute), 707 wkt (Envelope attribute), 586 validators (Field attribute), 699, 743 wkt (GEOSGeometry attribute), 565 value (Field attribute), 578 wkt (OGRGeometry attribute), 582 value_for_index() (in module django.utils.datastructures), wkt (SpatialReference attribute), 588 880 WKTReader (class in django.contrib.gis.geos), 571 value_to_string() (in module django.db.models), 364 WKTWriter (class in django.contrib.gis.geos), 573 values() (in module django.db.models.QuerySet), 770 wordcount values() (QueryDict method), 797 template lter, 860 values_list() (in module django.db.models.QuerySet), 771 wordwrap Variance (class in django.db.models.QuerySet), 792 template lter, 860 verbose_name (Field attribute), 743 write() (File method), 680 verbose_name (Options attribute), 757 write() (HttpResponse method), 800 verbose_name_plural (Options attribute), 757 write() (in module django.utils.feedgenerator), 882 verify_exists (URLField attribute), 707, 749 write() (SyndicationFeed method), 645 view, 909 write() (WKBWriter method), 571 views.login() (in module django.contrib.auth), 259 write() (WKTWriter method), 573 views.logout() (in module django.contrib.auth), 261 write_hex() (WKBWriter method), 572 views.logout_then_login() (in module writeString() (in module django.utils.feedgenerator), 882 django.contrib.auth), 261 writeString() (SyndicationFeed method), 645 views.password_change() (in module X django.contrib.auth), 261 views.password_change_done() (in module x (LineString attribute), 584 django.contrib.auth), 261 x (Point attribute), 584 views.password_reset() (in module django.contrib.auth), xml 261 suckiness of, 902 views.password_reset_done() (in module xml (SpatialReference attribute), 589 django.contrib.auth), 262 XMLField (class in django.db.models), 749
1062
Index
Y
y (LineString attribute), 584 y (Point attribute), 584 year eld lookup type, 787 YEAR_MONTH_FORMAT setting, 823 yesno template lter, 860
Z
z (LineString attribute), 584 z (Point attribute), 584 za.forms.ZAIDField (class in django.contrib.localavor), 612 za.forms.ZAPostCodeField (class in django.contrib.localavor), 612
Index
1063