Mastering Django: Core (2017) - PDF
Document Details
Uploaded by IlluminatingPixie
2017
Nigel George
Tags
Summary
This book, Mastering Django: Core, is a comprehensive guide to Django 1.8 LTS. It covers topics like installing Django, views, URLconfs, templates, and models. The book is aimed at programmers, and it includes examples, and practical exercises with questions and answers.
Full Transcript
Mastering Django: Core The Complete Guide to Django 1.8 LTS Nigel George This book is for sale at http://leanpub.com/masteringdjangocore This version was published on 2017-05-01 ISBN 978-0-9946168-0-7 This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishing proce...
Mastering Django: Core The Complete Guide to Django 1.8 LTS Nigel George This book is for sale at http://leanpub.com/masteringdjangocore This version was published on 2017-05-01 ISBN 978-0-9946168-0-7 This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishing process. Lean Publishing is the act of publishing an in-progress ebook using lightweight tools and many iterations to get reader feedback, pivot until you have the right book and build traction once you do. © 2016 - 2017 Nigel George Tweet This Book! Please help Nigel George by spreading the word about this book on Twitter! The suggested hashtag for this book is #masteringdjangocore. Find out what other people are saying about the book by clicking on this link to search for this hashtag on Twitter: https://twitter.com/search?q=#masteringdjangocore Contents Acknowledgements................................. i About the Author................................ i Introduction..................................... ii Why should you care about Django?..................... ii About This Book................................. iii How to Read This Book............................. iv Required Programming Knowledge..................... v Required Python Knowledge......................... v Required Django Version............................ vi Getting Help................................... vi Introduction to Django............................... vii Introducing Django............................. vii Django’s History............................... viii Chapter 1: Getting Started............................. 1 Installing Django................................ 1 Installing Python................................ 2 Python Versions............................... 2 Installation.................................. 3 Installing a Python Virtual Environment.................. 7 Installing Django................................ 9 Setting Up a Database............................. 10 Starting a Project................................ 11 Django Settings............................... 12 The Development Server.......................... 13 The Model-View-Controller (MVC) Design Pattern............ 15 What’s Next?................................... 17 CONTENTS Chapter 2: Views and URLconfs.......................... 18 Your First Django-Powered Page: Hello World............... 18 Your First View................................ 18 Your First URLconf............................. 19 Regular Expressions............................. 24 A Quick Note About 404 Errors...................... 25 A Quick Note About the Site Root.................... 27 How Django Processes a Request..................... 27 Your Second View: Dynamic Content.................... 28 URLconfs and Loose Coupling........................ 30 Your Third View: Dynamic URLs....................... 31 Django’s Pretty Error Pages.......................... 36 What’s Next?................................... 38 Chapter 3: Templates................................ 40 Template System Basics............................ 41 Using the Template System.......................... 43 Creating Template Objects......................... 44 Rendering a Template............................ 45 Dictionaries and Contexts........................... 46 Multiple Contexts, Same Template.................... 48 Context Variable Lookup.......................... 49 Method Call Behavior............................ 52 How Invalid Variables Are Handled.................... 54 Basic Template Tags and Filters....................... 54 Tags...................................... 55 Filters..................................... 64 Philosophies and Limitations......................... 65 Using Templates in Views........................... 68 Template Loading................................ 69 Template Directories............................ 70 render()...................................... 73 Template Subdirectories............................ 75 The include Template Tag........................... 75 Template Inheritance.............................. 77 What’s Next?................................... 82 Chapter 4: Models.................................. 84 CONTENTS The “Dumb” Way to Do Database Queries in Views............ 84 Configuring the Database........................... 85 Your First App.................................. 86 Defining Models in Python.......................... 88 Your First Model............................... 89 Installing the Model............................. 91 Basic Data Access................................ 95 Adding Model String Representations.................. 97 Inserting and Updating Data........................ 99 Selecting Objects.............................. 100 Filtering Data................................. 101 Retrieving Single Objects.......................... 103 Ordering Data................................ 104 Chaining Lookups.............................. 106 Slicing Data.................................. 106 Updating Multiple Objects in One Statement.............. 107 Deleting Objects............................... 109 What’s Next?................................... 110 Appendix G: Developing Django with Visual Studio............. 111 Installing Visual Studio............................. 112 Install PTVS and Web Essentials..................... 115 Creating A Django Project........................... 118 Start A Django Project........................... 118 Django Development in Visual Studio.................... 122 Integration of Django Management Commands............ 123 Easy Installation of Python Packages................... 123 Easy Installation of New Django Apps.................. 124 License & Copyright................................. 126 GNU Free Documentation License.................... 126 ADDENDUM: How to use this License for your documents..... 136 Acknowledgements First and foremost, I would like to thank the original authors of the Django Book - Adrian Holovaty and Jacob Kaplan-Moss. They provided such a strong foundation that it has really been a delight writing this new edition. Equal first in the shout out has to be the Django community. Vibrant and collaborative, the Django community is what really stood out to this cynical old businessman many years ago when I first discovered the “new kid on the web- framework block”. It’s your support that makes Django so great. Thank you. About the Author Nigel George is a business systems developer specializing in the application of Open Source technologies to solve common business prob- lems. He has a broad range of experience in software development - from writing database apps for small business, to developing the backend and UI for a distributed sensor network at the University of Newcastle, Australia. Nigel also has over 15 years’ experience in technical writing for business. He has written several training manuals and hundreds of technical procedures for corporations and Australian government departments. He has been using Django since version 0.96 and has written applications in C, C#, C++, VB, VBA, HTML, JavaScript, Python and PHP. He has another book on Django - Beginning Django CMS - published by Apress in December 2015. Nigel lives in Newcastle, NSW, Australia. Introduction This year (2014) it will be 30 years since I plugged the 5.25” DOS 3.3 disk into my school’s very first Apple IIe computer and discovered BASIC. In the intervening years I have written more lines of code than I could guess in about a dozen languages. I still write code every week - although the list of languages, and number of lines are somewhat diminished these days. Over the years I have seen plenty of horrible code and some really good stuff too. In my own work, I have written my fair share of good and bad. Interestingly, not once in my career have I been employed as a programmer. I had my own IT business for five years, and have been in businesses large and small - mostly in R&D, technical and operations management - but never working solely as a programmer. What I have been is the guy that gets called up to Get Stuff Done. Emphasized for good reason - business is all about Getting Stuff Done. When everything has to work yesterday, religious wars over curly braces and pontif- ication over which language is best for what application become trivialities. Having read dozens and dozens of textbooks on all the various programming languages I have used, I know why you are here reading the introduction, so let’s get right to the point. Why should you care about Django? While it is a given that Django is not the only web framework that will allow you to Get Stuff Done, I can confidently say one thing - if you want to write clean, intelligible code and build high performance, good looking modern websites quickly, then you will definitely benefit from working through this book. I have deliberately not rattled off comparisons with other languages and frame- works because that’s not the point - all languages and the frameworks and tools built on them have strengths and weaknesses. However, having worked with many of them over the years, I am totally convinced that Django stands way out Introduction iii in front for ease of use and ability to allow a programmer to produce robust, secure, and bug free code quickly. Django is spectacularly good at getting out of your way when you just need to Get Something Done, but still exposes all the good stuff just under the surface when you want to dig down further. Django is also built with Python, arguably the most intelligible and easy to learn programming language. Of course these strengths do bring one challenge. Because both Python and Django hide an enormous amount of power and functionality just below the surface, it can be a bit confusing for beginners. This is where this book comes in. 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. Adrian and Jacob wrote the original Django Book because they firmly be- lieved that Django makes Web development better. I think Django’s longevity and exponential growth in the years since the publication of the original Django Book is testament to this belief. As per the original, this book is open source and all are welcome to improve it by either submitting comments and suggestions at the Mastering Django website1 , or sending me an email to [email protected]. I, like many, get a great deal of pleasure out of working with Django - it truly is as exciting, fun and useful as Adrian and Jacob had hoped it would be! About This Book This book is about Django, a Web development framework that saves you time and makes Web development a joy. Using Django, you can build and maintain high-quality Web applications with minimal fuss. Mastering Django: Core is a completely revised and updated version of the Django Book - first published by Apress in 2007 as The Definitive Guide to Django: Web Development Done Right and then republished as The Django Book by the original authors in 2009. The latter publication was released as an Open Source project under the Gnu Free Documentation License (GFDL). Mastering Django: Core could be considered an unofficial 3rd edition of the Django Book, although I will leave it up to Jacob and the Django community to 1 http://masteringdjango.com Introduction iv decide whether it deserves that honor. Personally, I just wanted to see it back out there because, like many Django programmers, the Django Book is where I got started. To retain Adrian and Jacob’s original desire for the Django Book to be accessible as possible, the source code for Mastering Django: Core is freely available online on the Mastering Django website. The main goal of this book is to make you a Django expert. The focus is twofold. First, I explain in depth what Django does and how to build Web applications with it. Second, I 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. The secondary, but no less important, goal of this book is to provide a pro- grammer’s manual that covers the current Long Term Support (LTS) version of Django. Django has matured to the point where it is seeing many commercial and business critical deployments. As such, this book is intended to provide the definitive up-to-date resource for commercial deployment of Django 1.8 LTS. The electronic version of this book will be kept in sync with Django 1.8 right up until the end of extended support (2018). How to Read This Book In writing Mastering Django: Core, I have tried to maintain a similar balance between readability and reference as the first book, however Django has grown considerably since 2007 and with increased power and flexibility, comes some additional complexity. Django still has one of the shortest learning curves of all the web application frameworks, but there is still some solid work ahead of you if you want to become a Django expert. This book retains the same “learn by example” philosophy as the original book, however some of the more complex sections (database configuration for example) have been moved to later chapters. This is so that you can first learn how Django works with a simple, out-of-the-box configuration and then build on your knowledge with more advanced topics later. With that in mind, I recommend that you read Chapters 1 through 13 in order. They form the foundation of how to use Django; once you’ve read them, you’ll be able to build and deploy Django-powered Web sites. Specifically, Chapters 1 through 6 are the “core curriculum,” Chapters 7 through 12 cover more Introduction v advanced Django usage, and Chapter 13 covers deployment. The remaining chapters, 14 through 21, focus on specific Django features and can be read in any order. The appendices are for reference. They, along with the free documentation at the Django Project2 , are probably what you’ll flip back to occasionally to recall syntax or find quick synopses of what certain parts of Django do. Required Programming Knowledge Readers of this book should understand the basics of procedural and object- oriented programming: control structures (e.g., if, while, for), data structures (lists, hashes/dictionaries), variables, classes and objects. Experience in Web development is, as you may expect, very helpful, but it’s not required to understand this book. Throughout the book, I try to promote best practices in Web development for readers who lack this experience. Required Python Knowledge At its core, Django is simply a collection of libraries written in the Python programming language. To develop a site using Django, you write Python code that uses these libraries. Learning Django, then, is a matter of learning how to program in Python and understanding how the Django libraries work. If you have experience programming in Python, you should have no trouble diving in. By and large, the Django code doesn’t perform a lot of “magic” (i.e., programming trickery whose implementation is difficult to explain or understand). For you, learning Django will be a matter of learning Django’s conventions and APIs. If you don’t have experience programming in Python, you’re in for a treat. It’s easy to learn and a joy to use! Although this book doesn’t include a full Python tutorial, it highlights Python features and functionality where appropriate, particularly when code doesn’t immediately make sense. Still, I recommend you read the official Python tutorial3. I also recommend Mark Pilgrim’s free book Dive Into Python, available online at http://www.diveintopython.net/ and published in print by Apress. 2 http://www.djangoproject.com/ 3 http://docs.python.org/tut/ Introduction vi Required Django Version This book covers Django 1.8 Long Term Support (LTS). This is the long term support version of Django, with full support until at least April 2018. If you have an early version of Django, it is recommended that you upgrade to the latest version of Django 1.8 LTS. At the time of printing (July 2016), the most current production version of Django 1.8 LTS is 1.8.13. If you have installed a later version of Django, please note that while Django’s developers maintain backwards compatibility as much as possible, some back- wards incompatible changes do get introduced occasionally. The changes in each release are always covered in the release notes, which you can find at https://docs.djangoproject.com/en/dev/releases/. Getting Help One of the greatest benefits of Django is its kind and helpful user community. For help with any aspect of Django - from installation, to application design, to database design, to deployment - feel free to ask questions online. The django-users mailing list is where thousands of Django users hang out to ask and answer questions. Sign up for free at http://www.djangoproject.com/r/django-users. The Django IRC channel is where Django users hang out to chat and help each other in real time. Join the fun by logging on to #django on the Freenode IRC network. Introduction to Django Great open source software almost always comes about because one or more clever developers had a problem to solve and no viable or cost effective solution available. Django is no exception. Adrian and Jacob have long since “retired” from the project, but the fundamentals of what drove them to create Django live on. It is this solid base of real-world experience that has made Django as successful as it is. In recognition of their contribution, I think it best we let them introduce Django in their own words (edited and reformatted from the original book). Introducing Django By Adrian Holovaty and Jacob Kaplan-Moss - December 2009 In the early days, Web developers wrote every page by hand. Updating a Web site meant editing HTML; a “redesign” involved redoing every single page, one at a time. As Web sites grew and became more ambitious, it quickly became obvious that that approach was tedious, time-consuming, and ultimately un- tenable. A group of enterprising hackers at NCSA (the National Center for Super- computing 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 the most popular tool used to create dynamic Web sites, and dozens of similar Introduction to Django viii languages (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; it’s very ease of use encourages sloppy, repet- itive, ill-conceived code. Worse, PHP does little to protect programmers from security vulnerabilities, and thus many PHP developers found themselves learn- ing about security only once it was too late. These and similar frustrations led directly to the development of the current crop of “third-generation” Web development frameworks. With this new ex- plosion 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’s History Django grew organically from real-world applications written by a Web devel- opment team in Lawrence, Kansas, USA. It was born in the fall of 2003, when the Web programmers at the Lawrence Journal-World newspaper, Adrian Holovaty and Simon Willison, began using Python to build applications. The World Online team, responsible for the production and maintenance of several local news sites, thrived in a development environment dictated by journalism deadlines. For the sites - including LJWorld.com, Lawrence.com and KUsports.com - journalists (and management) demanded that features be added and entire applications be built on an intensely fast schedule, often with only days’ or hours’ notice. Thus, Simon and Adrian developed a time-saving Web development framework out of necessity - it was the only way they could build maintainable applications under the extreme deadlines. In summer 2005, after having developed this framework to a point where it was efficiently powering most of World Online’s sites, the team, which now included Jacob Kaplan-Moss, decided to release the framework as open source software. They released it in July 2005 and named it Django, after the jazz guitarist Django Reinhardt. This history is relevant because it helps explain two key things. The first is Django’s “sweet spot.” Because Django was born in a news environment, it offers Introduction to Django ix several features (such as its admin site, covered in Chapter 5) that are particu- larly well suited for “content” sites - sites like Amazon.com, craigslist.org, and washingtonpost.com that offer dynamic, database-driven information. Don’t let that turn you off, though - although Django is particularly good for developing those sorts of sites, that doesn’t preclude it from being an effective tool for building any sort of dynamic Web site. (There’s a difference between being particularly effective at something and being ineffective at other things.) The second matter to note is how Django’s origins have shaped the culture of its open source community. Because Django was extracted from real-world code, rather than being an academic exercise or commercial product, it is acutely focused on solving Web development problems that Django’s developers them- selves have faced - and continue to face. As a result, Django itself is actively improved on an almost daily basis. The framework’s maintainers have a vested interest in making sure Django saves developers time, produces applications that are easy to maintain and performs well under load. 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 devel- opment 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 suc- cessfully design, develop, and deploy a site that you’ll be proud of. Chapter 1: Getting Started There are two very important things you need to do to get started with Django: 1. Install Django (obviously); and 2. Get a good understanding of the Model-View-Controller (MVC) design pattern. The first, installing Django, is really simple and detailed in the first part of this chapter. The second is just as important, especially if you are a new programmer or coming from using a programming language that does not clearly separate the data and logic behind your website from the way it is displayed. Django’s philosophy is based on loose coupling, which is the underlying philosophy of MVC. We will be discussing loose coupling and MVC in much more detail as we go along, but if you don’t know much about MVC, then you best not skip the second half of this chapter, because understanding MVC will make understanding Django so much easier. Installing Django Before you can start learning how to use Django, you must first install some software on your computer. Fortunately, this is a simple three step process: 1. Install Python. 2. Install a Python Virtual Environment. 3. Install Django. If this does not sound familiar to you don’t worry, in this chapter I assume you have never installed software from the command line before and will lead you through it step by step. I have written this section for those of you running Windows. While there is a strong *nix and OSX user base for Django, most new users are on Windows. If Chapter 1: Getting Started 2 you are using Mac or Linux, there are a large number of resources on the Inter- net; with the best place to start being Django’s own installation instructions4. For Windows users, your computer can be running any recent version of Windows (Vista, 7, 8.1 or 10). This chapter also assumes you’re installing Django on a desktop or laptop computer and will be using the development server and SQLite to run all the example code in this book. This is by far the easiest, and best way to setup Django when you are first starting out. If you do want to go to a more advanced installation of Django, your options are covered in Chapter 13 - Deploying Django, Chapter 20 - More on installing Django and Chapter 21 - Advanced Database Management. If you are using Windows, I recommend that you try out Visual Studio for all your Django development. Microsoft have made a significant investment in providing support for Python and Django program- mers. This includes full IntelliSense support for Python/Django and incorporation of all of Django’s command line tools into the VS IDE. Best of all it’s entirely free. I know, who would have expected that from M$??, but it’s true! See Appendix G for a complete installation guide for Visual Studio Community 2015, as well as a few tips on developing Django in Windows. Installing Python Django itself is written purely in Python, so the first step in installing the framework is to make sure you have Python installed. Python Versions Django version 1.8 LTS works with Python version 2.7, 3.3, 3.4 and 3.5. For each version of Python, only the latest micro release (A.B.C) is supported. If you are just trialling Django, it doesn’t really matter whether you use Python 2 or Python 3. If, however, you are planning on eventually deploying code to a 4 https://docs.djangoproject.com/en/1.8/topics/install/ Chapter 1: Getting Started 3 live website, Python 3 should be your first choice. The Python wiki5 puts the reason behind this very succinctly: Short version: Python 2.x is legacy, Python 3.x is the present and future of the language Unless you have a very good reason to use Python 2 (e.g. legacy libraries), Python 3 is the way to go. NOTE: All of the code samples in this book are written in Python 3 Installation If you’re on Linux or Mac OS X, you probably have Python already installed. Type python at a command prompt (or in Applications/Utilities/Terminal, in OS X). If you see something like this, then Python is installed: Python 2.7.5 (default, June 27 2015, 13:20:20) [GCC x.x.x] on xxx Type "help", "copyright", "credits" or "license" for more information. >>> You can see that, in the above example, Python interactive mode is running Python 2.7. This is a trap for inexperienced users. On Linux and Mac OS X machines, it is common for both Python 2 and Python 3 to be installed. If your system is like this, you need to type python3 in front of all your commands, rather than python to run Django with Python 3. Assuming Python is not installed in your system, we first need to get the installer. Go to https://www.python.org/downloads/ and click the big yellow button that says “Download Python 3.x.x”. At the time of writing, the latest version of Python is 3.5.1, but it may have been updated by the time you read this, so the numbers may be slightly different. 5 https://wiki.python.org/moin/Python2orPython3 Chapter 1: Getting Started 4 DO NOT download version 2.7.x as this is the old version of Python. All of the code in this book is written in Python 3, so you will get compilation errors if you try to run the code on Python 2. Once you have downloaded the Python installer, go to your Downloads folder and double click the file “python-3.x.x.msi” to run the installer. The installation process is the same as any other Windows program, so if you have installed software before, there should be no problem here, however the is one extremely important customization you must make. Do not forget this next step as it will solve most problems that arise from incorrect mapping of pythonpath (an important variable for Python installations) in Windows. By default, the Python executable is not added to the Windows PATH statement. For Django to work properly, Python must be listed in the PATH statement. Fortunately, this is easy to rectify: In Python 3.4.x, When the installer opens the customization window, the option “Add python.exe to Path” is not selected, you must change this to “Will be installed on local hard drive” as shown in Figure 1-1. In Python 3.5.x you make sure “Add Python 3.5 to PATH” is checked before installing (Figure 1-2). Chapter 1: Getting Started 5 Figure 1-1: Add Python to PATH (Version 3.4.x). Chapter 1: Getting Started 6 Figure 1-2: Add Python to PATH (Version 3.5.x). Once Python is installed, you should be able to re-open the command window and type python at the command prompt and get something like this: Python 3.5.1 (v3.5.1:37a07cee5969, Dec 6 2015, 01:38:48) [MSC v.1900 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> While you are at it, there is one more important thing to do. Exit out of Python with CTRL-C. At the command prompt type, the following and hit enter: python -m pip install -U pip The output will be something similar to this: Chapter 1: Getting Started 7 C:\Users\nigel>python -m pip install -U pip Collecting pip Downloading pip-8.1.2-py2.py3-none-any.whl (1.2MB) 100% |################################| 1.2MB 198kB/s Installing collected packages: pip Found existing installation: pip 7.1.2 Uninstalling pip-7.1.2: Successfully uninstalled pip-7.1.2 Successfully installed pip-8.1.2 You don’t need to understand exactly what this command does right now; put briefly pip is the Python package manager. It’s used to install Python packages: pip is actually a recursive acronym for “Pip Installs Packages”. Pip is important for the next stage of our install process, but first we need to make sure we are running the latest version of pip (8.1.2 at the time of writing), which is exactly what this command does. Installing a Python Virtual Environment If you are going to use Microsoft Visual Studio (VS), you can stop here and jump to Appendix G. VS only requires that you install Python, everything else VS does for you from inside the Integrated Development Environment (IDE). All of the software on your computer operates interdependently - each pro- gram has other bits of software that it depends on (called dependencies) and settings that it needs to find the files and other software it needs to run (call environment variables). When you are writing new software programs, it is possible (and common!) to modify dependencies and environment variables that your other software depends on. This can cause numerous problems, so should be avoided. A Python virtual environment solves this problem by wrapping all the depen- dencies and environment variables that your new software needs into a file system separate from the rest of the software on your computer. Chapter 1: Getting Started 8 Some of you who have looked at other tutorials will note that this step is often described as optional. This is not a view I support, nor is it supported by a number of Django’s core developers. The advantages of developing Python applications (of which Django is one) within a virtual environment are manifest and not worth going through here. As a beginner, you just need to take my word for it - running a virtual environment for Django development is not optional. The virtual environment tool in Python is called virtualenv and we install it from the command line using pip: pip install virtualenv The output from your command window should look something like this: C:\Users\nigel>pip install virtualenv Collecting virtualenv Downloading virtualenv-15.0.2-py2.py3-none-any.whl (1.8MB) 100% |################################| 1.8MB 323kB/s Installing collected packages: virtualenv Successfully installed virtualenv-15.0.2 Once virtualenv is installed, you need to create a virtual environment for your project by typing: virtualenv env_mysite Most examples on the Internet use “env” as your environment name. This is bad; principally because it’s common to have several virtual environments installed to test different configurations, and “env” is not very descriptive. For example, you may be developing an application that must run on Python 2.7 and Python 3.4. Envi- ronments named “env_someapp_python27” and “env_someapp_- python34” are going to be a lot easier to distinguish than if you had named them “env” and “env1”. In this example, I have kept it simple as we will only be using one virtual environment for our project, so I have used “env_mysite”. The output from your command should look something like this: Chapter 1: Getting Started 9 C:\Users\nigel>virtualenv env_mysite Using base prefix 'c:\\users\\nigel\\appdata\\lo\ cal\\programs\\python\\python35-32' New python executable in C:\Users\nigel\env_mysite\Scripts\python.exe Installing setuptools, pip, wheel...done. Once virtualenv has finished setting up your new virtual environment, open Windows Explorer and have a look at what virtualenv created for you. In your home directory, you will now see a folder called \env_mysite (or whatever name you gave the virtual environment). If you open the folder, you will see the following: \Include \Lib \Scripts \src Virtualenv has created a complete Python installation for you, separate from your other software, so you can work on your project without affecting any of the other software on you system. To use this new Python virtual environment, we have to activate it, so let’s go back to the command prompt and type the following: env_mysite\scripts\activate This will run the activate script inside your virtual environment’s \scripts folder. You will notice your command prompt has now changed: (env_mysite) C:\Users\nigel> The (env_mysite) at the beginning of the command prompt lets you know that you are running in the virtual environment. Our next step is to install Django. Installing Django Now that we have Python and are running a virtual environment, installing Django is super easy, just type the command: Chapter 1: Getting Started 10 pip install django==1.8.13 This will instruct pip to install Django into your virtual environment. Your command output should look like this: (env_mysite) C:\Users\nigel>pip install django==1.8.13 Collecting django==1.8.13 Downloading Django-1.8.13-py2.py3-none-any.whl (6.2MB) 100% |################################| 6.2MB 107kB/s Installing collected packages: django Successfully installed django-1.8.13 In this case, we are explicitly telling pip to install Django 1.8.13, which is the latest version of Django 1.8 LTS at the time of writing. If you are installing Django, it’s good practice to check the Django Project website for the latest version of Django 1.8 LTS. In case you were wondering, typing in pip install django will in- stall the latest stable release of Django. If you want information on installing the latest development release of Django, see Chapter 20. For some post-installation positive feedback, take a moment to test whether the installation worked. At your virtual environment command prompt, start the Python interactive interpreter by typing python and hitting enter. If the installation was successful, you should be able to import the module django: (env_mysite) C:\Users\nigel>python Python 3.5.1 (v3.5.1:37a07cee5969, Dec 6 2015, 01:38:48) [MSC v.1900 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import django >>> django.get_version() '1.8.13' Setting Up a Database This step is not necessary in order to complete any of the examples in this book. Django comes with SQLite installed by default. SQLite requires no configuration on your part. If you would like to work with a “large” database engine like PostgreSQL, MySQL, or Oracle, see Chapter 21. Chapter 1: Getting Started 11 Starting a Project Once you’ve installed Python, Django and (optionally) your database server/li- brary, you can take the first step in developing a Django application by creating a project. A project is a collection of settings for an instance of Django. If this is your first time using Django, you’ll have to take care of some initial setup. Namely, you’ll need to auto-generate some code that establishes a Django project: a collection of settings for an instance of Django, including database configuration, Django- specific options and application-specific settings. I am assuming at this stage you are still running the virtual environment from the previous installation step. If not, you will have to start it again with env_- mysite\scripts\activate\. From your virtual environment command line, run the following command: django-admin startproject mysite This will create a mysite directory in your current directory (in this case \env_mysite\). If you want to create your project in a directory other than the root, you can create a new directory, change into that directory and run the startproject command from there. Warning! You’ll need to avoid naming projects after built-in Python or Django components. In particular, this means you should avoid using names like “django” (which will conflict with Django itself) or “test” (which conflicts with a built-in Python package). Let’s look at what startproject created: Chapter 1: Getting Started 12 mysite/ manage.py mysite/ __init__.py settings.py urls.py wsgi.py These files are: The outer mysite/ root directory. It’s just a container for your project. Its name doesn’t matter to Django; you can rename it to anything you like. manage.py. A command-line utility that lets you interact with your Django project in various ways. You can read all the details about manage.py on the Django Project website6. The inner mysite/ directory. It’s the Python package for your project. It’s the name you’ll use to import anything inside it (e.g. mysite.urls). mysite/__init__.py. An empty file that tells Python that this directory should be considered a Python package. (Read more about packages in the official Python docs7 if you’re a Python beginner.). mysite/settings.py. Settings/configuration for this Django project. Ap- pendix D will tell you all about how settings work. mysite/urls.py. The URL declarations for this Django project; a “table of contents” of your Django-powered site. You can read more about URLs in Chapters 2 and 7. mysite/wsgi.py. An entry-point for WSGI-compatible web servers to serve your project. See Chapter 13 for more details. Django Settings Now, edit mysite/settings.py. It’s a normal Python module with module- level variables representing Django settings. First step while you’re editing settings.py, is to set TIME_ZONE to your time zone. Note the INSTALLED_APPS setting at the top of the file. That holds the names of all Django applications that are activated in this Django instance. Apps can be used in multiple projects, 6 https://docs.djangoproject.com/en/1.8/ref/django-admin/ 7 https://docs.python.org/tutorial/modules.html#packages Chapter 1: Getting Started 13 and you can package and distribute them for use by others in their projects. By default, INSTALLED_APPS contains the following apps, all of which come with Django: django.contrib.admin - The admin site. django.contrib.auth - An authentication system. django.contrib.contenttypes - A framework for content types. django.contrib.sessions - A session framework. django.contrib.messages - A messaging framework. django.contrib.staticfiles - A framework for managing static files. These applications are included by default as a convenience for the common case. Some of these applications makes use of at least one database table though, so we need to create the tables in the database before we can use them. To do that, run the following command: python manage.py migrate The migrate command looks at the INSTALLED_APPS setting and creates any nec- essary database tables according to the database settings in your settings.py file and the database migrations shipped with the app (we’ll cover those later). You’ll see a message for each migration it applies. The Development Server Let’s verify your Django project works. Change into the outer mysite directory, if you haven’t already, and run the following commands: python manage.py runserver You’ll see the following output on the command line: Chapter 1: Getting Started 14 Performing system checks... 0 errors found June 12, 2016 - 08:48:58 Django version 1.8.13, using settings 'mysite\.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CTRL-BREAK. You’ve started the Django development server, a lightweight Web server written purely in Python. We’ve included this with Django so you can develop things rapidly, without having to deal with configuring a production server - such as Apache - until you’re ready for production. Now’s a good time to note: don’t use this server in anything resembling a production environment. It’s intended only for use while developing. Now that the server’s running, visit http://127.0.0.1:8000/ with your Web browser. You’ll see a “Welcome to Django” page in pleasant, light-blue pastel (Figure 1-3). It worked! Chapter 1: Getting Started 15 Figure 1-3: Django’s welcome page Automatic reloading of runserver The development server automatically reloads Python code for each request as needed. You don’t need to restart the server for code changes to take effect. However, some actions like adding files don’t trigger a restart, so you’ll have to restart the server in these cases. The Model-View-Controller (MVC) Design Pattern MVC has been around as a concept for a long time, but has seen exponential growth since the advent of the Internet because it is the best way to design client-server applications. All of the best web frameworks are built around the MVC concept. At the risk of starting a flame war, I contest that if you are not using MVC to design web apps, you are doing it wrong. As a concept, the MVC design pattern is really simple to understand: Chapter 1: Getting Started 16 The model(M) is a model or representation of your data. It’s not the actual data, but an interface to the data. The model allows you to pull data from your database without knowing the intricacies of the underlying database. The model usually also provides an abstraction layer with your database, so that you can use the same model with multiple databases. The view(V) is what you see. It’s the presentation layer for your model. On your computer, the view is what you see in the browser for a Web app, or the UI for a desktop app. The view also provides an interface to collect user input. The controller(C) controls the flow of information between the model and the view. It uses programmed logic to decide what information is pulled from the database via the model and what information is passed to the view. It also gets information from the user via the view and implements business logic: either by changing the view, or modifying data through the model, or both. Where it gets difficult is the vastly different interpretations of what actually happens at each layer - different frameworks implement the same functionality in different ways. One framework “guru” might say a certain function belongs in a view, while another might vehemently defend the need for it to be in the controller. You, as a budding programmer who Gets Stuff Done, do not have to care about this because in the end, it doesn’t matter. As long as you understand how Django implements the MVC pattern, you are free to move on and get some real work done. Although, watching a flame war in a comment thread can be a highly amusing distraction… Django follows the MVC pattern closely, however it does use its own logic in the implementation. Because the “C” is handled by the framework itself and most of the excitement in Django happens in models, templates and views, Django is often 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. We will be looking closely at Django’s models in Chapter 4. T stands for “Template,” the presentation layer. This layer contains pre- sentation-related decisions: how something should be displayed on a Web Chapter 1: Getting Started 17 page or other type of document. We will explore Django’s templates in Chapter 3. 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. We will be checking out Django’s views in the next chapter. This is probably the only unfortunate bit of naming in Django, because Django’s view is more like the controller in MVC, and MVC’s view is actually a Template in Django. It is a little confusing at first, but as a programmer getting a job done, you really won’t care for long. It is only a problem for those of us who have to teach it. Oh, and to the flamers of course. What’s Next? Now that you have everything installed and the development server running, you’re ready to move on to Django’s views and learning the basics of serving Web pages with Django. Chapter 2: Views and URLconfs In the previous chapter, I explained how to set up a Django project and run the Django development server. In this chapter, you’ll learn the basics of creating dynamic Web pages with Django. Your First Django-Powered Page: Hello World As our first goal, let’s create a Web page that outputs that famous example message: “Hello world.” If you were publishing a simple “Hello world” Web page without a Web framework, you’d simply type “Hello world” into a text file, call it “hello.html", and upload it to a directory on a Web server some- where. Notice in that process you’ve specified two key pieces of information about that Web page: its contents (the string "Hello world") and its URL (e.g. http://www.example.com/hello.html). With Django, you specify those same two things, but in a different way. The contents of the page are produced by a view function, and the URL is specified in a URLconf. First, let’s write our “Hello world” view function. Your First View Within the mysite directory that we created in the last chapter, create an empty file called views.py. This Python module will contain our views for this chapter. Our “Hello world” view is simple. Here’s the entire function, plus import statements, which you should type into the views.py file: from django.http import HttpResponse def hello(request): return HttpResponse("Hello world") Let’s step through this code one line at a time: Chapter 2: Views and URLconfs 19 First, we import the class HttpResponse, which lives in the django.http module. We need to import this class because it’s used later in our code. Next, we define a function called hello- the view function. Each view function takes at least one parameter, called request by convention. This is an object that contains information about the current Web request that has triggered this view, and is an instance of the class django.http.HttpRequest. In this example, we don’t do anything with request, but it must be the first parameter of the view nonetheless. Note that the name of the view function doesn’t matter; it doesn’t have to be named in a certain way in order for Django to recognize it. We’re calling it hello here, because that name clearly indicates the gist of the view, but it could just as well be named hello_wonderful_- beautiful_world, or something equally revolting. The next section, “Your First URLconf”, will shed light on how Django finds this function. The function is a simple one-liner: it merely returns an HttpResponse object that has been instantiated with the text "Hello world". The main lesson here is this: a view is just a Python function that takes an HttpRequest as its first parameter and returns an instance of HttpResponse. In order for a Python function to be a Django view, it must do these two things. (There are exceptions, but we’ll get to those later.) Your First URLconf If, at this point, you ran python manage.py runserver again, you’d still see the “Welcome to Django” message, with no trace of our “Hello world” view anywhere. That’s because our mysite project doesn’t yet know about the hello view; we need to tell Django explicitly that we’re activating this view at a particular URL. Continuing our previous analogy of publishing static HTML files, at this point we’ve created the HTML file but haven’t uploaded it to a directory on the server yet. To hook a view function to a particular URL with Django, we use a URLconf. A URLconf is like a table of contents for your Django-powered Web site. Basically, it’s a mapping between URLs and the view functions that should be called for those URLs. It’s how you tell Django, “For this URL, call this code, and for that URL, call that code.” Chapter 2: Views and URLconfs 20 For example, when somebody visits the URL /foo/, call the view function foo_- view(), which lives in the Python module views.py. When you executed django- admin startproject in the previous chapter, the script created a URLconf for you automatically: the file urls.py. By default, it looks something like this: """mysite URL Configuration The urlpatterns list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/1.8/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') Including another URLconf 1. Add an import: from blog import urls as blog_urls 2. Add a URL to urlpatterns: url(r'^blog/', include(blog_urls)) """ from django.conf.urls import include, url from django.contrib import admin urlpatterns = [ url(r'^admin/', include(admin.site.urls)), ] If we ignore the documentation comments at the top of the file, here’s the essence of a URLconf: from django.conf.urls import include, url from django.contrib import admin urlpatterns = [ url(r'^admin/', include(admin.site.urls)), ] Let’s step through this code one line at a time: Chapter 2: Views and URLconfs 21 The first line imports two functions from the django.conf.urls module: include which allows you to include a full Python import path to another URLconf module, and url which uses a regular expression to pattern match the URL in your browser to a module in your Django project. The second line calls the function admin from the django.contrib module. This function is called by the include function to load the URLs for the Django admin site. The third line is urlpatterns - a simple list of url() instances. The main thing to note here is the variable urlpatterns, which Django expects to find in your URLconf module. This variable defines the mapping between URLs and the code that handles those URLs. To add a URL and view to the URLconf, just add a mapping between a URL pattern and the view function. Here’s how to hook in our hello view: from django.conf.urls import include, url from django.contrib import admin from mysite.views import hello urlpatterns = [ url(r'^admin/', include(admin.site.urls)), url(r'^hello/$', hello), ] We made two changes here: First, we imported the hello view from its module - mysite/views.py, which translates into mysite.views in Python import syntax. (This as- sumes mysite/views.py is on your Python path.) Next, we added the line url(r'ˆhello/$', hello), to urlpatterns. This line is referred to as a URLpattern. The url() function tells Django how to handle the url that you are configuring. The first argument is a pattern- matching string (a regular expression; more on this in a bit) and the second argument is the view function to use for that pattern. url() can take other optional arguments as well, which we’ll cover in more depth in Chapter 7. One more important detail we’ve introduced here is that ‘r’ character in front of the regular expression string. This tells Python that the string is a “raw string” - its contents should not interpret backslashes. Chapter 2: Views and URLconfs 22 In normal Python strings, backslashes are used for escaping special characters - such as in the string “\n”, which is a one-character string containing a newline. When you add the r to make it a raw string, Python does not apply its backslash escaping - so, “r'\n'” is a two-character string containing a literal backslash and a lowercase “n”. There’s a natural collision between Python’s usage of backslashes and the backslashes that are found in regular expressions, so it’s best practice to use raw strings any time you’re defining a regular expression in Django. In a nutshell, we just told Django that any request to the URL /hello/ should be handled by the hello view function. It’s worth discussing the syntax of this URLpattern, as it may not be immediately obvious. Although we want to match the URL /hello/, the pattern looks a bit different than that. Here’s why: Django removes the slash from the front of every incoming URL before it checks the URLpatterns. This means that our URLpattern doesn’t include the leading slash in /hello/. At first, this may seem unintuitive, but this requirement simplifies things - such as the inclusion of URLconfs within other URLconfs, which we’ll cover in Chapter 7. The pattern includes a caret (ˆ) and a dollar sign ($). These are regular expression characters that have a special meaning: the caret means “require that the pattern matches the start of the string,” and the dollar sign means “require that the pattern matches the end of the string.” This concept is best explained by example. If we had instead used the pattern ˆhello/ (without a dollar sign at the end), then any URL starting with /hello/ would match, such as /hello/foo and /hello/bar, not just /hello/. Similarly, if we had left off the initial caret character (i.e., hello/$), Django would match any URL that ends with hello/, such as /foo/bar/hello/. If we had simply used hello/, without a caret or dollar sign, then any URL containing hello/ would match, such as /foo/hello/bar. Thus, we use both the caret and dollar sign to ensure that only the URL /hello/ matches - nothing more, nothing less. Most of your URLpatterns will start with carets and end with dollar signs, but it’s nice to have the flexibility to perform more sophisticated matches. Chapter 2: Views and URLconfs 23 You may be wondering what happens if someone requests the URL /hello (that is, without a trailing slash). Because our URLpattern requires a trailing slash, that URL would not match. However, by default, any request to a URL that doesn’t match a URLpattern and doesn’t end with a slash will be redirected to the same URL with a trailing slash (This is regulated by the APPEND_SLASH Django setting, which is covered in Appendix D). The other thing to note about this URLconf is that we’ve passed the hello view function as an object without calling the function. This is a key feature of Python (and other dynamic languages): functions are first-class objects, which means you can pass them around just like any other variables. Cool stuff, eh? To test our changes to the URLconf, start the Django development server, as you did in Chapter 1, by running the command python manage.py runserver. (If you left it running, that’s fine, too. The development server automati- cally detects changes to your Python code and reloads as necessary, so you don’t have to restart the server between changes.) The server is running at the address http://127.0.0.1:8000/, so open up a Web browser and go to http://127.0.0.1:8000/hello/. You should see the text “Hello world” - the output of your Django view (Figure 2-1). Chapter 2: Views and URLconfs 24 Figure 2-1: Hooray! Your first Django view. Regular Expressions Regular expressions (or regexes) are a compact way of specifying patterns in text. While Django URLconfs allow arbitrary regexes for powerful URL matching, you’ll probably only use a few regex symbols in practice. Table 2-1 lists a selection of common symbols. Table 2-1: Common regex symbols Chapter 2: Views and URLconfs 25 Symbol Matches. (dot) Any single character \d Any single digit [A-Z] Any character between A and Z (uppercase) [a-z] Any character between a and z (lowercase) [A-Za- Any character between a and z (case-insensitive) z] + One or more of the previous expression (e.g., \d+ matches one or more digits) [ˆ/]+ One or more characters until (and not including) a forward slash ? Zero or one of the previous expression (e.g., \d? matches zero or one digits) * Zero or more of the previous expression (e.g., \d* matches zero, one or more than one digit) {1,3} Between one and three (inclusive) of the previous expression (e.g., \d{1,3} matches one, two or three digits) For more on regular expressions, see the Python regex documentation8. A Quick Note About 404 Errors At this point, our URLconf defines only a single URLpattern: the one that handles requests to the URL /hello/. What happens when you request a different URL? To find out, try running the Django development server and visiting a page such as http://127.0.0.1:8000/goodbye/. You should see a “Page not found” message (Figure 2-2). Django displays this message because you requested a URL that’s not defined in your URLconf. 8 https://docs.python.org/3.4/library/re.html Chapter 2: Views and URLconfs 26 Figure 2-2: Django’s 404 page The utility of this page goes beyond the basic 404 error message. It also tells you precisely which URLconf Django used and every pattern in that URLconf. From that information, you should be able to tell why the requested URL threw a 404. Naturally, this is sensitive information intended only for you, the Web developer. If this were a production site deployed live on the Internet, you wouldn’t want to expose that information to the public. For that reason, this “Page not found” page is only displayed if your Django project is in debug mode. I’ll explain how to deactivate debug mode later. For now, just know that every Django project is in debug mode when you first create it, and if the project is not in debug mode, Django outputs a different 404 response. Chapter 2: Views and URLconfs 27 A Quick Note About the Site Root As explained in the last section, you’ll see a 404 error message if you view the site root - http://127.0.0.1:8000/. Django doesn’t magically add anything to the site root; that URL is not special-cased in any way. It’s up to you to assign it to a URLpattern, just like every other entry in your URLconf. The URLpattern to match the site root is a bit unintuitive, though, so it’s worth mentioning. When you’re ready to implement a view for the site root, use the URLpattern “ˆ$”, which matches an empty string. For example: from mysite.views import hello, my_homepage_view urlpatterns = [ url(r'^$', my_homepage_view), #... How Django Processes a Request Before continuing to our second view function, let’s pause to learn a little more about how Django works. Specifically, when you view your “Hello world” message by visiting http://127.0.0.1:8000/hello/ in your Web browser, what does Django do behind the scenes? It all starts with the settings file. When you run python manage.py runserver, the script looks for a file called settings.py in the inner mysite directory. This file contains all sorts of con- figuration for this particular Django project, all in uppercase: TEMPLATE_DIRS, DATABASES, etc. The most important setting is called ROOT_URLCONF. ROOT_URLCONF tells Django which Python module should be used as the URLconf for this Web site. Remember when django-admin startproject created the files settings.py and urls.py? The auto-generated settings.py contains a ROOT_URLCONF setting that points to the auto-generated urls.py. Open the settings.py file and see for yourself; it should look like this: ROOT_URLCONF = 'mysite.urls' Chapter 2: Views and URLconfs 28 This corresponds to the file mysite/urls.py. When a request comes in for a particular URL - say, a request for /hello/ - Django loads the URLconf pointed to by the ROOT_URLCONF setting. Then it checks each of the URLpatterns in that URLconf, in order, comparing the requested URL with the patterns one at a time, until it finds one that matches. When it finds one that matches, it calls the view function associated with that pattern, passing it an HttpRequest object as the first parameter. (We’ll cover the specifics of HttpRequest later.) As we saw in our first view example, a view function must return an HttpResponse. Once it does this, Django does the rest, converting the Python object to a proper Web response with the appropriate HTTP headers and body (i.e., the content of the Web page). In summary: 1. A request comes in to /hello/. 2. Django determines the root URLconf by looking at the ROOT_URLCONF setting. 3. Django looks at all of the URLpatterns in the URLconf for the first one that matches /hello/. 4. If it finds a match, it calls the associated view function. 5. The view function returns an HttpResponse. 6. Django converts the HttpResponse to the proper HTTP response, which results in a Web page. You now know the basics of how to make Django-powered pages. It’s quite simple, really - just write view functions and map them to URLs via URLconfs. Your Second View: Dynamic Content Our “Hello world” view was instructive in demonstrating the basics of how Django works, but it wasn’t an example of a dynamic Web page, because the content of the page is always the same. Every time you view /hello/, you’ll see the same thing; it might as well be a static HTML file. For our second view, let’s create something more dynamic - a Web page that displays the current date and time. This is a nice, simple next step, because it doesn’t involve a database or any user input - just the output of your server’s Chapter 2: Views and URLconfs 29 internal clock. It’s only marginally more exciting than “Hello world,” but it’ll demonstrate a few new concepts. This view needs to do two things: calculate the current date and time, and return an HttpResponse containing that value. If you have experience with Python, you know that Python includes a datetime module for calculating dates. Here’s how to use it: >>> import datetime >>> now = datetime.datetime.now() >>> now datetime.datetime(2015, 7, 15, 18, 12, 39, 2731) >>> print (now) 2015-07-15 18:12:39.002731 That’s simple enough, and it has nothing to do with Django. It’s just Python code. (I want to emphasize that you should be aware of what code is “just Python” vs. code that is Django-specific. As you learn Django, I want you to be able to apply your knowledge to other Python projects that don’t necessarily use Django.) To make a Django view that displays the current date and time, we just need to hook this datetime.datetime.now() statement into a view and return an HttpResponse. Here’s what the updated views.py looks like: from django.http import HttpResponse import datetime def hello(request): return HttpResponse("Hello world") def current_datetime(request): now = datetime.datetime.now() html = "It is now %s." % now return HttpResponse(html) Let’s step through the changes we’ve made to views.py to accommodate the current_datetime view. We’ve added an import datetime to the top of the module, so we can calculate dates. The new current_datetime function calculates the current date and time, as a datetime.datetime object, and stores that as the local variable now. Chapter 2: Views and URLconfs 30 The second line of code within the view constructs an HTML response using Python’s “format-string” capability. The %s within the string is a placeholder, and the percent sign after the string means “Replace the %s in the preceding string with the value of the variable now.” The now variable is technically a datetime.datetime object, not a string, but the %s format character converts it to its string representation, which is something like "2015-07-15 18:12:39.002731". This will result in an HTML string such as "It is now 2015-07-15 18:12:39.002731.". Finally, the view returns an HttpResponse object that contains the gener- ated response - just as we did in hello. After adding that to views.py, add the URLpattern to urls.py to tell Django which URL should handle this view. Something like /time/ would make sense: from django.conf.urls import include, url from django.contrib import admin from mysite.views import hello, current_datetime urlpatterns = [ url(r'^admin/', include(admin.site.urls)), url(r'^hello/$', hello), url(r'^time/$', current_datetime), ] We’ve made two changes here. First, we imported the current_datetime func- tion at the top. Second, and more importantly, we added a URLpattern mapping the URL /time/ to that new view. Getting the hang of this? With the view written and URLconf updated, fire up the runserver and visit http://127.0.0.1:8000/time/ in your browser. You should see the current date and time. If you don’t see your local time, it is likely because the default time zone in your settings.py is set to 'UTC'. URLconfs and Loose Coupling Now’s a good time to highlight a key philosophy behind URLconfs and behind Django in general: the principle of loose coupling. Simply put, loose coupling is a software-development approach that values the importance of making pieces Chapter 2: Views and URLconfs 31 interchangeable. If two pieces of code are loosely coupled, then changes made to one of the pieces will have little or no effect on the other. Django’s URLconfs are a good example of this principle in practice. In a Django web application, the URL definitions and the view functions they call are loosely coupled; that is, the decision of what the URL should be for a given function, and the implementation of the function itself, reside in two separate places. For example, consider our current_datetime view. If we wanted to change the URL for the application - say, to move it from /time/ to /current-time/- we could make a quick change to the URLconf, without having to worry about the view itself. Similarly, if we wanted to change the view function - altering its logic somehow - we could do that without affecting the URL to which the function is bound. Furthermore, if we wanted to expose the current-date functionality at several URLs, we could easily take care of that by editing the URLconf, without having to touch the view code. In this example, our current_datetime is available at two URLs. It’s a contrived example, but this technique can come in handy: urlpatterns = [ url(r'^admin/', include(admin.site.urls)), url(r'^hello/$', hello), url(r'^time/$', current_datetime), url(r'^another-time-page/$', current_datetime), ] URLconfs and views are loose coupling in action. I’ll continue to point out examples of this important philosophy throughout the book. Your Third View: Dynamic URLs In our current_datetime view, the contents of the page - the current date/- time - were dynamic, but the URL (/time/) was static. In most dynamic Web applications though, a URL contains parameters that influence the output of the page. For example, an online bookstore might give each book its own URL, like /books/243/ and /books/81196/. Let’s create a third view that displays the current date and time offset by a certain number of hours. The goal is to craft a site in such a way that the page /time/plus/1/ displays the date/time one hour Chapter 2: Views and URLconfs 32 into the future, the page /time/plus/2/ displays the date/time two hours into the future, the page /time/plus/3/ displays the date/time three hours into the future, and so on. A novice might think to code a separate view function for each hour offset, which might result in a URLconf like this: urlpatterns = [ url(r'^time/$', current_datetime), url(r'^time/plus/1/$', one_hour_ahead), url(r'^time/plus/2/$', two_hours_ahead), url(r'^time/plus/3/$', three_hours_ahead), ] Clearly, this line of thought is flawed. Not only would this result in redundant view functions, but also the application is fundamentally limited to supporting only the predefined hour ranges - one, two or three hours. If we decided to create a page that displayed the time four hours into the future, we’d have to create a separate view and URLconf line for that, furthering the duplication. How, then do we design our application to handle arbitrary hour offsets? The key is to use wildcard URLpatterns. As I mentioned previously, a URLpattern is a regular expression; hence, we can use the regular expression pattern \d+ to match one or more digits: urlpatterns = [ #... url(r'^time/plus/\d+/$', hours_ahead), #... ] (I’m using the #... to imply there might be other URLpatterns that have been trimmed from this example.) This new URLpattern will match any URL such as /time/plus/2/, /time/plus/25/, or even /time/plus/100000000000/. Come to think of it, let’s limit it so that the maximum allowed offset is something reasonable. In this example, we will set a maximum 99 hours by only allowing either one- or two-digit numbers - and in regular expression syntax, that translates into \d{1,2}: Chapter 2: Views and URLconfs 33 url(r'^time/plus/\d{1,2}/$', hours_ahead), Now that we’ve designated a wildcard for the URL, we need a way of passing that wildcard data to the view function, so that we can use a single view function for any arbitrary hour offset. We do this by placing parentheses around the data in the URLpattern that we want to save. In the case of our example, we want to save whatever number was entered in the URL, so let’s put parentheses around the \d{1,2}, like this: url(r'^time/plus/(\d{1,2})/$', hours_ahead), If you’re familiar with regular expressions, you’ll be right at home here; we’re using parentheses to capture data from the matched text. The final URLconf, including our previous two views, looks like this: from django.conf.urls import include, url from django.contrib import admin from mysite.views import hello, current_datetime, hours_ahead urlpatterns = [ url(r'^admin/', include(admin.site.urls)), url(r'^hello/$', hello), url(r'^time/$', current_datetime), url(r'^time/plus/(\d{1,2})/$', hours_ahead), ] If you’re experienced in another Web development platform, you may be thinking, “Hey, let’s use a query string parameter!” - something like /time/plus?hours=3, in which the hours would be designated by the hours parameter in the URL’s query string (the part after the ‘?’). You can do that with Django (and I’ll tell you how in Chapter 7), but one of Django’s core philosophies is that URLs should be beautiful. The URL /time/plus/3/ is far cleaner, simpler, more readable, easier to recite to somebody aloud and... just plain prettier than its query string counterpart. Pretty URLs are a characteristic of a quality Web application. Django’s URLconf system encourages pretty URLs by making it easier to use pretty URLs than not to. With that taken care of, let’s write the hours_ahead view. hours_ahead is very similar to the current_datetime view we wrote earlier, with a key difference: it takes an extra argument, the number of hours of offset. Here’s the view code: Chapter 2: Views and URLconfs 34 from django.http import Http404, HttpResponse import datetime def hours_ahead(request, offset): try: offset = int(offset) except ValueError: raise Http404() dt = datetime.datetime.now() + datetime.timedelta(hours=offset) html = "In %s hour(s), it will be %s. " % (offset, dt) return HttpResponse(html) Let’s take a closer look at this code. The view function, hours_ahead, takes two parameters: request and offset: request is an HttpRequest object, just as in hello and current_datetime. I’ll say it again: each view always takes an HttpRequest object as its first parameter. offset is the string captured by the parentheses in the URLpattern. For example, if the requested URL were /time/plus/3/, then offset would be the string ‘3’. If the requested URL were /time/plus/21/, then offset would be the string ‘21’. Note that captured values will always be Unicode objects, not integers, even if the string is composed of only digits, such as ‘21’. I decided to call the variable offset, but you can call it whatever you’d like, as long as it’s a valid Python identifier. The variable name doesn’t matter; all that matters is that it’s the second argument to the function, after request. (It’s also possible to use keyword, rather than positional, arguments in an URLconf. I cover that in Chapter 7.) The first thing we do within the function is call int() on offset. This converts the Unicode string value to an integer. Note that Python will raise a ValueError exception if you call int() on a value that cannot be converted to an integer, such as the string “foo”. In this example, if we encounter the ValueError, we raise the exception django.http.Http404, which, as you can imagine, results in a 404 “Page not found” error. Chapter 2: Views and URLconfs 35 Astute readers will wonder: how could we ever reach the ValueError case, anyway, given that the regular expression in our URLpattern - (\d{1,2}) - captures only digits, and therefore offset will only ever be a string composed of digits? The answer is, we won’t, because the URLpattern provides a modest but useful level of input validation, but we still check for the ValueError in case this view function ever gets called in some other way. It’s good practice to implement view functions such that they don’t make any assumptions about their parameters. Loose coupling, remember? In the next line of the function, we calculate the current date/time and add the appropriate number of hours. We’ve already seen datetime.datetime.now() from the current_datetime view; the new concept here is that you can perform date/time arithmetic by creating a datetime.timedelta object and adding to a datetime.datetime object. Our result is stored in the variable dt. This line also shows why we called int() on offset - the datetime.timedelta function requires the hours parameter to be an integer. Next, we construct the HTML output of this view function, just as we did in current_datetime. A small difference in this line from the previous line is that it uses Python’s format-string capability with two values, not just one. Hence, there are two %s symbols in the string and a tuple of values to insert: (offset, dt). Finally, we return an HttpResponse of the HTML. With that view function and URLconf written, start the Django development server (if it’s not already running), and visit http://127.0.0.1:8000/time/plus/3/ to verify it works. Then try http://127.0.0.1:8000/time/plus/5/. Then http://127.0.0.1:8000/time/plus/24/. Finally, visit http://127.0.0.1:8000/time/plus/100/ to verify that the pattern in your URLconf only accepts one- or two-digit numbers; Django should display a “Page not found” error in this case, just as we saw in the section “A Quick Note About 404 Errors” earlier. The URL http://127.0.0.1:8000/time/plus/ (with no hour designation) should also throw a 404. Chapter 2: Views and URLconfs 36 Django’s Pretty Error Pages Take a moment to admire the fine Web application we’ve made so far... now let’s break it! Let’s deliberately introduce a Python error into our views.py file by commenting out the offset = int(offset) lines in the hours_ahead view: def hours_ahead(request, offset): # try: # offset = int(offset) # except ValueError: # raise Http404() dt = datetime.datetime.now() + datetime.timedelta(hours=offset) html = "In %s hour(s), it will be %s. " % (offset, dt) return HttpResponse(html) Load up the development server and navigate to /time/plus/3/. You’ll see an error page with a significant amount of information, including a TypeError message displayed at the very top: "unsupported type for timedelta hours component: str" (Figure 2-3). Figure 2-3: Django’s error page What happened? Well, the datetime.timedelta function expects the hours parameter to be an integer, and we commented out the bit of code that converted offset to an integer. That caused datetime.timedelta to raise the Chapter 2: Views and URLconfs 37 TypeError. It’s the typical kind of small bug that every programmer runs into at some point. The point of this example was to demonstrate Django’s error pages. Take some time to explore the error page and get to know the various bits of information it gives you. Here are some things to notice: At the top of the page, you get the key information about the exception: the type of exception, any parameters to the exception (the "unsupported type" message in this case), the file in which the exception was raised, and the offending line number. Under the key exception information, the page displays the full Python traceback for this exception. This is similar to the standard traceback you get in Python’s command-line interpreter, except it’s more interactive. For each level (“frame”) in the stack, Django displays the name of the file, the function/method name, the line number, and the source code of that line. Click the line of source code (in dark gray), and you’ll see several lines from before and after the erroneous line, to give you context. Click “Local vars” under any frame in the stack to view a table of all local variables and their values, in that frame, at the exact point in the code at which the exception was raised. This debugging information can be a great help. Note the “Switch to copy-and-paste view” text under the “Traceback” header. Click those words, and the traceback will switch to an alternate version that can be easily copied and pasted. Use this when you want to share your exception traceback with others to get technical support - such as the kind folks in the Django IRC chat room or on the Django users mailing list. Underneath, the “Share this traceback on a public Web site” button will do this work for you in just one click. Click it to post the traceback to dpaste, where you’ll get a distinct URL that you can share with other people. Next, the “Request information” section includes a wealth of information about the incoming Web request that spawned the error: GET and POST information, cookie values, and meta information, such as CGI headers. Appendix F has a complete reference of all the information a request object contains. Below the “Request information” section, the “Settings” section lists all of the settings for this particular Django installation. All the available settings Chapter 2: Views and URLconfs 38 are covered in detail in Appendix D. The Django error page is capable of displaying more information in certain special cases, such as the case of template syntax errors. We’ll get to those later, when we discuss the Django template system. For now, uncomment the offset = int(offset) lines to get the view function working properly again. The Django error page is also really useful if you are the type of programmer who likes to debug with the help of carefully placed print statements. At any point in your view, temporarily insert an assert False to trigger the error page. Then, you can view the local variables and state of the program. Here’s an example, using the hours_ahead view: def hours_ahead(request, offset): try: offset = int(offset) except ValueError: raise Http404() dt = datetime.datetime.now() + datetime.timedelta(hours=offset) assert False html = "In %s hour(s), it will be %s. " % (offset, dt) return HttpResponse(html) Finally, it’s obvious that much of this information is sensitive - it exposes the innards of your Python code and Django configuration - and it would be foolish to show this information on the public Internet. A malicious person could use it to attempt to reverse-engineer your Web application and do nasty things. For that reason, the Django error page is only displayed when your Django project is in debug mode. I’ll explain how to deactivate debug mode in Chapter 13. For now, just know that every Django project is in debug mode automatically when you start it. (Sound familiar? The “Page not found” errors, described earlier in this chapter, work the same way.) What’s Next? So far, we’ve been writing our view functions with HTML hard-coded directly in the Python code. I’ve done that to keep things simple while I demonstrated Chapter 2: Views and URLconfs 39 core concepts, but in the real world, this is nearly always a bad idea. Django ships with a simple yet powerful template engine that allows you to separate the design of the page from the underlying code. We’ll dive into Django’s template engine in the next chapter. Chapter 3: Templates In the previous chapter, you may have noticed something peculiar in how we returned the text in our example views. Namely, the HTML was hard-coded directly in our Python code, like this: def current_datetime(request): now = datetime.datetime.now() html = "It is now %s." % now return HttpResponse(html) Although this technique was convenient for the purpose of explaining how views work, it’s not a good idea to hard-code HTML directly into your views. Here’s why: Any change to the design of the page requires a change to the Python code. The design of a site tends to change far more frequently than the underlying Python code, so it would be convenient if the design could change without needing to modify the Python code. This is only a very simple example. A common webpage template has hundreds of lines of HTML and scripts. Untangling and troubleshooting program code from this mess is a nightmare (cough-PHP-cough). Writing Python code and designing HTML are two different disciplines, and most professional Web development environments split these re- sponsibilities between separate people (or even separate departments). Designers and HTML/CSS coders shouldn’t be required to edit Python code to get their job done. It’s most efficient if programmers can work on Python code and designers can work on templates at the same time, rather than one person waiting for the other to finish editing a single file that contains both Python and HTML. For these reasons, it’s much cleaner and more maintainable to separate the design of the page from the Python code itself. We can do this with Django’s template system, which we discuss in this chapter. Chapter 3: Templates 41 Template System Basics A Django template is a string of text that is intended to separate the presenta- tion of a document from its data. A template defines placeholders and various bits of basic logic (template tags) that regulate how the document should be displayed. Usually, templates are used for producing HTML, but Django templates are equally capable of generating any text-based format. Philosophy behind Django’s templates If you have a background in programming, or if you’re used to languages which mix programming code directly into HTML, you’ll want to bear in mind that the Django template system is not simply Python embedded into HTML. This is by design: the template system is meant to express presenta- tion, not program logic. Let’s start with a simple example template. This Django template describes an HTML page that thanks a person for placing an order with a company. Think of it as a form letter: Ordering notice Ordering notice Dear {{ person_name }}, Thanks for placing an order from {{ company }}. It's scheduled to ship on {{ s\ hip_date|date:"F j, Y" }}. Here are the items you've ordered: {% for item in item_list %} {{ item }}{% endfor %} Chapter 3: Templates 42 {% if ordered_warranty %} Your warranty information will be included in the packaging. {% else %} You didn't order a warranty, so you're on your own when the products inevitably stop working. {% endif %} Sincerely,{{ company }} This template is basic HTML with some variables and template tags thrown in. Let’s step through it: Any text surrounded by a pair of braces (e.g., {{ person_name }}) is a variable. This means “insert the value of the variable with the given name.” How do we specify the values of the variables? We’ll get to that in a moment. Any text that’s surrounded by curly braces and percent signs (e.g., {% if ordered_warranty %}) is a template tag. The definition of a tag is quite broad: a tag just tells the template system to “do something”. This example template contains a for tag ({% for item in item_list %}) and an if tag ({% if ordered_warranty %}). A for tag works very much like a for statement in Python, letting you loop over each item in a sequence. An if tag, as you may expect, acts as a logical “if” statement. In this particular case, the tag checks whether the value of the ordered_warranty variable evaluates to True. If it does, the template system will display everything between the {% if ordered_warranty %} and {% else %}. If not, the template system will display everything between {% else %} and{% endif %}. Note that the {% else %} is optional. Finally, the second paragraph of this template contains an example of a filter, which is the most convenient way to alter the formatting of a variable. In this example, {{ ship_date|date:"F j, Y" }}, we’re passing the ship_date variable to the date filter, giving the date filter the argument "F j, Y". The date filter formats dates in a given format, as specified Chapter 3: Templates 43 by that argument. Filters are attached using a pipe character (|), as a reference to Unix pipes. Each Django template has access to several built- in tags and filters, many of which are discussed in the sections that follow. Appendix E contains the full list of tags and filters, and it’s a good idea to familiarize yourself with that list so you know what’s possible. It’s also possible to create your own filters and tags; we’ll cover that in Chapter 8. Using the Template System A Django project can be configured with one or several template engines (or even zero if you don’t use templates). Django ships with a built-in backend for its own template system - the Django Template Language (DTL). Django 1.8 also includes support for the popular alternative Jinja29. If you don’t have a pressing reason to choose another backend, you should use the DTL - especially if you’re writing a pluggable application and you intend to distribute templates. Django’s contrib apps that include templates, like django.contrib.admin, use the DTL. All of the examples in this chapter will use the DTL. For more advanced template topics, including configuring third-party template engines, see Chapter 8. Before we go about implementing Django templates in your view, lets first dig inside the DTL a little so you can see how it works. Here is the most basic way you can use Django’s template system in Python code: 1. Create a Template object by providing the raw template code as a string. 2. Call the render() method of the Template object with a given set of variables (the context). This returns a fully rendered template as a string, with all of the variables and template tags evaluated according to the context. In code, here’s what that looks like: 9 http://jinja.pocoo.org/ Chapter 3: Templates 44 >>> from django import template >>> t = template.Template('My name is {{ name }}.') >>> c = template.Context({'name': 'Nige'}) >>> print (t.render(c)) My name is Nige. >>> c = template.Context({'name': 'Barry'}) >>> print (t.render(c)) My name is Barry. The following sections describe each step in much more detail. Creating Template Objects The easiest way to create a Template object is to instantiate it directly. The Template class lives in the django.template module, and the constructor takes one argument, the raw template code. Let’s dip into the Python interactive interpreter to see how this works in code. From the mysite project directory you created in Chapter 1, type python manage.py shell to start the interactive interpreter. Let’s go through some template system basics: >>> from django.template import Template >>> t = Template('My name is {{ name }}.') >>> print (t) If you’re following along interactively, you’ll see something like this: That 0x030396B0 will be different every time, and it isn’t relevant; it’s a Python thing (the Python “identity” of the Template object, if you must know). When you create a Template object, the template system compiles the raw template code into an internal, optimized form, ready for rendering. But if your template code includes any syntax errors, the call to Template() will cause a TemplateSyntaxError exception: Chapter 3: Templates 45 >>> from django.template import Template >>> t = Template('{% notatag %}') Traceback (most recent call last): File "", line 1, in ?... django.template.base.TemplateSyntaxError: Invalid block tag: 'notatag' The term “block tag” here refers to {% notatag %}. “Block tag” and “template tag” are synonymous. The system raises a TemplateSyntaxError exception for any of the following cases: Invalid tags Invalid arguments to valid tags Invalid filters Invalid arguments to valid filters Invalid template syntax Unclosed tags (for tags that require closing tags) Rendering a Template Once you have a Template object, you can pass it data by giving it a context. A context is simply a set of template variable names and their associated values. A template uses this to populate its variables and evaluate its tags. A context is represented in Django by the Context class, which lives in the django.template module. Its constructor takes one optional argument: a dictionary mapping variable names to variable values. Call the Template object’s render() method with the context to “fill” the template: >>> from django.template import Context, Template >>> t = Template('My name is {{ name }}.') >>> c = Context({'name': 'Stephane'}) >>> t.render(c) 'My name is Stephane.' Chapter 3: Templates 46 A special Python prompt If you’ve used Python before, you may be wondering why we’re running python manage.py shell instead of just python (or python3). Both commands will start the interactive interpreter, but the manage.py shell command has one key difference: before starting the interpreter, it tells Django which settings file to use. Many parts of Django, including the template system, rely on your settings, and you won’t be able to use them unless the framework knows which settings to use. If you’re curious, here’s how it works behind the scenes. Django looks for an environment variable called DJANGO_SETTINGS_MODULE, which should be set to the import path of your settings.py. For example, DJANGO_SETTINGS_MODULE might be set to 'mysite.settings', assuming mysite is on