APress The Definitive Guide To Django
User Manual:
Open the PDF directly: View PDF .
Page Count: 474
Download | ![]() |
Open PDF In Browser | View PDF |
7257ch00FM.qxd 11/9/07 12:37 PM Page i The Definitive Guide to Django Web Development Done Right Adrian Holovaty and Jacob Kaplan-Moss 7257ch00FM.qxd 11/9/07 12:37 PM Page ii The Definitive Guide to Django: Web Development Done Right Copyright © 2008 by Adrian Holovaty and Jacob Kaplan-Moss All rights reserved. No part of this work may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording, or by any information storage or retrieval system, without the prior written permission of the copyright owner and the publisher. ISBN-13 (pbk): 978-1-59059-725-5 ISBN-10 (pbk): 1-59059-725-7 ISBN-13 (electronic): 978-1-4302-0331-5 ISBN-10 (electronic): 1-4302-0331-5 Printed and bound in the United States of America 9 8 7 6 5 4 3 2 1 Trademarked names may appear in this book. Rather than use a trademark symbol with every occurrence of a trademarked name, we use the names only in an editorial fashion and to the benefit of the trademark owner, with no intention of infringement of the trademark. Lead Editor: Jason Gilmore Technical Reviewer: Jeremy Dunck Editorial Board: Steve Anglin, Ewan Buckingham, Tony Campbell, Gary Cornell, Jonathan Gennick, Jason Gilmore, Kevin Goff, Jonathan Hassell, Matthew Moodie, Joseph Ottinger, Jeffrey Pepper, Ben Renow-Clarke, Dominic Shakeshaft, Matt Wade, Tom Welsh Project Manager | Production Director: Grace Wong Copy Editor: Nicole Flores Associate Production Director: Kari Brooks-Copony Production Editor: Ellie Fountain Compositor and Artist: Kinetic Publishing Services, LLC Proofreaders: Lori Bring and Christy Wagner Indexer: Brenda Miller Cover Designer: Kurt Krames Manufacturing Director: Tom Debolski Distributed to the book trade worldwide by Springer-Verlag New York, Inc., 233 Spring Street, 6th Floor, New York, NY 10013. Phone 1-800-SPRINGER, fax 201-348-4505, e-mail orders-ny@springer-sbm.com, or visit http://www.springeronline.com. For information on translations, please contact Apress directly at 2855 Telegraph Avenue, Suite 600, Berkeley, CA 94705. Phone 510-549-5930, fax 510-549-5939, e-mail info@apress.com, or visit http://www.apress.com. The information in this book is distributed on an “as is” basis, without warranty. Although every precaution has been taken in the preparation of this work, neither the author(s) nor Apress shall have any liability to any person or entity with respect to any loss or damage caused or alleged to be caused directly or indirectly by the information contained in this work. The source code for this book is available to readers at http://www.apress.com and at http://www.djangobook.com. 7257ch00FM.qxd 11/9/07 12:37 PM Page iv Contents at a Glance About the Authors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxvii About the Technical Reviewer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxviii Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxix Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxxi PART 1 ■CHAPTER ■CHAPTER ■CHAPTER ■CHAPTER ■CHAPTER ■CHAPTER ■CHAPTER ■CHAPTER PART 2 ■CHAPTER ■CHAPTER ■CHAPTER ■CHAPTER ■CHAPTER ■CHAPTER ■CHAPTER ■CHAPTER ■CHAPTER ■CHAPTER ■CHAPTER ■CHAPTER iv ■■■ 1 2 3 4 5 6 7 8 Introduction to Django . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 The Basics of Dynamic Web Pages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 The Django Template System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 Interacting with a Database: Models . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 The Django Administration Site. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 Form Processing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 Advanced Views and URLconfs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 ■■■ 9 10 11 12 13 14 15 16 17 18 19 20 Getting Started Django’s Subframeworks Generic Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 Extending the Template Engine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 Generating Non-HTML Content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157 Sessions, Users, and Registration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 Caching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 Other Contributed Subframeworks . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209 Middleware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227 Integrating with Legacy Databases and Applications . . . . . . . . . . . 235 Extending Django’s Admin Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . 241 Internationalization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251 Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265 Deploying Django . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275 7257ch00FM.qxd 11/9/07 12:37 PM PART 3 ■■■ ■APPENDIX ■APPENDIX ■APPENDIX ■APPENDIX ■APPENDIX ■APPENDIX ■APPENDIX ■APPENDIX A B C D E F G H Page v Appendixes Case Studies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297 Model Definition Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305 Database API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333 Generic View Reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359 Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379 Built-in Template Tags and Filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395 The django-admin Utility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415 Request and Response Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425 ■INDEX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433 v 7257ch00FM.qxd 11/9/07 12:37 PM Page vii Contents About the Authors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxvii About the Technical Reviewer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxviii Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxix Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxxi PART 1 ■■■ ■CHAPTER 1 Getting Started Introduction to Django . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 What Is a Web Framework? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 The MVC Design Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Django’s History . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 How to Read This Book. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 Required Programming Knowledge . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 Required Python Knowledge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 New Django Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 Getting Help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 What’s Next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 ■CHAPTER 2 Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Installing Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Installing Django . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Installing an Official Release . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Installing Django from Subversion . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 Setting Up a Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 Using Django with PostgreSQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 Using Django with SQLite 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 Using Django with MySQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 Using Django Without a Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 Starting a Project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 The Development Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 What’s Next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 vii 7257ch00FM.qxd viii 11/9/07 12:37 PM Page viii ■CONTENTS ■CHAPTER 3 The Basics of Dynamic Web Pages . . . . . . . . . . . . . . . . . . . . . . . . 17 Your First View: Dynamic Content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 Mapping URLs to Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 How Django Processes a Request . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 How Django Processes a Request: Complete Details . . . . . . . . . . . . 22 URLconfs and Loose Coupling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 404 Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 Your Second View: Dynamic URLs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 A Word About Pretty URLs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 Wildcard URLpatterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 Django’s Pretty Error Pages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 What’s Next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 ■CHAPTER 4 The Django Template System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 Template System Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 Using the Template System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 Creating Template Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 Rendering a Template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 Multiple Contexts, Same Template . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 Context Variable Lookup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 Playing with Context Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 Basic Template Tags and Filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 Tags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 Filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 Philosophies and Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 Using Templates in Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 Template Loading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 render_to_response() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 The locals() Trick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 Subdirectories in get_template() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 The include Template Tag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 Template Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 What’s Next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 ■CHAPTER 5 Interacting with a Database: Models . . . . . . . . . . . . . . . . . . . . . . 59 The “Dumb” Way to Do Database Queries in Views . . . . . . . . . . . . . . . . . . 59 The MTV Development Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 Configuring the Database. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 Your First App . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 7257ch00FM.qxd 11/9/07 12:37 PM Page ix ■CONTENTS Defining Models in Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 Your First Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 Installing the Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 Basic Data Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 Adding Model String Representations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 Inserting and Updating Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 Selecting Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 Filtering Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 Retrieving Single Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 Ordering Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 Chaining Lookups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 Slicing Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 Deleting Objects. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 Making Changes to a Database Schema. . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 Adding Fields . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 Removing Fields . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 Removing Many-to-Many Fields . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 Removing Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 What’s Next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 ■CHAPTER 6 The Django Administration Site . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 Activating the Admin Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 Using the Admin Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 Users, Groups, and Permissions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 Customizing the Admin Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 Customizing the Admin Interface’s Look and Feel . . . . . . . . . . . . . . . . . . . . 93 Customizing the Admin Index Page . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 When and Why to Use the Admin Interface . . . . . . . . . . . . . . . . . . . . . . . . . . 94 What’s Next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 ■CHAPTER 7 Form Processing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 Search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 The “Perfect Form” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 Creating a Feedback Form . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 Processing the Submission . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 Custom Validation Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 A Custom Look and Feel. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 Creating Forms from Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 What’s Next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 ix 7257ch00FM.qxd x 11/9/07 12:37 PM Page x ■CONTENTS ■CHAPTER 8 Advanced Views and URLconfs . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 URLconf Tricks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 Streamlining Function Imports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 Using Multiple View Prefixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 Special-Casing URLs in Debug Mode . . . . . . . . . . . . . . . . . . . . . . . . . 109 Using Named Groups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 Understanding the Matching/Grouping Algorithm . . . . . . . . . . . . . . 112 Passing Extra Options to View Functions . . . . . . . . . . . . . . . . . . . . . . 112 Using Default View Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 Special-Casing Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118 Capturing Text in URLs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119 Determining What the URLconf Searches Against . . . . . . . . . . . . . . 119 Including Other URLconfs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120 How Captured Parameters Work with include() . . . . . . . . . . . . . . . . 121 How Extra URLconf Options Work with include() . . . . . . . . . . . . . . . 121 What’s Next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 PART 2 ■■■ ■CHAPTER 9 Django’s Subframeworks Generic Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 Using Generic Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 Generic Views of Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 Extending Generic Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 Making “Friendly” Template Contexts . . . . . . . . . . . . . . . . . . . . . . . . 128 Adding Extra Context . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129 Viewing Subsets of Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 Complex Filtering with Wrapper Functions . . . . . . . . . . . . . . . . . . . . 131 Performing Extra Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 What’s Next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 ■CHAPTER 10 Extending the Template Engine . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 Template Language Review. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 RequestContext and Context Processors. . . . . . . . . . . . . . . . . . . . . . . . . . . 136 django.core.context_processors.auth . . . . . . . . . . . . . . . . . . . . . . . . 140 django.core.context_processors.debug . . . . . . . . . . . . . . . . . . . . . . . 140 django.core.context_processors.i18n . . . . . . . . . . . . . . . . . . . . . . . . 140 django.core.context_processors.request. . . . . . . . . . . . . . . . . . . . . . 141 Guidelines for Writing Your Own Context Processors . . . . . . . . . . . . 141 7257ch00FM.qxd 11/9/07 12:37 PM Page xi ■CONTENTS Inside Template Loading. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141 Extending the Template System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142 Creating a Template Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142 Writing Custom Template Filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 Writing Custom Template Tags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145 Shortcut for Simple Tags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150 Inclusion Tags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151 Writing Custom Template Loaders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152 Using the Built-in Template Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 Configuring the Template System in Standalone Mode . . . . . . . . . . . . . . 154 What’s Next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155 ■CHAPTER 11 Generating Non-HTML Content . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157 The Basics: Views and MIME Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157 Producing CSV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158 Generating PDFs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159 Installing ReportLab. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160 Writing Your View . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160 Complex PDFs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 Other Possibilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162 The Syndication Feed Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162 Initialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 A Simple Feed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 A More Complex Feed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 Specifying the Type of Feed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 Enclosures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 Language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168 URLs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168 Publishing Atom and RSS Feeds in Tandem . . . . . . . . . . . . . . . . . . . 168 The Sitemap Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 Initialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170 Sitemap Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170 Shortcuts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 Creating a Sitemap Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172 Pinging Google . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173 What’s Next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174 xi 7257ch00FM.qxd xii 11/9/07 12:37 PM Page xii ■CONTENTS ■CHAPTER 12 Sessions, Users, and Registration . . . . . . . . . . . . . . . . . . . . . . . . 175 Cookies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 Getting and Setting Cookies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176 The Mixed Blessing of Cookies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177 Django’s Session Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178 Enabling Sessions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178 Using Sessions in Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 Setting Test Cookies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180 Using Sessions Outside of Views. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 When Sessions Are Saved . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 Browser-Length Sessions vs. Persistent Sessions . . . . . . . . . . . . . . 182 Other Session Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 Users and Authentication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183 Enabling Authentication Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184 Using Users . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184 Logging In and Out . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186 Limiting Access to Logged-in Users . . . . . . . . . . . . . . . . . . . . . . . . . . 188 Limiting Access to Users Who Pass a Test. . . . . . . . . . . . . . . . . . . . . 189 Managing Users, Permissions, and Groups . . . . . . . . . . . . . . . . . . . . 190 Using Authentication Data in Templates . . . . . . . . . . . . . . . . . . . . . . 193 The Other Bits: Permissions, Groups, Messages, and Profiles . . . . . . . . . 193 Permissions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193 Groups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195 Profiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 What’s Next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 ■CHAPTER 13 Caching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 Setting Up the Cache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 Memcached . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 Database Caching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199 Filesystem Caching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199 Local-Memory Caching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 Simple Caching (for Development) . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 Dummy Caching (for Development) . . . . . . . . . . . . . . . . . . . . . . . . . . 200 CACHE_BACKEND Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 The Per-Site Cache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 The Per-View Cache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202 Specifying Per-View Cache in the URLconf . . . . . . . . . . . . . . . . . . . . 203 7257ch00FM.qxd 11/9/07 12:37 PM Page xiii ■CONTENTS The Low-Level Cache API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 Upstream Caches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204 Using Vary Headers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205 Other Cache Headers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207 Other Optimizations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208 Order of MIDDLEWARE_CLASSES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208 What’s Next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208 ■CHAPTER 14 Other Contributed Subframeworks . . . . . . . . . . . . . . . . . . . . . . . 209 The Django Standard Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209 Sites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210 Scenario 1: Reusing Data on Multiple Sites . . . . . . . . . . . . . . . . . . . 210 Scenario 2: Storing Your Site Name/Domain in One Place . . . . . . . 211 How to Use the Sites Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211 The Sites Framework’s Capabilities . . . . . . . . . . . . . . . . . . . . . . . . . . 212 CurrentSiteManager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215 How Django Uses the Sites Framework . . . . . . . . . . . . . . . . . . . . . . . 216 Flatpages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216 Using Flatpages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 Adding, Changing, and Deleting Flatpages . . . . . . . . . . . . . . . . . . . . 218 Using Flatpage Templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219 Redirects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219 Using the Redirects Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220 Adding, Changing, and Deleting Redirects . . . . . . . . . . . . . . . . . . . . 220 CSRF Protection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221 A Simple CSRF Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221 A More Complex CSRF Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221 Preventing CSRF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222 Form Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223 django.contrib.formtools.preview . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223 Using FormPreview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224 Humanizing Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 apnumber . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 intcomma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 intword. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 ordinal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226 Markup Filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226 What’s Next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226 xiii 7257ch00FM.qxd xiv 11/9/07 12:37 PM Page xiv ■CONTENTS ■CHAPTER 15 Middleware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227 What’s Middleware? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227 Middleware Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228 Middleware Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229 Initializer: __init__(self) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229 Request Preprocessor: process_request(self, request) . . . . . . . . . . 229 View Preprocessor: process_view(self, request, view, args, kwargs) . . . . . . . . . . . . . 229 Response Postprocessor: process_response(self, request, response) . . . . . . . . . . . . . . . . . 230 Exception Postprocessor: process_exception(self, request, exception) . . . . . . . . . . . . . . . . 230 Built-in Middleware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230 Authentication Support Middleware . . . . . . . . . . . . . . . . . . . . . . . . . . 231 “Common” Middleware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231 Compression Middleware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232 Conditional GET Middleware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232 Reverse Proxy Support (X-Forwarded-For Middleware) . . . . . . . . . 232 Session Support Middleware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232 Sitewide Cache Middleware. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233 Transaction Middleware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233 “X-View” Middleware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233 What’s Next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233 ■CHAPTER 16 Integrating with Legacy Databases and Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 Integrating with a Legacy Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 Using inspectdb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 Cleaning Up Generated Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236 Integrating with an Authentication System . . . . . . . . . . . . . . . . . . . . . . . . . 237 Specifying Authentication Back-Ends. . . . . . . . . . . . . . . . . . . . . . . . . 237 Writing an Authentication Back-End . . . . . . . . . . . . . . . . . . . . . . . . . . 237 Integrating with Legacy Web Applications. . . . . . . . . . . . . . . . . . . . . . . . . . 239 What’s Next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240 7257ch00FM.qxd 11/9/07 12:37 PM Page xv ■CONTENTS ■CHAPTER 17 Extending Django’s Admin Interface . . . . . . . . . . . . . . . . . . . . . 241 The Zen of Admin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242 “Trusted users . . .” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242 “. . . editing . . .” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242 “. . . structured content” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243 Full Stop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243 Customizing Admin Templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243 Custom Model Templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244 Custom JavaScript. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245 Creating Custom Admin Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246 Overriding Built-in Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249 What’s Next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249 ■CHAPTER 18 Internationalization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251 Specifying Translation Strings in Python Code . . . . . . . . . . . . . . . . . . . . . . 252 Standard Translation Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252 Marking Strings As No-op . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253 Lazy Translation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253 Pluralization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254 Specifying Translation Strings in Template Code . . . . . . . . . . . . . . . . . . . . 254 Creating Language Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256 Creating Message Files. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256 Compiling Message Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258 How Django Discovers Language Preference. . . . . . . . . . . . . . . . . . . . . . . 258 The set_language Redirect View . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260 Using Translations in Your Own Projects . . . . . . . . . . . . . . . . . . . . . . . . . . . 261 Translations and JavaScript. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262 The javascript_catalog View . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262 Using the JavaScript Translation Catalog . . . . . . . . . . . . . . . . . . . . . 263 Creating JavaScript Translation Catalogs . . . . . . . . . . . . . . . . . . . . . 263 Notes for Users Familiar with gettext . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264 What’s Next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264 ■CHAPTER 19 Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265 The Theme of Web Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265 SQL Injection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266 The Solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266 xv 7257ch00FM.qxd xvi 11/9/07 12:37 PM Page xvi ■CONTENTS Cross-Site Scripting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267 The Solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268 Cross-Site Request Forgery . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269 Session Forging/Hijacking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269 The Solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270 Email Header Injection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271 The Solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271 Directory Traversal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271 The Solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272 Exposed Error Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273 The Solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273 A Final Word on Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273 What’s Next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273 ■CHAPTER 20 Deploying Django . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275 Shared Nothing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276 A Note on Personal Preferences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278 Using Django with Apache and mod_python . . . . . . . . . . . . . . . . . . . . . . . 278 Basic Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279 Running Multiple Django Installations on the Same Apache Instance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280 Running a Development Server with mod_python. . . . . . . . . . . . . . 280 Serving Django and Media Files from the Same Apache Instance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281 Error Handling. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281 Handling a Segmentation Fault . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282 Using Django with FastCGI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282 FastCGI Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282 Running Your FastCGI Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283 Using Django with Apache and FastCGI . . . . . . . . . . . . . . . . . . . . . . . 284 FastCGI and lighttpd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285 Running Django on a Shared-Hosting Provider with Apache . . . . . 287 Scaling. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288 Running on a Single Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288 Separating Out the Database Server . . . . . . . . . . . . . . . . . . . . . . . . . 289 Running a Separate Media Server . . . . . . . . . . . . . . . . . . . . . . . . . . . 289 Implementing Load Balancing and Redundancy . . . . . . . . . . . . . . . 290 Going Big . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292 7257ch00FM.qxd 11/9/07 12:37 PM Page xvii ■CONTENTS Performance Tuning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293 There’s No Such Thing As Too Much RAM . . . . . . . . . . . . . . . . . . . . . 293 Turn Off Keep-Alive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293 Use Memcached . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294 Use Memcached Often . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294 Join the Conversation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294 What’s Next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294 PART 3 ■■■ ■APPENDIX A Appendixes Case Studies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297 Cast of Characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297 Why Django? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299 Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299 Porting Existing Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300 How Did It Go? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300 Team Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302 Deployment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303 ■APPENDIX B Model Definition Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305 Fields . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305 Field Name Restrictions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305 AutoField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306 BooleanField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306 CharField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306 CommaSeparatedIntegerField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306 DateField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306 DateTimeField. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 EmailField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 FileField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 FilePathField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308 FloatField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308 ImageField. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309 IntegerField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309 IPAddressField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309 NullBooleanField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309 PhoneNumberField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309 PositiveIntegerField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309 xvii 7257ch00FM.qxd xviii 11/9/07 12:37 PM Page xviii ■CONTENTS PositiveSmallIntegerField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309 SlugField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309 SmallIntegerField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310 TextField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310 TimeField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310 URLField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310 USStateField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310 XMLField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310 Universal Field Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310 null . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310 blank . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311 choices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311 db_column . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312 db_index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312 default . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312 editable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312 help_text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312 primary_key . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312 radio_admin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312 unique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313 unique_for_date . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313 unique_for_month . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313 unique_for_year. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313 verbose_name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313 Relationships . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314 Many-to-One Relationships . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314 Many-to-Many Relationships . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316 Model Metadata Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317 db_table . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317 db_tablespace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318 get_latest_by . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318 order_with_respect_to . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318 ordering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318 permissions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319 unique_together . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319 verbose_name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320 verbose_name_plural . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320 Managers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320 Manager Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320 Custom Managers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321 7257ch00FM.qxd 11/9/07 12:37 PM Page xix ■CONTENTS Model Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323 __str__ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324 get_absolute_url . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324 Executing Custom SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325 Overriding Default Model Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . 326 Admin Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326 date_hierarchy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326 fields . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327 js . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328 list_display . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328 list_display_links . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 list_filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 list_per_page . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331 list_select_related . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331 ordering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331 save_as . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331 save_on_top . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331 search_fields . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332 ■APPENDIX C Database API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333 Creating Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334 What Happens When You Save? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334 Autoincrementing Primary Keys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334 Saving Changes to Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335 Retrieving Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336 Caching and QuerySets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337 Filtering Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337 Chaining Filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338 Limiting QuerySets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339 Query Methods That Return New QuerySets. . . . . . . . . . . . . . . . . . . 339 QuerySet Methods That Do Not Return QuerySets . . . . . . . . . . . . . . 343 Field Lookups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346 exact . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346 iexact . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347 contains . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347 icontains . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347 gt, gte, lt, and lte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348 in . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348 startswith . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348 xix 7257ch00FM.qxd xx 11/9/07 12:37 PM Page xx ■CONTENTS istartswith . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348 endswith and iendswith . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348 range . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348 year, month, and day . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349 isnull. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349 search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349 The pk Lookup Shortcut . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349 Complex Lookups with Q Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350 Related Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351 Lookups That Span Relationships . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351 Foreign Key Relationships . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352 “Reverse” Foreign Key Relationships . . . . . . . . . . . . . . . . . . . . . . . . . 352 Many-to-Many Relationships . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354 Queries over Related Objects. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355 Deleting Objects. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355 Extra Instance Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356 get_FOO_display() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356 get_next_by_FOO(**kwargs) and get_previous_by_FOO(**kwargs) . . . . . . . . . . . . . . . . . . . . . . . . . 356 get_FOO_filename() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357 get_FOO_url() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357 get_FOO_size() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357 save_FOO_file(filename, raw_contents) . . . . . . . . . . . . . . . . . . . . . . 357 get_FOO_height() and get_FOO_width() . . . . . . . . . . . . . . . . . . . . . . 357 Shortcuts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357 get_object_or_404() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357 get_list_or_404() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358 Falling Back to Raw SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358 ■APPENDIX D Generic View Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359 Common Arguments to Generic Views. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359 “Simple” Generic Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360 Rendering a Template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360 Redirecting to Another URL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360 List/Detail Generic Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361 Lists of Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361 Detail Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363 Date-Based Generic Views. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365 Archive Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365 Year Archives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367 7257ch00FM.qxd 11/9/07 12:37 PM Page xxi ■CONTENTS Month Archives. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368 Week Archives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 370 Day Archives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371 Archive for Today . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372 Date-Based Detail Pages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373 Create/Update/Delete Generic Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375 Create Object View . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375 Update Object View . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377 Delete Object View . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378 ■APPENDIX E Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379 What’s a Settings File? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379 Default Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 380 Seeing Which Settings You’ve Changed . . . . . . . . . . . . . . . . . . . . . . . 380 Using Settings in Python Code. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 380 Altering Settings at Runtime . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 380 Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381 Creating Your Own Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381 Designating the Settings: DJANGO_SETTINGS_MODULE. . . . . . . . . . . . . 381 The django-admin.py Utility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381 On the Server (mod_python) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382 Using Settings Without Setting DJANGO_SETTINGS_MODULE . . . . . . . . 382 Custom Default Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383 Either configure() or DJANGO_SETTINGS_MODULE Is Required . . . . 383 Available Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383 ABSOLUTE_URL_OVERRIDES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383 ADMIN_FOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384 ADMIN_MEDIA_PREFIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384 ADMINS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384 ALLOWED_INCLUDE_ROOTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384 APPEND_SLASH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384 CACHE_BACKEND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385 CACHE_MIDDLEWARE_KEY_PREFIX . . . . . . . . . . . . . . . . . . . . . . . . . 385 DATABASE_ENGINE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385 DATABASE_HOST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385 DATABASE_NAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385 DATABASE_OPTIONS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385 DATABASE_PASSWORD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385 DATABASE_PORT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386 xxi 7257ch00FM.qxd xxii 11/9/07 12:37 PM Page xxii ■CONTENTS DATABASE_USER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386 DATE_FORMAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386 DATETIME_FORMAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386 DEBUG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386 DEFAULT_CHARSET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386 DEFAULT_CONTENT_TYPE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387 DEFAULT_FROM_EMAIL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387 DISALLOWED_USER_AGENTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387 EMAIL_HOST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387 EMAIL_HOST_PASSWORD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387 EMAIL_HOST_USER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387 EMAIL_PORT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387 EMAIL_SUBJECT_PREFIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388 FIXTURE_DIRS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388 IGNORABLE_404_ENDS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388 IGNORABLE_404_STARTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388 INSTALLED_APPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388 INTERNAL_IPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388 JING_PATH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388 LANGUAGE_CODE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389 LANGUAGES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389 MANAGERS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389 MEDIA_ROOT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389 MEDIA_URL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390 MIDDLEWARE_CLASSES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390 MONTH_DAY_FORMAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390 PREPEND_WWW . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390 PROFANITIES_LIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390 ROOT_URLCONF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390 SECRET_KEY. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391 SEND_BROKEN_LINK_EMAILS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391 SERIALIZATION_MODULES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391 SERVER_EMAIL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391 SESSION_COOKIE_AGE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391 SESSION_COOKIE_DOMAIN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391 SESSION_COOKIE_NAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391 SESSION_COOKIE_SECURE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392 SESSION_EXPIRE_AT_BROWSER_CLOSE . . . . . . . . . . . . . . . . . . . . . 392 SESSION_SAVE_EVERY_REQUEST . . . . . . . . . . . . . . . . . . . . . . . . . . . 392 SITE_ID . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392 TEMPLATE_CONTEXT_PROCESSORS . . . . . . . . . . . . . . . . . . . . . . . . . 392 7257ch00FM.qxd 11/9/07 12:37 PM Page xxiii ■CONTENTS TEMPLATE_DEBUG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392 TEMPLATE_DIRS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393 TEMPLATE_LOADERS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393 TEMPLATE_STRING_IF_INVALID . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393 TEST_RUNNER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393 TEST_DATABASE_NAME. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393 TIME_FORMAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393 TIME_ZONE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393 URL_VALIDATOR_USER_AGENT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394 USE_ETAGS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394 USE_I18N . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394 YEAR_MONTH_FORMAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394 ■APPENDIX F Built-in Template Tags and Filters . . . . . . . . . . . . . . . . . . . . . . . . 395 Built-in Tag Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395 block . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395 comment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395 cycle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395 debug . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396 extends . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396 filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396 firstof . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396 for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397 if . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397 ifchanged . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399 ifequal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399 ifnotequal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399 include . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400 load . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400 now . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400 regroup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402 spaceless . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403 ssi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403 templatetag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403 url . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404 widthratio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404 Built-in Filter Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405 add . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405 addslashes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405 capfirst . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405 xxiii 7257ch00FM.qxd xxiv 11/9/07 12:37 PM Page xxiv ■CONTENTS center . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405 cut . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405 date . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406 default . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406 default_if_none . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406 dictsort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406 dictsortreversed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406 divisibleby . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406 escape . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407 filesizeformat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407 first . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407 fix_ampersands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407 floatformat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407 get_digit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408 join . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408 length . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408 length_is . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408 linebreaks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409 linebreaksbr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409 linenumbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409 ljust. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409 lower . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409 make_list . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409 phone2numeric . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410 pluralize . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410 pprint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410 random . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410 removetags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410 rjust . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411 slice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411 slugify . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411 stringformat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411 striptags. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411 time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411 timesince . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412 timeuntil . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412 title . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412 truncatewords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412 truncatewords_html . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412 unordered_list . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413 upper . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413 7257ch00FM.qxd 11/9/07 12:37 PM Page xxv ■CONTENTS urlencode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413 urlize . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413 urlizetrunc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414 wordcount . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414 wordwrap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414 yesno . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414 ■APPENDIX G The django-admin Utility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415 Usage. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415 Available Actions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416 adminindex [appname appname ...]. . . . . . . . . . . . . . . . . . . . . . . . . . 416 createcachetable [tablename] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416 dbshell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416 diffsettings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416 dumpdata [appname appname ...] . . . . . . . . . . . . . . . . . . . . . . . . . . . 417 flush . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417 inspectdb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417 loaddata [fixture fixture ...] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417 reset [appname appname ...] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419 runfcgi [option] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419 runserver [optional port number, or ipaddr:port] . . . . . . . . . . . . . . . 419 shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420 sql [appname appname ...] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420 sqlall [appname appname ...] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420 sqlclear [appname appname ...] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420 sqlcustom [appname appname ...] . . . . . . . . . . . . . . . . . . . . . . . . . . . 420 sqlindexes [appname appname ...] . . . . . . . . . . . . . . . . . . . . . . . . . . 420 sqlreset [appname appname ...] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420 sqlsequencereset [appname appname ...] . . . . . . . . . . . . . . . . . . . . 421 startapp [appname] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421 startproject [projectname] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421 syncdb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421 test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421 validate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421 Available Option . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421 --settings. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421 --pythonpath . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422 --format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422 --help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422 --indent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422 xxv 7257ch00FM.qxd xxvi 11/9/07 12:37 PM Page xxvi ■CONTENTS --noinput . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422 --noreload . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422 --version . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423 --verbosity. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423 --adminmedia. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423 ■APPENDIX H Request and Response Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . 425 HttpRequest . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425 QueryDict Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427 A Complete Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 428 HttpResponse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429 Construction HttpResponses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429 Setting Headers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429 HttpResponse Subclasses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 430 Returning Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 430 Customizing the 404 (Page Not Found) View . . . . . . . . . . . . . . . . . . 431 Customizing the 500 (Server Error) View . . . . . . . . . . . . . . . . . . . . . . 432 ■INDEX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433 7257ch00FM.qxd 11/9/07 12:37 PM Page xxvii About the Authors ■ADRIAN HOLOVATY, a Web developer/journalist, is one of the creators and core developers of Django. He is the founder of EveryBlock, a local news Web startup. When not working on Django improvements, Adrian hacks on side projects for the public good, such as chicagocrime.org, one of the original Google Maps mashups. He lives in Chicago and maintains a weblog at http://holovaty.com. ■JACOB KAPLAN-MOSS is one of the lead developers of Django. At his day job, he’s the lead developer for Lawrence Journal-World, a locally-owned newspaper in Lawrence, Kansas, where Django was developed. At Journal-World, Jacob hacks on a number of sites, including lawrence.com, LJworld.com, and KUsports.com, and is continually embarrassed by the multitude of media awards those sites win. In his spare time—what little of it there is—he fancies himself a chef. xxvii 7257ch00FM.qxd 11/9/07 12:37 PM Page xxviii About the Technical Reviewer ■JEREMY DUNCK is 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. xxviii 7257ch00FM.qxd 11/9/07 12:37 PM Page xxix Acknowledgments T he most gratifying aspect of working on Django is the community. We’ve been especially lucky that Django has attracted such a smart, motivated, and friendly bunch. A segment of that community followed us over to the online “beta” release of this book. Their reviews and comments were indispensable; this book wouldn’t have been possible without all that wonderful peer review. Almost a thousand people left comments that helped us improve the clarity, quality, and flow of the final book; we’d like to thank each and every one of them. We’re especially grateful to those who took the time to review the book in depth and left dozens (sometimes hundreds) of comments apiece: Marty Alchin, Max Battcher, Oliver Beattie, Rod Begbie, Paul Bissex, Matt Boersma, Robbin Bonthond, Peter Bowyer, Nesta Campbell, Jon Colverson, Jeff Croft, Chris Dary, Alex Dong, Matt Drew, Robert Dzikowski, Nick Efford, Ludvig Ericson, Eric Floehr, Brad Fults, David Grant, Simon Greenhill, Robert Haveman, Kent Johnson, Andrew Kember, Marek Kubica, Eduard Kucera, Anand Kumria, Scott Lamb, Fredrik Lundh, Vadim Macagon, Markus Majer, Orestis Markou, R. Mason, Yasushi Masuda, Kevin Menard, Carlo Miron, James Mulholland, R.D. Nielsen, Michael O’Keefe, Lawrence Oluyede, Andreas Pfrengle, Frankie Robertson, Mike Robinson, Armin Ronacher, Daniel Roseman, Johan Samyn, Ross Shannon, Carolina F. Silva, Paul Smith, Björn Stabell, Bob Stepno, Graeme Stevenson, Justin Stockton, Kevin Teague, Daniel Tietze, Brooks Travis, Peter Tripp, Matthias Urlichs, Peter van Kampen, Alexandre Vassalotti, Jay Wang, Brian Will, and Joshua Works. Many thanks to our technical editor, Jeremy Dunck. Without Jeremy this book would be littered with errors, inaccuracies, and broken code. We feel very lucky that someone as talented as Jeremy found the time to help us out. We’re grateful for all the hard work the folks at Apress put into this book. They’ve been amazingly supportive and patient; this book wouldn’t have come together without a lot of work on their part. We’re especially happy that Apress supported and even encouraged the free release of this book online; it’s wonderful seeing a publisher so embracing the spirit of open source. Finally, of course, thanks to our friends, families, and coworkers who’ve graciously tolerated our mental absence while we finished this work. xxix 7257ch00FM.qxd 11/9/07 12:37 PM Page xxxi Introduction I n the early days, Web developers wrote every page by hand. Updating a Web site meant editing HTML; a “redesign” involved redoing every single page, one at a time. As Web sites grew and became more ambitious, it quickly became obvious that that situation was tedious, time-consuming, and ultimately untenable. A group of enterprising hackers at NCSA (the National Center for Supercomputing Applications, where Mosaic, the first graphical Web browser, was developed) solved this problem by letting the Web server spawn external programs that could dynamically generate HTML. They called this protocol the Common Gateway Interface, or CGI, and it changed the Web forever. It’s hard now to imagine what a revelation CGI must have been: instead of treating HTML pages as simple files on disk, CGI allows you to think of your pages as resources generated dynamically on demand. The development of CGI ushered in the first generation of dynamic Web sites. However, CGI has its problems: CGI scripts need to contain a lot of repetitive “boilerplate” code, they make code reuse difficult, and they can be difficult for first-time developers to write and understand. PHP fixed many of these problems, and it took the world by storm—it’s now by far the most popular tool used to create dynamic Web sites, and dozens of similar languages and environments (ASP, JSP, etc.) followed PHP’s design closely. PHP’s major innovation is its ease of use: PHP code is simply embedded into plain HTML; the learning curve for someone who already knows HTML is extremely shallow. But PHP has its own problems; its very ease of use encourages sloppy, repetitive, illconceived code. Worse, PHP does little to protect programmers from security vulnerabilities, and thus many PHP developers found themselves learning about security only once it was too late. These and similar frustrations led directly to the development of the current crop of “thirdgeneration” Web development frameworks. These frameworks—Django and Ruby on Rails appear to be the most popular these days—recognize that the Web’s importance has escalated of late. With this new explosion of Web development comes yet another increase in ambition; Web developers are expected to do more and more every day. Django was invented to meet these new ambitions. Django lets you build deep, dynamic, interesting sites in an extremely short time. Django is designed to let you focus on the fun, interesting parts of your job while easing the pain of the repetitive bits. In doing so, it provides high-level abstractions of common Web development patterns, shortcuts for frequent programming tasks, and clear conventions on how to solve problems. At the same time, Django tries to stay out of your way, letting you work outside the scope of the framework as needed. We wrote this book because we firmly believe that Django makes Web development better. It’s designed to quickly get you moving on your own Django projects, and then ultimately teach you everything you need to know to successfully design, develop, and deploy a site that you’ll be proud of. xxxi 7257ch00FM.qxd xxxii 11/9/07 12:37 PM Page xxxii ■INTRODUCTION We’re extremely interested in your feedback. The online version of this book—available at http://djangobook.com/—will let you comment on any part of the book, and discuss it with other readers. We’ll do our best to read all the comments posted there, and to respond to as many as possible. If you prefer email, please drop us a line at feedback@djangobook.com. Either way, we’d love to hear from you! We’re glad you’re here, and we hope you find Django as exciting, fun, and useful as we do. 7257ch01.qxd 11/8/07 1:44 PM PART Page 1 1 ■■■ Getting Started 7257ch01.qxd 11/8/07 1:44 PM CHAPTER Page 3 1 ■■■ Introduction to Django T his book is about Django, a Web development framework that saves you time and makes Web development a joy. Using Django, you can build and maintain high-quality Web applications with minimal fuss. At its best, Web development is an exciting, creative act; at its worst, it can be a repetitive, frustrating nuisance. Django lets you focus on the fun stuff—the crux of your Web application— while easing the pain of the repetitive bits. In doing so, it provides high-level abstractions of common Web development patterns, shortcuts for frequent programming tasks, and clear conventions for how to solve problems. At the same time, Django tries to stay out of your way, letting you work outside the scope of the framework as needed. The goal of this book is to make you a Django expert. The focus is twofold. First, we explain, in depth, what Django does and how to build Web applications with it. Second, we discuss higher-level concepts where appropriate, answering the question “How can I apply these tools effectively in my own projects?” By reading this book, you’ll learn the skills needed to develop powerful Web sites quickly, with code that is clean and easy to maintain. In this chapter, we provide a high-level overview of Django. What Is a Web Framework? Django is a prominent member of a new generation of Web frameworks. So, what exactly does that term mean? To answer that question, let’s consider the design of a Web application written using the Common Gateway Interface (CGI) standard, a popular way to write Web applications circa 1998. In those days, when you wrote a CGI application, you did everything yourself—the equivalent of baking a cake from scratch. For example, here’s a simple CGI script, written in Python, that displays the ten most recently published books from a database: #!/usr/bin/python import MySQLdb 3 7257ch01.qxd 4 11/8/07 1:44 PM Page 4 CHAPTER 1 ■ INTRODUCTION TO DJANGO print print print print print print "Content-Type: text/html" "Books " "" "Books
" "
- "
connection = MySQLdb.connect(user='me', passwd='letmein', db='my_db')
cursor = connection.cursor()
cursor.execute("SELECT name FROM books ORDER BY pub_date DESC LIMIT 10")
for row in cursor.fetchall():
print "
- %s " % row[0] print "
Books
-
{% for book in book_list %}
- {{ book.name }} {% endfor %}
Dear {{ person_name }},
31 7257ch04.qxd 32 11/1/07 1:22 PM Page 32 CHAPTER 4 ■ THE DJANGO TEMPLATE SYSTEMThanks for placing an order from {{ company }}. It's scheduled to ship on {{ ship_date|date:"F j, Y" }}.
Here are the items you've ordered:
-
{% for item in item_list %}
- {{ item }} {% endfor %}
Your warranty information will be included in the packaging.
{% endif %}Sincerely,
{{ company }}
Dear {{ person_name }},
... ...Thanks for ordering {{ product }} from {{ company }}. It's scheduled ... to ship on {{ ship_date|date:"F j, Y" }}.
... ... {% if ordered_warranty %} ...Your warranty information will be included in the packaging.
... {% endif %} ... ...Sincerely,
{{ company }}
Dear John Smith,
\n\nThanks for ordering Super Lawn Mower from Outdoor Equipment. It's scheduled \nto ship on April 2, 2009.
\n\n\nYour warranty information will be included in the packaging.
\n\n\nSincerely,
Outdoor Equipment
Welcome to the weekend!
{% endif %} An {% else %} tag is optional: {% if today_is_weekend %}Welcome to the weekend!
{% else %}Get back to work.
{% endif %} PYTHON “TRUTHINESS” In Python, the empty list ([]), tuple (()), dictionary ({}), string (''), zero (0), and the special object None are False in a Boolean context. Everything else is True. The {% if %} tag accepts and, or, or not for testing multiple variables, or to negate a given variable. Here’s an example: {% if athlete_list and coach_list %} Both athletes and coaches are available. {% endif %} {% if not athlete_list %} There are no athletes. {% endif %} {% if athlete_list or coach_list %} There are some athletes or some coaches. {% endif %} {% if not athlete_list or coach_list %} There are no athletes or there are some coaches. (OK, so writing English translations of Boolean logic sounds stupid; it's not our fault.) {% endif %} {% if athlete_list and not coach_list %} There are some athletes and absolutely no coaches. {% endif %} 41 7257ch04.qxd 42 11/1/07 1:22 PM Page 42 CHAPTER 4 ■ THE DJANGO TEMPLATE SYSTEM {% if %} tags don’t allow and and or clauses within the same tag, because the order of logic would be ambiguous. For example, this is invalid: {% if athlete_list and coach_list or cheerleader_list %} The use of parentheses for controlling order of operations is not supported. If you find yourself needing parentheses, consider performing logic in the view code in order to simplify the templates. Even so, if you need to combine and and or to do advanced logic, just use nested {% if %} tags, for example: {% if athlete_list %} {% if coach_list or cheerleader_list %} We have athletes, and either coaches or cheerleaders! {% endif %} {% endif %} Multiple uses of the same logical operator are fine, but you can’t combine different operators. For example, this is valid: {% if athlete_list or coach_list or parent_list or teacher_list %} There is no {% elif %} tag. Use nested {% if %} tags to accomplish the same thing: {% if athlete_list %}Here are the athletes: {{ athlete_list }}.
{% else %}No athletes are available.
{% if coach_list %}Here are the coaches: {{ coach_list }}.
{% endif %} {% endif %} Make sure to close each {% if %} with an {% endif %}. Otherwise, Django will throw a TemplateSyntaxError. for The {% for %} tag allows you to loop over each item in a sequence. As in Python’s for statement, the syntax is for X in Y, where Y is the sequence to loop over and X is the name of the variable to use for a particular cycle of the loop. Each time through the loop, the template system will render everything between {% for %} and {% endfor %}. For example, you could use the following to display a list of athletes given a variable athlete_list:-
{% for athlete in athlete_list %}
- {{ athlete.name }} {% endfor %}
{{ country.name }}
-
{% for city in country.city_list %}
- {{ city }} {% endfor %}
{{ forloop.counter }}: {{ item }}
{% endfor %} • forloop.counter0 is like forloop.counter, except it’s zero-indexed. Its value will be set to 0 the first time through the loop. • forloop.revcounter is always set to an integer representing the number of remaining items in the loop. The first time through the loop, forloop.revcounter will be set to the total number of items in the sequence you’re traversing. The last time through the loop, forloop.revcounter will be set to 1. • forloop.revcounter0 is like forloop.revcounter, except it’s zero-indexed. The first time through the loop, forloop.revcounter0 will be set to the number of elements in the sequence minus 1. The last time through the loop, it will be set to 0. • forloop.first is a Boolean value set to True if this is the first time through the loop. This is convenient for special casing: {% for object in objects %} {% if forloop.first %}Country #{{ forloop.parentloop.counter }} | City #{{ forloop.counter }} | {{ city }} |
Welcome!
{% endifequal %} The arguments can be hard-coded strings, with either single or double quotes, so the following is valid: {% ifequal section 'sitenews' %}Site News
{% endifequal %} {% ifequal section "community" %}Community
{% endifequal %} Just like {% if %}, the {% ifequal %} tag supports an optional {% else %}: {% ifequal section 'sitenews' %}Site News
{% else %}No News Here
{% endifequal %} Only template variables, strings, integers, and decimal numbers are allowed as arguments to {% ifequal %}. These are valid examples: {% {% {% {% ifequal ifequal ifequal ifequal variable variable variable variable 1 %} 1.23 %} 'foo' %} "foo" %} Any other types of variables, such as Python dictionaries, lists, or Booleans, can’t be hardcoded in {% ifequal %}. These are invalid examples: {% ifequal variable True %} {% ifequal variable [1, 2, 3] %} {% ifequal variable {'key': 'value'} %} If you need to test whether something is true or false, use the {% if %} tags instead of {% ifequal %}. Comments Just as in HTML or in a programming language such as Python, the Django template language allows for comments. To designate a comment, use {# #}: {# This is a comment #} The comment will not be output when the template is rendered. 45 7257ch04.qxd 46 11/1/07 1:22 PM Page 46 CHAPTER 4 ■ THE DJANGO TEMPLATE SYSTEM A comment cannot span multiple lines. This limitation improves template parsing performance. In the following template, the rendered output will look exactly the same as the template (i.e., the comment tag will not be parsed as a comment): This is a {# this is not a comment #} test. Filters As explained earlier in this chapter, template filters are simple ways of altering the value of variables before they’re displayed. Filters look like this: {{ name|lower }} This displays the value of the {{ name }} variable after being filtered through the lower filter, which converts text to lowercase. Use a pipe (|) to apply a filter. Filters can be chained—that is, the output of one filter is applied to the next. Here’s a common idiom for escaping text contents and then converting line breaks totags: {{ my_text|escape|linebreaks }} Some filters take arguments. A filter argument looks like this: {{ bio|truncatewords:"30" }} This displays the first 30 words of the bio variable. Filter arguments are always in double quotes. The following are a few of the most important filters; Appendix F covers the rest. • addslashes: Adds a backslash before any backslash, single quote, or double quote. This is useful if the produced text is included in a JavaScript string. • date: Formats a date or datetime object according to a format string given in the parameter, for example: {{ pub_date|date:"F j, Y" }} Format strings are defined in Appendix F. • escape: Escapes ampersands, quotes, and angle brackets in the given string. This is useful for sanitizing user-submitted data and for ensuring data is valid XML or XHTML. Specifically, escape makes these conversions: • Converts & to & • Converts < to < • Converts > to > • Converts " (double quote) to " • Converts ' (single quote) to ' 7257ch04.qxd 11/1/07 1:22 PM Page 47 CHAPTER 4 ■ THE DJANGO TEMPLATE SYSTEM • length: Returns the length of the value. You can use this on a list or a string, or any Python object that knows how to determine its length (i.e., any object that has a __len__() method). Philosophies and Limitations Now that you’ve gotten a feel for the Django template language, we should point out some of its intentional limitations, along with some philosophies behind why it works the way it does. More than any other component of Web applications, programmer opinions on template systems vary wildly. The fact that Python alone has dozens, if not hundreds, of open source template-language implementations supports this point. Each was likely created because its developer deemed all existing template languages inadequate. (In fact, it is said to be a rite of passage for a Python developer to write his or her own template language! If you haven’t done this yet, consider it. It’s a fun exercise.) With that in mind, you might be interested to know that Django doesn’t require that you use its template language. Because Django is intended to be a full-stack Web framework that provides all the pieces necessary for Web developers to be productive, many times it’s more convenient to use Django’s template system than other Python template libraries, but it’s not a strict requirement in any sense. As you’ll see in the upcoming section “Using Templates in Views,” it’s very easy to use another template language with Django. Still, it’s clear we have a strong preference for the way Django’s template language works. The template system has roots in how Web development is done at World Online and the combined experience of Django’s creators. Here are a few of those philosophies: • Business logic should be separated from presentation logic. We see a template system as a tool that controls presentation and presentation-related logic—and that’s it. The template system shouldn’t support functionality that goes beyond this basic goal. For that reason, it’s impossible to call Python code directly within Django templates. All “programming” is fundamentally limited to the scope of what template tags can do. It is possible to write custom template tags that do arbitrary things, but the out-of-the-box Django template tags intentionally do not allow for arbitrary Python code execution. • Syntax should be decoupled from HTML/XML. Although Django’s template system is used primarily to produce HTML, it’s intended to be just as usable for non-HTML formats, such as plain text. Some other template languages are XML based, placing all template logic within XML tags or attributes, but Django deliberately avoids this limitation. Requiring valid XML to write templates introduces a world of human mistakes and hard-to-understand error messages, and using an XML engine to parse templates incurs an unacceptable level of overhead in template processing. • Designers are assumed to be comfortable with HTML code. The template system isn’t designed so that templates necessarily are displayed nicely in WYSIWYG editors such as Dreamweaver. That is too severe a limitation and wouldn’t allow the syntax to be as nice as it is. Django expects template authors to be comfortable editing HTML directly. • Designers are assumed not to be Python programmers. The template system authors recognize that Web page templates are most often written by designers, not programmers, and therefore should not assume Python knowledge. 47 7257ch04.qxd 48 11/1/07 1:22 PM Page 48 CHAPTER 4 ■ THE DJANGO TEMPLATE SYSTEM However, the system also intends to accommodate small teams in which the templates are created by Python programmers. It offers a way to extend the system’s syntax by writing raw Python code (more on this in Chapter 10). • The goal is not to invent a programming language. The goal is to offer just enough programming-esque functionality, such as branching and looping, that is essential for making presentation-related decisions. As a result of these design philosophies, the Django template language has the following limitations: • A template cannot set a variable or change the value of a variable. It’s possible to write custom template tags that accomplish these goals (see Chapter 10), but the stock Django template tags do not allow it. • A template cannot call raw Python code. There’s no way to “drop into Python mode” or use raw Python constructs. Again, it’s possible to write custom template tags to do this, but the stock Django template tags don’t allow it. Using Templates in Views You’ve learned the basics of using the template system; now let’s use this knowledge to create a view. Recall the current_datetime view in mysite.views, which we started in the previous chapter. Here’s what it looks like: from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() html = "
It is now %s." % now return HttpResponse(html) Let’s change this view to use Django’s template system. At first, you might think to do something like this: from django.template import Template, Context from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() t = Template("It is now {{ current_date }}.") html = t.render(Context({'current_date': now})) return HttpResponse(html) Sure, that uses the template system, but it doesn’t solve the problems we pointed out in the introduction of this chapter. Namely, the template is still embedded in the Python code. Let’s fix that by putting the template in a separate file, which this view will load. 7257ch04.qxd 11/1/07 1:22 PM Page 49 CHAPTER 4 ■ THE DJANGO TEMPLATE SYSTEM You might first consider saving your template somewhere on your filesystem and using Python’s built-in file-opening functionality to read the contents of the template. Here’s what that might look like, assuming the template was saved as the file /home/djangouser/templates/ mytemplate.html: from django.template import Template, Context from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() # Simple way of using templates from the filesystem. # This doesn't account for missing files! fp = open('/home/djangouser/templates/mytemplate.html') t = Template(fp.read()) fp.close() html = t.render(Context({'current_date': now})) return HttpResponse(html) This approach, however, is inelegant for these reasons: • It doesn’t handle the case of a missing file. If the file mytemplate.html doesn’t exist or isn’t readable, the open() call will raise an IOError exception. • It hard-codes your template location. If you were to use this technique for every view function, you’d be duplicating the template locations. Not to mention it involves a lot of typing! • It includes a lot of boring boilerplate code. You’ve got better things to do than write calls to open(), fp.read(), and fp.close() each time you load a template. To solve these issues, we’ll use template loading and template directories, both of which are described in the sections that follow. Template Loading Django provides a convenient and powerful API for loading templates from disk, with the goal of removing redundancy both in your template-loading calls and in your templates themselves. In order to use this template-loading API, first you’ll need to tell the framework where you store your templates. The place to do this is in your settings file. A Django settings file is the place to put configuration for your Django instance (aka your Django project). It’s a simple Python module with module-level variables, one for each setting. When you ran django-admin.py startproject mysite in Chapter 2, the script created a default settings file for you, aptly named settings.py. Have a look at the file’s contents. It contains variables that look like this (though not necessarily in this order): DEBUG = True TIME_ZONE = 'America/Chicago' USE_I18N = True ROOT_URLCONF = 'mysite.urls' 49 7257ch04.qxd 50 11/1/07 1:22 PM Page 50 CHAPTER 4 ■ THE DJANGO TEMPLATE SYSTEM This is pretty self-explanatory; the settings and their respective values are simple Python variables. And because the settings file is just a plain Python module, you can do dynamic things such as checking the value of one variable before setting another. (This also means that you should avoid Python syntax errors in your settings file.) We’ll cover settings files in depth in Appendix E, but for now, have a look at the TEMPLATE_DIRS setting. This setting tells Django’s template-loading mechanism where to look for templates. By default, it’s an empty tuple. Pick a directory where you’d like to store your templates and add it to TEMPLATE_DIRS, like so: TEMPLATE_DIRS = ( '/home/django/mysite/templates', ) There are a few things to note: • You can specify any directory you want, as long as the directory and templates within that directory are readable by the user account under which your Web server runs. If you can’t think of an appropriate place to put your templates, we recommend creating a templates directory within your Django project (i.e., within the mysite directory you created in Chapter 2, if you’ve been following along with this book’s examples). • Don’t forget the comma at the end of the template directory string! Python requires commas within single-element tuples to disambiguate the tuple from a parenthetical expression. This is a common newbie gotcha. If you want to avoid this error, you can make TEMPLATE_DIRS a list instead of a tuple, because single-element lists don’t require a trailing comma: TEMPLATE_DIRS = [ '/home/django/mysite/templates' ] A tuple is slightly more semantically correct than a list (tuples cannot be changed after being created, and nothing should be changing settings once they’ve been read), so we recommend using a tuple for your TEMPLATE_DIRS setting. • If you’re on Windows, include your drive letter and use Unix-style forward slashes rather than backslashes, as follows: • It’s simplest to use absolute paths (i.e., directory paths that start at the root of the filesystem). If you want to be a bit more flexible and decoupled, though, you can take advantage of the fact that Django settings files are just Python code by constructing the contents of TEMPLATE_DIRS dynamically, for example: import os.path TEMPLATE_DIRS = ( os.path.join(os.path.dirname(__file__), 'templates').replace('\\', '/'), ) This example uses the “magic” Python variable __file__, which is automatically set to the file name of the Python module in which the code lives. 7257ch04.qxd 11/1/07 1:22 PM Page 51 CHAPTER 4 ■ THE DJANGO TEMPLATE SYSTEM TEMPLATE_DIRS = ( 'C:/www/django/templates', ) With TEMPLATE_DIRS set, the next step is to change the view code to use Django’s templateloading functionality rather than hard-coding the template paths. Returning to our current_ datetime view, let’s change it like so: from django.template.loader import get_template from django.template import Context from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() t = get_template('current_datetime.html') html = t.render(Context({'current_date': now})) return HttpResponse(html) In this example, we’re using the function django.template.loader.get_template() rather than loading the template from the filesystem manually. The get_template() function takes a template name as its argument, figures out where the template lives on the filesystem, opens that file, and returns a compiled Template object. If get_template() cannot find the template with the given name, it raises a TemplateDoesNotExist exception. To see what that looks like, fire up the Django development server again, as in Chapter 3, by running python manage.py runserver within your Django project’s directory. Then, point your browser at the page that activates the current_datetime view (e.g., http://127.0.0.1:8000/time/). Assuming your DEBUG setting is set to True and you haven’t yet created a current_datetime.html template, you should see a Django error page highlighting the TemplateDoesNotExist error, as shown in Figure 4-1. Figure 4-1. The error page shown when a template cannot be found 51 7257ch04.qxd 52 11/1/07 1:22 PM Page 52 CHAPTER 4 ■ THE DJANGO TEMPLATE SYSTEM This error page is similar to the one we explained in Chapter 3, with one additional piece of debugging information: a “Template-loader postmortem” section. This section tells you which templates Django tried to load, along with the reason each attempt failed (e.g., “File does not exist”). This information is invaluable when you’re trying to debug template-loading errors. As you can probably tell from the error messages found in the Figure 4-1, Django attempted to find the template by combining the directory in the TEMPLATE_DIRS setting with the template name passed to get_template(). So if your TEMPLATE_DIRS contains '/home/django/templates', Django looks for the file '/home/django/templates/current_datetime.html'. If TEMPLATE_DIRS contains more than one directory, each is checked until the template is found or they’ve all been checked. Moving along, create the current_datetime.html file within your template directory using the following template code: It is now {{ current_date }}. Refresh the page in your Web browser, and you should see the fully rendered page. render_to_response() Because it’s such a common idiom to load a template, fill a Context, and return an HttpResponse object with the result of the rendered template, Django provides a shortcut that lets you do those things in one line of code. This shortcut is a function called render_to_response(), which lives in the module django.shortcuts. Most of the time, you’ll be using render_to_response() rather than loading templates and creating Context and HttpResponse objects manually. Here’s the ongoing current_datetime example rewritten to use render_to_response(): from django.shortcuts import render_to_response import datetime def current_datetime(request): now = datetime.datetime.now() return render_to_response('current_datetime.html', {'current_date': now}) What a difference! Let’s step through the code changes: • We no longer have to import get_template, Template, Context, or HttpResponse. Instead, we import django.shortcuts.render_to_response. The import datetime remains. • Within the current_datetime function, we still calculate now, but the template loading, context creation, template rendering, and HttpResponse creation is all taken care of by the render_to_response() call. Because render_to_response() returns an HttpResponse object, we can simply return that value in the view. The first argument to render_to_response() should be the name of the template to use. The second argument, if given, should be a dictionary to use in creating a Context for that template. If you don’t provide a second argument, render_to_response() will use an empty dictionary. 7257ch04.qxd 11/1/07 1:22 PM Page 53 CHAPTER 4 ■ THE DJANGO TEMPLATE SYSTEM The locals() Trick Consider our latest incarnation of current_datetime: def current_datetime(request): now = datetime.datetime.now() return render_to_response('current_datetime.html', {'current_date': now}) Many times, as in this example, you’ll find yourself calculating some values, storing them in variables (e.g., now in the preceding code), and sending those variables to the template. Particularly lazy programmers should note that it’s slightly redundant to have to give names for temporary variables and give names for the template variables. Not only is it redundant, but also it’s extra typing. So if you’re one of those lazy programmers and you like keeping code particularly concise, you can take advantage of a built-in Python function called locals(). It returns a dictionary mapping all local variable names to their values. Thus, the preceding view could be rewritten like so: def current_datetime(request): current_date = datetime.datetime.now() return render_to_response('current_datetime.html', locals()) Here, instead of manually specifying the context dictionary as before, we pass the value of locals(), which will include all variables defined at that point in the function’s execution. As a consequence, we’ve renamed the now variable to current_date, because that’s the variable name that the template expects. In this example, locals() doesn’t offer a huge improvement, but this technique can save you some typing if you have several template variables to define— or if you’re lazy. One thing to watch out for when using locals() is that it includes every local variable, which may comprise more variables than you actually want your template to have access to. In the previous example, locals() will also include request. Whether this matters to you depends on your application. A final thing to consider is that locals() incurs a small bit of overhead, because when you call it, Python has to create the dictionary dynamically. If you specify the context dictionary manually, you avoid this overhead. Subdirectories in get_template() It can get unwieldy to store all of your templates in a single directory. You might like to store templates in subdirectories of your template directory, and that’s fine. In fact, we recommend doing so; some more advanced Django features (such as the generic views system, which we cover in Chapter 9) expect this template layout as a default convention. Storing templates in subdirectories of your template directory is easy. In your calls to get_template(), just include the subdirectory name and a slash before the template name, like so: t = get_template('dateapp/current_datetime.html') 53 7257ch04.qxd 54 11/1/07 1:22 PM Page 54 CHAPTER 4 ■ THE DJANGO TEMPLATE SYSTEM Because render_to_response() is a small wrapper around get_template(), you can do the same thing with the first argument to render_to_response(). There’s no limit to the depth of your subdirectory tree. Feel free to use as many as you like. ■Note Windows users, be sure to use forward slashes rather than backslashes. get_template() assumes a Unix-style file name designation. The include Template Tag Now that we’ve covered the template-loading mechanism, we can introduce a built-in template tag that takes advantage of it: {% include %}. This tag allows you to include the contents of another template. The argument to the tag should be the name of the template to include, and the template name can be either a variable or a hard-coded (quoted) string, in either single or double quotes. Anytime you have the same code in multiple templates, consider using an {% include %} to remove the duplication. These two examples include the contents of the template nav.html. The examples are equivalent and illustrate that either single or double quotes are allowed: {% include 'nav.html' %} {% include "nav.html" %} This example includes the contents of the template includes/nav.html: {% include 'includes/nav.html' %} This example includes the contents of the template whose name is contained in the variable template_name: {% include template_name %} As in get_template(), the file name of the template is determined by adding the template directory from TEMPLATE_DIRS to the requested template name. Included templates are evaluated with the context of the template that’s including them. If a template with the given name isn’t found, Django will do one of two things: • If DEBUG is set to True, you’ll see the TemplateDoesNotExist exception on a Django error page. • If DEBUG is set to False, the tag will fail silently, displaying nothing in the place of the tag. Template Inheritance Our template examples so far have been tiny HTML snippets, but in the real world, you’ll be using Django’s template system to create entire HTML pages. This leads to a common Web development problem: across a Web site, how do you reduce the duplication and redundancy of common page areas, such as sitewide navigation? 7257ch04.qxd 11/1/07 1:22 PM Page 55 CHAPTER 4 ■ THE DJANGO TEMPLATE SYSTEM A classic way of solving this problem is to use server-side includes, directives you can embed within your HTML pages to “include” one Web page inside another. Indeed, Django supports that approach, with the {% include %} template tag just described. But the preferred way of solving this problem with Django is to use a more elegant strategy called template inheritance. In essence, template inheritance lets you build a base “skeleton” template that contains all the common parts of your site and defines “blocks” that child templates can override. Let’s see an example of this by creating a more complete template for our current_datetime view, by editing the current_datetime.html file:My helpful timestamp site
It is now {{ current_date }}.
Thanks for visiting my site.
That looks just fine, but what happens when we want to create a template for another view—say, the hours_ahead view from Chapter 3? If we want to again make a nice, valid, full HTML template, we’d create something like this:My helpful timestamp site
In {{ hour_offset }} hour(s), it will be {{ next_time }}.
Thanks for visiting my site.
Clearly, we’ve just duplicated a lot of HTML. Imagine if we had a more typical site, including a navigation bar, a few style sheets, perhaps some JavaScript—we’d end up putting all sorts of redundant HTML into each template. The server-side include solution to this problem is to factor out the common bits in both templates and save them in separate template snippets, which are then included in each template. Perhaps you’d store the top bit of the template in a file called header.html: 55 7257ch04.qxd 56 11/1/07 1:22 PM Page 56 CHAPTER 4 ■ THE DJANGO TEMPLATE SYSTEM And perhaps you’d store the bottom bit in a file called footer.html:Thanks for visiting my site.
With an include-based strategy, headers and footers are easy. It’s the middle ground that’s messy. In this example, both pages feature a title—My helpful timestamp site
—but that title can’t fit into header.html because the in the header, we’d have to include the , which wouldn’t allow us to customize
it per page. See where this is going?
Django’s template inheritance system solves these problems. You can think of it as an
“inside-out” version of server-side includes. Instead of defining the snippets that are common,
you define the snippets that are different.
The first step is to define a base template—a skeleton of your page that child templates
will later fill in. Here’s a base template for our ongoing example:
{% block title %}{% endblock %}
My helpful timestamp site
{% block content %}{% endblock %}
{% block footer %}
Thanks for visiting my site.
{% endblock %} This template, which we’ll call base.html, defines a simple HTML skeleton document that we’ll use for all the pages on the site. It’s the job of child templates to override, or add to, or leave alone the contents of the blocks. (If you’re following along at home, save this file to your template directory.) We’re using a template tag here that you haven’t seen before: the {% block %} tag. All the {% block %} tags do is tell the template engine that a child template may override those portions of the template. 7257ch04.qxd 11/1/07 1:22 PM Page 57 CHAPTER 4 ■ THE DJANGO TEMPLATE SYSTEM Now that we have this base template, we can modify our existing current_datetime.html template to use it: {% extends "base.html" %} {% block title %}The current time{% endblock %} {% block content %}It is now {{ current_date }}.
{% endblock %} While we’re at it, let’s create a template for the hours_ahead view from Chapter 3. (If you’re following along with code, we’ll leave it up to you to change hours_ahead to use the template system.) Here’s what that would look like: {% extends "base.html" %} {% block title %}Future time{% endblock %} {% block content %}In {{ hour_offset }} hour(s), it will be {{ next_time }}.
{% endblock %} Isn’t this beautiful? Each template contains only the code that’s unique to that template. No redundancy needed. If you need to make a sitewide design change, just make the change to base.html, and all of the other templates will immediately reflect the change. Here’s how it works. When you load the template current_datetime.html, the template engine sees the {% extends %} tag, noting that this template is a child template. The engine immediately loads the parent template—in this case, base.html. At that point, the template engine notices the three {% block %} tags in base.html and replaces those blocks with the contents of the child template. So, the title we’ve defined in {% block title %} will be used, as will the {% block content %}. Note that since the child template doesn’t define the footer block, the template system uses the value from the parent template instead. Content within a {% block %} tag in a parent template is always used as a fallback. Inheritance doesn’t affect the way the context works, and you can use as many levels of inheritance as needed. One common way of using inheritance is the following three-level approach: 1. Create a base.html template that holds the main look and feel of your site. This is the stuff that rarely, if ever, changes. 2. Create a base_SECTION.html template for each “section” of your site (e.g., base_photos.html and base_forum.html). These templates extend base.html and include section-specific styles/design. 3. Create individual templates for each type of page, such as a forum page or a photo gallery. These templates extend the appropriate section template. 57 7257ch04.qxd 58 11/1/07 1:22 PM Page 58 CHAPTER 4 ■ THE DJANGO TEMPLATE SYSTEM This approach maximizes code reuse and makes it easy to add items to shared areas, such as sectionwide navigation. Here are some tips for working with template inheritance: • If you use {% extends %} in a template, it must be the first template tag in that template. Otherwise, template inheritance won’t work. • Generally, the more {% block %} tags in your base templates, the better. Remember, child templates don’t have to define all parent blocks, so you can fill in reasonable defaults in a number of blocks, and then define only the ones you need in the child templates. It’s better to have more hooks than fewer hooks. • If you find yourself duplicating code in a number of templates, it probably means you should move that code to a {% block %} in a parent template. • If you need to get the content of the block from the parent template, 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. • You may not define multiple {% block %} tags with the same name in the same template. This limitation exists because a block tag works in “both” directions. That is, a block tag doesn’t just provide a hole to fill, it also defines the content that fills the hole in the parent. If there were two similarly named {% block %} tags in a template, that template’s parent wouldn’t know which one of the blocks’ content to use. • The template name you pass to {% extends %} is loaded using the same method that get_template() uses. That is, the template name is appended to your TEMPLATE_DIRS setting. • In most cases, the argument to {% extends %} will be a string, but it can also be a variable, if you don’t know the name of the parent template until runtime. This lets you do some cool, dynamic stuff. What’s Next? Most modern Web sites are database driven, meaning the site content is stored in a relational database. This allows a clean separation of data and logic (in the same way views and templates allow the separation of logic and display). The next chapter covers the tools Django provides to interact with a database. 7257ch05.qxd 11/1/07 1:24 PM CHAPTER Page 59 5 ■■■ Interacting with a Database: Models I n Chapter 3, we covered the fundamentals of building dynamic Web sites with Django: setting up views and URLconfs. As we explained, a view is responsible for doing some arbitrary logic and then returning a response. In the example, our arbitrary logic was to calculate the current date and time. In modern Web applications, the arbitrary logic often involves interacting with a database. Behind the scenes, a database-driven Web site connects to a database server, retrieves some data out of it, and displays that data, nicely formatted, on a Web page. Or, similarly, the site could provide functionality that lets site visitors populate the database on their own. Many complex Web sites provide some combination of the two. Amazon.com, for instance, is a great example of a database-driven site. Each product page is essentially a query into Amazon’s product database formatted as HTML, and when you post a customer review, it gets inserted into the database of reviews. Django is well suited for making database-driven Web sites, as it comes with easy yet powerful ways of performing database queries using Python. This chapter explains that functionality: Django’s database layer. ■Note While it’s not strictly necessary to know basic database theory and SQL in order to use Django’s database layer, it’s highly recommended. An introduction to those concepts is beyond the scope of this book, but keep reading even if you’re a database newbie. You’ll probably be able to follow along and grasp concepts based on the context. The “Dumb” Way to Do Database Queries in Views Just as Chapter 3 detailed a “dumb” way to produce output within a view (by hard-coding the text directly within the view), there’s a “dumb” way to retrieve data from a database in a view. It’s simple: just use any existing Python library to execute an SQL query and do something with the results. In this example view, we use the MySQLdb library (available at http://www.djangoproject.com/ r/python-mysql/) to connect to a MySQL database, retrieve some records, and feed them to a template for display as a Web page: 59 7257ch05.qxd 60 11/1/07 1:24 PM Page 60 CHAPTER 5 ■ INTERACTING WITH A DATABASE: MODELS from django.shortcuts import render_to_response import MySQLdb def book_list(request): db = MySQLdb.connect(user='me', db='mydb', passwd='secret', host='localhost') cursor = db.cursor() cursor.execute('SELECT name FROM books ORDER BY name') names = [row[0] for row in cursor.fetchall()] db.close() return render_to_response('book_list.html', {'names': names}) This approach works, but some problems should jump out at you immediately: • We’re hard-coding the database connection parameters. Ideally, these parameters would be stored in the Django configuration. • We’re having to write a fair bit of boilerplate code: creating a connection, creating a cursor, executing a statement, and closing the connection. Ideally, all we’d have to do is specify which results we wanted. • It ties us to MySQL. If, down the road, we switch from MySQL to PostgreSQL, we’ll have to use a different database adapter (e.g., psycopg rather than MySQLdb), alter the connection parameters, and—depending on the nature of the SQL statement—possibly rewrite the SQL. Ideally, the database server we’re using would be abstracted, so that a database server change could be made in a single place. As you might expect, Django’s database layer aims to solve these problems. Here’s a sneak preview of how the previous view can be rewritten using Django’s database API: from django.shortcuts import render_to_response from mysite.books.models import Book def book_list(request): books = Book.objects.order_by('name') return render_to_response('book_list.html', {'books': books}) We’ll explain this code a little later in the chapter. For now, just get a feel for how it looks. The MTV Development Pattern Before we delve into any more code, let’s take a moment to consider the overall design of a database-driven Django Web application. As we mentioned in previous chapters, Django is designed to encourage loose coupling and strict separation between pieces of an application. If you follow this philosophy, it’s easy to make changes to a particular piece of the application without affecting the other pieces. In view functions, for instance, we discussed the importance of separating the business logic from the presentation logic by using a template system. With the database layer, we’re applying that same philosophy to data access logic. Those three pieces together—data access logic, business logic, and presentation logic— comprise a concept that’s sometimes called the Model-View-Controller (MVC) pattern of 7257ch05.qxd 11/1/07 1:24 PM Page 61 CHAPTER 5 ■ INTERACTING WITH A DATABASE: MODELS software architecture. In this pattern, “Model” refers to the data access layer, “View” refers to the part of the system that selects what to display and how to display it, and “Controller” refers to the part of the system that decides which view to use, depending on user input, accessing the model as needed. WHY THE ACRONYM? The goal of explicitly defining patterns such as MVC is mostly to streamline communication among developers. Instead of having to tell your coworkers, “Let’s make an abstraction of the data access, then let’s have a separate layer that handles data display, and let’s put a layer in the middle that regulates this,” you can take advantage of a shared vocabulary and say, “Let’s use the MVC pattern here.” Django follows this MVC pattern closely enough that it can be called an MVC framework. Here’s roughly how the M, V, and C break down in Django: • M, the data-access portion, is handled by Django’s database layer, which is described in this chapter. • V, the portion that selects which data to display and how to display it, is handled by views and templates. • C, the portion that delegates to a view depending on user input, is handled by the framework itself by following your URLconf and calling the appropriate Python function for the given URL. Because the “C” is handled by the framework itself and most of the excitement in Django happens in models, templates, and views, Django has been referred to as an MTV framework. In the MTV development pattern, • M stands for “Model,” the data access layer. This layer contains anything and everything about the data: how to access it, how to validate it, which behaviors it has, and the relationships between the data. • T stands for “Template,” the presentation layer. This layer contains presentation-related decisions: how something should be displayed on a Web page or other type of document. • V stands for “View,” the business logic layer. This layer contains the logic that accesses the model and defers to the appropriate template(s). You can think of it as the bridge between models and templates. If you’re familiar with other MVC Web-development frameworks, such as Ruby on Rails, you may consider Django views to be the “controllers” and Django templates to be the “views.” This is an unfortunate confusion brought about by differing interpretations of MVC. In Django’s interpretation of MVC, the “view” describes the data that gets presented to the user; it’s not necessarily just how the data looks, but which data is presented. In contrast, Ruby on Rails and similar frameworks suggest that the controller’s job includes deciding which data gets presented to the user, whereas the view is strictly how the data looks, not which data is presented. 61 7257ch05.qxd 62 11/1/07 1:24 PM Page 62 CHAPTER 5 ■ INTERACTING WITH A DATABASE: MODELS Neither interpretation is more “correct” than the other. The important thing is to understand the underlying concepts. Configuring the Database With all of that philosophy in mind, let’s start exploring Django’s database layer. First, we need to take care of some initial configuration: we need to tell Django which database server to use and how to connect to it. We’ll assume you’ve set up a database server, activated it, and created a database within it (e.g., using a CREATE DATABASE statement). SQLite is a special case; in that case, there’s no database to create, because SQLite uses standalone files on the filesystem to store its data. As with TEMPLATE_DIRS in the previous chapter, database configuration lives in the Django settings file, called settings.py by default. Edit that file and look for the database settings: DATABASE_ENGINE = '' DATABASE_NAME = '' DATABASE_USER = '' DATABASE_PASSWORD = '' DATABASE_HOST = '' DATABASE_PORT = '' Here’s a rundown of each setting. • DATABASE_ENGINE tells Django which database engine to use. If you’re using a database with Django, DATABASE_ENGINE must be set to one of the strings shown in Table 5-1. Table 5-1. Database Engine Settings Setting Database Required Adapter postgresql PostgreSQL psycopg version 1.x, http://www.djangoproject.com/r/ python-pgsql/1/. postgresql_ psycopg2 PostgreSQL psycopg version 2.x, http://www.djangoproject.com/ r/python-pgsql/. mysql MySQL MySQLdb, http://www.djangoproject.com/r/python-mysql/. sqlite3 SQLite No adapter needed if using Python 2.5+. Otherwise, pysqlite, http://www.djangoproject.com/r/python-sqlite/. oracle Oracle cx_Oracle, http://www.djangoproject.com/r/python-oracle/. Note that for whichever database back-end you use, you’ll need to download and install the appropriate database adapter. Each one is available for free on the Web; just follow the links in the “Required Adapter” column in Table 5-1. 7257ch05.qxd 11/1/07 1:24 PM Page 63 CHAPTER 5 ■ INTERACTING WITH A DATABASE: MODELS • DATABASE_NAME tells Django the name of your database. If you’re using SQLite, specify the full filesystem path to the database file on your filesystem (e.g., '/home/django/mydata.db'). • DATABASE_USER tells Django which username to use when connecting to your database. If you’re using SQLite, leave this blank. • DATABASE_PASSWORD tells Django which password to use when connecting to your database. If you’re using SQLite or have an empty password, leave this blank. • DATABASE_HOST tells Django which host to use when connecting to your database. If your database is on the same computer as your Django installation (i.e., localhost), leave this blank. If you’re using SQLite, leave this blank. MySQL is a special case here. If this value starts with a forward slash (/) and you’re using MySQL, MySQL will connect via a Unix socket to the specified socket, for example: DATABASE_HOST = '/var/run/mysql' If you’re using MySQL and this value doesn’t start with a forward slash, then this value is assumed to be the host. • DATABASE_PORT tells Django which port to use when connecting to your database. If you’re using SQLite, leave this blank. Otherwise, if you leave this blank, the underlying database adapter will use whichever port is default for your given database server. In most cases, the default port is fine, so you can leave this blank. Once you’ve entered those settings, test your configuration. First, from within the mysite project directory you created in Chapter 2, run the command python manage.py shell. You’ll notice this starts a Python interactive interpreter. Looks can be deceiving, though! There’s an important difference between running the command python manage.py shell within your Django project directory and the more generic python. The latter is the basic Python shell, but the former tells Django which settings file to use before it starts the shell. This is a key requirement for doing database queries: Django needs to know which settings file to use in order to get your database connection information. Behind the scenes, python manage.py shell simply assumes that your settings file is in the same directory as manage.py. There are other ways to tell Django which settings module to use; we’ll cover those options later. For now, use python manage.py shell whenever you need to drop into the Python interpreter to do Django-specific tinkering. Once you’ve entered the shell, type these commands to test your database configuration: >>> from django.db import connection >>> cursor = connection.cursor() If nothing happens, then your database is configured properly. Otherwise, check the error message for clues about what’s wrong. Table 5-2 shows some common errors. 63 7257ch05.qxd 64 11/1/07 1:24 PM Page 64 CHAPTER 5 ■ INTERACTING WITH A DATABASE: MODELS Table 5-2. Database Configuration Error Messages Error Message Solution You haven’t set the DATABASE_ENGINE setting yet. Set the DATABASE_ENGINE setting to something other than an empty string. Environment variable DJANGO_SETTINGS_MODULE is undefined. python. Error loading _____ module: No module named _____. You haven’t installed the appropriate database-specific adapter (e.g., psycopg or MySQLdb). _____ isn’t an available database backend. Set your DATABASE_ENGINE setting to one of the valid engine settings described previously. Perhaps you made a typo? database _____ does not exist Change the DATABASE_NAME setting to point to a database that exists, or execute the appropriate CREATE DATABASE statement in order to create it. role _____ does not exist Change the DATABASE_USER setting to point to a user that exists, or create the user in your database. could not connect to server Make sure DATABASE_HOST and DATABASE_PORT are set correctly, and make sure the server is running. Run the command python manage.py shell rather than Your First App Now that you’ve verified the connection is working, it’s time to create a Django app—a bundle of Django code, including models and views, that lives together in a single Python package and represents a full Django application. It’s worth explaining the terminology here, because this tends to trip up beginners. We already created a project, in Chapter 2, so what’s the difference between a project and an app? The difference is that of configuration vs. code: • A project is an instance of a certain set of Django apps, plus the configuration for those apps. Technically, the only requirement of a project is that it supplies a settings file, which defines the database connection information, the list of installed apps, the TEMPLATE_DIRS, and so forth. • An app is a portable set of Django functionality, usually including models and views, that lives together in a single Python package. For example, Django comes with a number of apps, such as a commenting system and an automatic admin interface. A key thing to note about these apps is that they’re portable and reusable across multiple projects. There are very few hard-and-fast rules about how you fit your Django code into this scheme; it’s flexible. If you’re building a simple Web site, you may use only a single app. If you’re building a complex Web site with several unrelated pieces such as an e-commerce system and a message board, you’ll probably want to split those into separate apps so that you’ll be able to reuse them individually in the future. Indeed, you don’t necessarily need to create apps at all, as evidenced by the example view functions we’ve created so far in this book. In those cases, we simply created a file called 7257ch05.qxd 11/1/07 1:24 PM Page 65 CHAPTER 5 ■ INTERACTING WITH A DATABASE: MODELS views.py, filled it with view functions, and pointed our URLconf at those functions. No “apps” were needed. However, there’s one requirement regarding the app convention: if you’re using Django’s database layer (models), you must create a Django app. Models must live within apps. Thus, in order to start writing our models, we’ll need to create a new app. Within the mysite project directory you created in Chapter 2, type this command to create a new app named books: python manage.py startapp books This command does not produce any output, but it does create a books directory within the mysite directory. Let’s look at the contents of that directory: books/ __init__.py models.py views.py These files will contain the models and views for this app. Have a look at models.py and views.py in your favorite text editor. Both files are empty, except for an import in models.py. This is the blank slate for your Django app. Defining Models in Python As we discussed earlier in this chapter, the “M” in “MTV” stands for “Model.” A Django model is a description of the data in your database, represented as Python code. It’s your data layout— the equivalent of your SQL CREATE TABLE statements—except it’s in Python instead of SQL, and it includes more than just database column definitions. Django uses a model to execute SQL code behind the scenes and return convenient Python data structures representing the rows in your database tables. Django also uses models to represent higher-level concepts that SQL can’t necessarily handle. If you’re familiar with databases, your immediate thought might be, “Isn’t it redundant to define data models in Python and in SQL?” Django works the way it does for several reasons: • Introspection requires overhead and is imperfect. In order to provide convenient dataaccess APIs, Django needs to know the database layout somehow, and there are two ways of accomplishing this. The first way is to explicitly describe the data in Python, and the second way is to introspect the database at runtime to determine the data models. This second way seems cleaner, because the metadata about your tables lives in only one place, but it introduces a few problems. First, introspecting a database at runtime obviously requires overhead. If the framework had to introspect the database each time it processed a request, or even when the Web server was initialized, this would incur an unacceptable level of overhead. (While some believe that level of overhead is acceptable, Django’s developers aim to trim as much framework overhead as possible, and this approach has succeeded in making Django faster than its high-level framework competitors in benchmarks.) Second, some databases, notably older versions of MySQL, do not store sufficient metadata for accurate and complete introspection. 65 7257ch05.qxd 66 11/1/07 1:24 PM Page 66 CHAPTER 5 ■ INTERACTING WITH A DATABASE: MODELS • Writing Python is fun, and keeping everything in Python limits the number of times your brain has to do a “context switch.” It helps productivity if you keep yourself in a single programming environment/mentality for as long as possible. Having to write SQL, then Python, and then SQL again is disruptive. • Having data models stored as code rather than in your database makes it easier to keep your models under version control. This way, you can easily keep track of changes to your data layouts. • SQL allows for only a certain level of metadata about a data layout. Most database systems, for example, do not provide a specialized data type for representing email addresses or URLs. Django models do. The advantage of higher-level data types is higher productivity and more reusable code. • SQL is inconsistent across database platforms. If you’re distributing a Web application, for example, it’s much more pragmatic to distribute a Python module that describes your data layout than separate sets of CREATE TABLE statements for MySQL, PostgreSQL, and SQLite. A drawback of this approach, however, is that it’s possible for the Python code to get out of sync with what’s actually in the database. If you make changes to a Django model, you’ll need to make the same changes inside your database to keep your database consistent with the model. We’ll detail some strategies for handling this problem later in this chapter. Finally, we should note that Django includes a utility that can generate models by introspecting an existing database. This is useful for quickly getting up and running with legacy data. Your First Model As an ongoing example in this chapter and the next chapter, we’ll focus on a basic book/author/ publisher data layout. We use this as our example because the conceptual relationships between books, authors, and publishers are well known, and this is a common data layout used in introductory SQL textbooks. You’re also reading a book that was written by authors and produced by a publisher! We’ll suppose the following concepts, fields, and relationships: • An author has a salutation (e.g., Mr. or Mrs.), a first name, a last name, an email address, and a headshot photo. • A publisher has a name, a street address, a city, a state/province, a country, and a Web site. • A book has a title and a publication date. It also has one or more authors (a many-tomany relationship with authors) and a single publisher (a one-to-many relationship—aka foreign key—to publishers). The first step in using this database layout with Django is to express it as Python code. In the models.py file that was created by the startapp command, enter the following: 7257ch05.qxd 11/1/07 1:24 PM Page 67 CHAPTER 5 ■ INTERACTING WITH A DATABASE: MODELS from django.db import models class Publisher(models.Model): name = models.CharField(maxlength=30) address = models.CharField(maxlength=50) city = models.CharField(maxlength=60) state_province = models.CharField(maxlength=30) country = models.CharField(maxlength=50) website = models.URLField() class Author(models.Model): salutation = models.CharField(maxlength=10) first_name = models.CharField(maxlength=30) last_name = models.CharField(maxlength=40) email = models.EmailField() headshot = models.ImageField(upload_to='/tmp') class Book(models.Model): title = models.CharField(maxlength=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField() Let’s quickly examine this code to cover the basics. The first thing to notice is that each model is represented by a Python class that is a subclass of django.db.models.Model. The parent class, Model, contains all the machinery necessary to make these objects capable of interacting with a database—and that leaves our models responsible solely for defining their fields, in a nice and compact syntax. Believe it or not, this is all the code we need to write to have basic data access with Django. Each model generally corresponds to a single database table, and each attribute on a model generally corresponds to a column in that database table. The attribute name corresponds to the column’s name, and the type of field (e.g., CharField) corresponds to the database column type (e.g., varchar). For example, the Publisher model is equivalent to the following table (assuming PostgreSQL CREATE TABLE syntax): CREATE TABLE "books_publisher" ( "id" serial NOT NULL PRIMARY KEY, "name" varchar(30) NOT NULL, "address" varchar(50) NOT NULL, "city" varchar(60) NOT NULL, "state_province" varchar(30) NOT NULL, "country" varchar(50) NOT NULL, "website" varchar(200) NOT NULL ); Indeed, Django can generate that CREATE TABLE statement automatically, as we’ll show in a moment. 67 7257ch05.qxd 68 11/1/07 1:24 PM Page 68 CHAPTER 5 ■ INTERACTING WITH A DATABASE: MODELS The exception to the one-class-per-database-table rule is the case of many-to-many relationships. In our example models, Book has a ManyToManyField called authors. This designates that a book has one or many authors, but the Book database table doesn’t get an authors column. Rather, Django creates an additional table—a many-to-many “join table”—that handles the mapping of books to authors. ■Note For a full list of field types and model syntax options, see Appendix B. Finally, note we haven’t explicitly defined a primary key in any of these models. Unless you instruct it otherwise, Django automatically gives every model an integer primary key field called id. Each Django model is required to have a single-column primary key. Installing the Model We’ve written the code; now let’s create the tables in our database. In order to do that, the first step is to activate these models in our Django project. We do that by adding the books app to the list of installed apps in the settings file. Edit the settings.py file again, and look for the INSTALLED_APPS setting. INSTALLED_APPS tells Django which apps are activated for a given project. By default, it looks something like this: INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', ) Temporarily comment out all four of those strings by putting a hash character (#) in front of them. (They’re included by default as a common-case convenience, but we’ll activate and discuss them later.) While you’re at it, modify the default MIDDLEWARE_CLASSES and TEMPLATE_CONTEXT_PROCESSORS settings. These depend on some of the apps we just commented out. Then, add 'mysite.books' to the INSTALLED_APPS list, so the setting ends up looking like this: MIDDLEWARE_CLASSES = [] TEMPLATE_CONTEXT_PROCESSORS = [] INSTALLED_APPS = ( #'django.contrib.auth', #'django.contrib.contenttypes', #'django.contrib.sessions', #'django.contrib.sites', 'mysite.books', ) 7257ch05.qxd 11/1/07 1:24 PM Page 69 CHAPTER 5 ■ INTERACTING WITH A DATABASE: MODELS ■Note As we’re dealing with a single-element tuple here, don’t forget the trailing comma. By the way, this book’s authors prefer to put a comma after every element of a tuple, regardless of whether the tuple has only a single element. This avoids the issue of forgetting commas, and there’s no penalty for using that extra comma. 'mysite.books' refers to the books app we’re working on. Each app in INSTALLED_APPS is represented by its full Python path—that is, the path of packages, separated by dots, leading to the app package. Now that the Django app has been activated in the settings file, we can create the database tables in our database. First, let’s validate the models by running this command: python manage.py validate The validate command checks whether your models’ syntax and logic are correct. If all is well, you’ll see the message 0 errors found. If you don’t, make sure you typed in the model code correctly. The error output should give you helpful information about what was wrong with the code. Anytime you think you have problems with your models, run python manage.py validate. It tends to catch all the common model problems. If your models are valid, run the following command for Django to generate CREATE TABLE statements for your models in the books app (with colorful syntax highlighting available if you’re using Unix): python manage.py sqlall books In this command, books is the name of the app. It’s what you specified when you ran the command manage.py startapp. When you run the command, you should see something like this: BEGIN; CREATE TABLE "books_publisher" ( "id" serial NOT NULL PRIMARY KEY, "name" varchar(30) NOT NULL, "address" varchar(50) NOT NULL, "city" varchar(60) NOT NULL, "state_province" varchar(30) NOT NULL, "country" varchar(50) NOT NULL, "website" varchar(200) NOT NULL ); CREATE TABLE "books_book" ( "id" serial NOT NULL PRIMARY KEY, "title" varchar(100) NOT NULL, "publisher_id" integer NOT NULL REFERENCES "books_publisher" ("id"), "publication_date" date NOT NULL ); 69 7257ch05.qxd 70 11/1/07 1:24 PM Page 70 CHAPTER 5 ■ INTERACTING WITH A DATABASE: MODELS CREATE TABLE "books_author" ( "id" serial NOT NULL PRIMARY KEY, "salutation" varchar(10) NOT NULL, "first_name" varchar(30) NOT NULL, "last_name" varchar(40) NOT NULL, "email" varchar(75) NOT NULL, "headshot" varchar(100) NOT NULL ); CREATE TABLE "books_book_authors" ( "id" serial NOT NULL PRIMARY KEY, "book_id" integer NOT NULL REFERENCES "books_book" ("id"), "author_id" integer NOT NULL REFERENCES "books_author" ("id"), UNIQUE ("book_id", "author_id") ); CREATE INDEX books_book_publisher_id ON "books_book" ("publisher_id"); COMMIT; Note the following: • Table names are automatically generated by combining the name of the app (books) and the lowercased name of the model (publisher, book, and author). You can override this behavior, as detailed in Appendix B. • As we mentioned earlier, Django adds a primary key for each table automatically—the id fields. You can override this, too. • By convention, Django appends "_id" to the foreign key field name. As you might have guessed, you can override this behavior as well. • The foreign key relationship is made explicit by a REFERENCES statement. • These CREATE TABLE statements are tailored to the database you’re using, so databasespecific field types such as auto_increment (MySQL), serial (PostgreSQL), or integer primary key (SQLite) are handled for you automatically. The same goes for quoting of column names (e.g., using double quotes or single quotes). This example output is in PostgreSQL syntax. The sqlall command doesn’t actually create the tables or otherwise touch your database—it just prints output to the screen so you can see what SQL Django would execute if you asked it. If you wanted to, you could copy and paste this SQL into your database client, or use Unix pipes to pass it directly. However, Django provides an easier way of committing the SQL to the database. Run the syncdb command, like so: python manage.py syncdb You’ll see something like this: Creating table books_publisher Creating table books_book Creating table books_author Installing index for books.Book model 7257ch05.qxd 11/1/07 1:24 PM Page 71 CHAPTER 5 ■ INTERACTING WITH A DATABASE: MODELS The syncdb command is a simple “sync” of your models to your database. It looks at all of the models in each app in your INSTALLED_APPS setting, checks the database to see whether the appropriate tables exist yet, and creates the tables if they don’t yet exist. Note that syncdb does not sync changes in models or deletions of models; if you make a change to a model or delete a model, and you want to update the database, syncdb will not handle that. (More on this later.) If you run python manage.py syncdb again, nothing happens, because you haven’t added any models to the books app or added any apps to INSTALLED_APPS. Ergo, it’s always safe to run python manage.py syncdb—it won’t clobber things. If you’re interested, take a moment to dive into your database server’s command-line client and see the database tables Django created. You can manually run the command-line client (e.g., psql for PostgreSQL) or you can run the command python manage.py dbshell, which will figure out which command-line client to run, depending on your DATABASE_SERVER setting. The latter is almost always more convenient. Basic Data Access Once you’ve created a model, Django automatically provides a high-level Python API for working with those models. Try it out by running python manage.py shell and typing the following: >>> from books.models import Publisher >>> p1 = Publisher(name='Addison-Wesley', address='75 Arlington St.', ... city='Boston', state_province='MA', country='U.S.A.', ... website='http://www.addison-wesley.com/') >>> p.save() >>> p2 = Publisher(name="O'Reilly", address='10 Fawcett St.', ... city='Cambridge', state_province='MA', country='U.S.A.', ... website='http://www.oreilly.com/') >>> p2.save() >>> publisher_list = Publisher.objects.all() >>> publisher_list [Results for "{{ query|escape }}":
{% if results %}-
{% for book in results %}
- {{ book }} {% endfor %}
No books found
{% endif %} {% endif %} Hopefully by now what this does is fairly obvious. However, there are a few subtleties worth pointing out: • The form’s action is ., which means “the current URL.” This is a standard best practice: don’t use separate views for the form page and the results page—use a single one that serves the form and search results. • We reinsert the value of the query back into the . This lets readers easily refine their searches without having to retype what they searched for. • Everywhere query is used, we pass it through the escape filter to make sure that any potentially malicious search text is filtered out before being inserted into the page. It’s vital that you do this with any user-submitted content! Otherwise you open your site up to cross-site scripting (XSS) attacks. Chapter 19 discusses XSS and security in more detail. • However, we don’t need to worry about harmful content in your database lookups—we can simply pass the query into the lookup as is. This is because Django’s database layer handles this aspect of security for you. 97 7257ch07.qxd 98 11/1/07 1:27 PM Page 98 CHAPTER 7 ■ FORM PROCESSING Now we have a working search. A further improvement would be putting a search form on every page (i.e., in the base template); we’ll let you handle that one yourself. Next, we’ll look at a more complex example. But before we do, let’s discuss a more abstract topic: the “perfect form.” The “Perfect Form” Forms can often be a major cause of frustration for the users of your site. Let’s consider the behavior of a hypothetical perfect form: • It should ask the user for some information, obviously. Accessibility and usability matter here, so smart use of the HTML