Permalink
Browse files

Restored *2.0* version of the book, not 1.0!

Oops. Apparently I ported over the 1.0 version, covering 0.96, not the
2.0 version, covering 1.0. Whoops. It's all good now. Nothing to see
here. Move along.
  • Loading branch information...
1 parent 66248c8 commit d40cfe73fd065bf010471910eb9cd45c31be7c6e @jacobian jacobian committed Sep 25, 2012
Showing with 9,807 additions and 8,820 deletions.
  1. +910 −344 appendixA.rst
  2. +991 −1,350 appendixB.rst
  3. +699 −1,284 appendixC.rst
  4. +662 −863 appendixD.rst
  5. +1,105 −648 appendixE.rst
  6. +498 −923 appendixF.rst
  7. +479 −463 appendixG.rst
  8. +0 −536 appendixH.rst
  9. +147 −129 chapter01.rst
  10. +348 −160 chapter02.rst
  11. +619 −417 chapter03.rst
  12. +474 −333 chapter04.rst
  13. +551 −491 chapter05.rst
  14. +886 −324 chapter06.rst
  15. +1,113 −480 chapter07.rst
  16. +325 −75 chapter08.rst
Sorry, we could not display the entire diff because it was too big.
View
1,254 appendixA.rst
@@ -1,389 +1,955 @@
-========================
-Appendix A: Case Studies
-========================
-
-To help answer questions about how Django works in the "real world," we spoke
-with (well, emailed) a handful of people who have complete, deployed Django
-sites under their belts. Most of this appendix is in their words, which have
-been lightly edited for clarity.
-
-Cast of Characters
-==================
-
-Let's meet our cast and their projects.
-
- * *Ned Batchelder* is the lead engineer at Tabblo.com. Tabblo started life as
- a storytelling tool built around photo sharing, but it was recently bought
- by Hewlett-Packard for more wide-reaching purposes:
-
- HP saw real value in our style of web development, and in the way we
- bridged the virtual and physical worlds. They acquired us so that we
- could bring that technology to other sites on the Web. Tabblo.com is
- still a great storytelling site, but now we are also working to
- componentize and rehost the most interesting pieces of our technology.
-
- * *Johannes Beigel* is a lead developer at Brainbot Technologies AG.
- Brainbot's major public-facing Django site is http://pediapress.com/,
- where you can order printed versions of Wikipedia articles. Johannes's team
- is currently working on an enterprise-class knowledge-management program
- known as Brainfiler.
-
- Johannes tells us that Brainfiler
-
- [...] is a software solution to manage, search for, categorize, and share
- information from distributed information sources. It's built for
- enterprise usage for both the intranet and the Internet and is highly
- scalable and customizable. The development of the core concepts and
- components started in 2001. Just recently we have
- redesigned/reimplemented the application server and Web front-end, which
- is [now] based on Django.
-
- * *David Cramer* is the lead developer at Curse, Inc. He develops
- Curse.com, a gaming site devoted to massively multiplayer online games
- like World of Warcraft, Ultima Online, and others.
-
- Curse.com is one of the largest deployed Django sites on the Internet:
-
- We do roughly 60-90 million page views in an average month, and we have
- peaked at over 130 million page views [in a month] using Django. We are a
- very dynamic and user-centric Web site for online gamers, specifically
- massively multiplayer games, and are one of the largest Web sites
- globally for World of Warcraft. Our Web site was established in early
- 2005, and since late 2006 we have been expanding our reach into games
- beyond World of Warcraft.
-
- * *Christian Hammond* is a senior engineer at VMware (a leading developer
- of virtualization software). He's also the lead developer of Review Board
- (http://www.review-board.org/), a Web-based code review system. Review
- Board began life as an internal VMware project, but is now open source:
-
- In late 2006, David Trowbridge and I were discussing the process we used
- at VMware for handling code reviews. Before people committed code to the
- source repository, they were supposed to send out a diff of the change
- to a mailing list and get it reviewed. It was all handled over email,
- and as such, it became hard to keep track of reviews requiring your
- attention. We began to discuss potential solutions for this problem.
-
- Rather than writing down my ideas, I put them into code. Before long,
- Review Board was born. Review Board helps developers, contributors, and
- reviewers to keep track of the code that's out for review and to better
- communicate with each other. Rather than vaguely referencing some part
- of the code in an email, the reviewer is able to comment directly on
- the code. The code, along with the comments, will then appear in the
- review, giving the developer enough context to work with to quickly make
- the necessary changes.
-
- Review Board grew quickly at VMware. Much faster than expected,
- actually. Within a few short weeks, we had ten teams using Review Board.
- However, this project is not internal to VMware. It was decided day one
- that this should be open source and be made available for any company or
- project to use.
-
- We made an open source announcement and put a site together, which is
- available at http://www.review-board.org/. The response to our public
- announcement was as impressive as our internal VMware announcement.
- Before long, our demo server reached over 600 users, and people began to
- contribute back to the project.
-
- Review Board isn't the only code review tool on the market, but it is
- the first we have seen that is open source and has the extensive feature
- set we've worked to build into it. We hope this will in time benefit
- many open source and commercial projects.
-
-Why Django?
-===========
+======================================
+Appendix A: Model Definition Reference
+======================================
-We asked each developer why he decided to use Django, what other options
-were considered, and how the decision to use Django was ultimately made.
+Chapter 5 explains the basics of defining models, and we use them throughout
+the rest of the book. There is, however, a *huge* range of model options
+available not covered elsewhere. This appendix explains each possible model
+definition option.
-*Ned Batchelder*:
-
- Before I joined Tabblo, Antonio Rodriguez (Tabblo's founder/CTO) did an evaluation
- of Rails and Django, and found that both provided a great
- quick-out-of-the-blocks rapid development environment. In comparing the
- two, he found that Django had a greater technical depth that would make it
- easier to build a robust, scalable site. Also, Django's Python foundation
- meant that we'd have all the richness of the Python ecosystem to support
- our work. This has definitely been proven out as we've built Tabblo.
-
-*Johannes Beigel*:
+Note that although these APIs are considered stable, the Django developers
+consistently add new shortcuts and conveniences to the model definition. It's a
+good idea to always check the latest documentation online at
+http://docs.djangoproject.com/.
- As we have been coding in Python for many years now, and quickly started
- using the Twisted framework, Nevow was the most "natural" solution for our
- Web application stuff. But we soon realized that -- despite the perfect
- Twisted integration -- many things were getting a little cumbersome and
- got in the way of our agile development process.
-
- After some Internet research it quickly became clear that Django was the
- most promising Web development framework for our requirements.
-
- The trigger that led us to Django was its template syntax, but we soon
- appreciated all the other features that are included, and so Django was
- pretty much a fast-selling item.
-
- After doing a few years of parallel development and deployment (Nevow is
- still in use for some projects on customer sites), we came to the
- conclusion that Django is a lot less cumbersome, results in code that is
- much better to maintain, and is more fun to work with.
-
-*David Cramer*:
+Fields
+======
- I heard about Django in the summer of 2006, about the time we were getting
- ready to do an overhaul of Curse, and we did some research on it. We were
- all very impressed at what it could do, and where it could save time for
- us. We talked it over, decided on Django, and began writing the third
- revision to the Web site almost immediately.
-
-*Christian Hammond*:
+The most important part of a model -- and the only required part of a model --
+is the list of database fields it defines.
+
+.. admonition:: Field Name Restrictions
+
+ Django places only two restrictions on model field names:
+
+ 1. A field name cannot be a Python reserved word, because that would result
+ in a Python syntax error. For example::
+
+ class Example(models.Model):
+ pass = models.IntegerField() # 'pass' is a reserved word!
+
+ 2. A field name cannot contain more than one underscore in a row, due to
+ the way Django's query lookup syntax works. For example::
- I had toyed around with Django on a couple of small projects and had been
- very impressed with it. It's based on Python, which I had become a big
- fan of, and it made it easy not only to develop Web sites and Web apps, but
- also to keep them organized and maintainable. This was always tricky in PHP and
- Perl. Based on past experiences, going with Django was a no-brainer.
+ class Example(models.Model):
+ foo__bar = models.IntegerField() # 'foo__bar' has two underscores!
+
+ These limitations can be worked around, though, because your field name
+ doesn't necessarily have to match your database column name. See
+ "db_column", below.
+
+ SQL reserved words, such as ``join``, ``where``, or ``select``, *are* allowed
+ as model field names, because Django escapes all database table names and
+ column names in every underlying SQL query. It uses the quoting syntax of your
+ particular database engine.
+
+Each field in your model should be an instance of the appropriate ``Field``
+class. Django uses the field class types to determine a few things:
+
+ * The database column type (e.g., ``INTEGER``, ``VARCHAR``).
-Getting Started
-===============
+ * The widget to use in Django's forms and admin site, if you care to use it
+ (e.g., ``<input type="text">``, ``<select>``).
-Since Django's a relatively new tool, there aren't that many experienced
-Django developers out there. We asked our "panel" how they got their team up
-to speed on Django and for any tips they wanted to share with new Django
-developers.
+ * The minimal validation requirements, which are used in Django's admin
+ interface and by forms.
+
+A complete list of field classes follows, sorted alphabetically. Note that
+relationship fields (``ForeignKey``, etc.) are handled in the next section.
-*Johannes Beigel*:
+AutoField
+---------
- After coding mostly in C++ and Perl, we switched to Python and continued
- using C++ for the computationally intensive code.
+An ``IntegerField`` that automatically increments according to available IDs.
+You usually won't need to use this directly; a primary key field will
+automatically be added to your model if you don't specify otherwise.
- [We learned Django by] working through the tutorial, browsing the
- documentation to get an idea of what's possible (it's easy to miss many
- features by just doing the tutorial), and trying to understand the basic
- concepts behind middleware, request objects, database models, template
- tags, custom filters, forms, authorization, localization... Then [we
- could] take a deeper look at those topics when [we] actually needed them.
+BooleanField
+------------
-*David Cramer*:
+A true/false field.
- The Web site documentation is great. Stick with it.
+.. admonition:: MySQL users...
-*Christian Hammond*:
+ A boolean field in MySQL is stored as a ``TINYINT`` column with a value of
+ either 0 or 1 (most databases have a proper ``BOOLEAN`` type instead). So,
+ for MySQL, only, when a ``BooleanField`` is retrieved from the database
+ and stored on a model attribute, it will have the values 1 or 0, rather
+ than ``True`` or ``False``. Normally, this shouldn't be a problem, since
+ Python guarantees that ``1 == True`` and ``0 == False`` are both true.
+ Just be careful if you're writing something like ``obj is True`` when
+ ``obj`` is a value from a boolean attribute on a model. If that model was
+ constructed using the ``mysql`` backend, the "``is``" test will fail.
+ Prefer an equality test (using "``==``") in cases like this.
- David and I both had prior experience with Django, though it was limited.
- We had learned a lot through our development of Review Board. I would
- advise new users to read through the well-written Django documentation and
- [the book you're reading now], both of which have been invaluable to us.
+CharField
+---------
-We didn't have to bribe Christian to get that quote -- promise!
+A string field, for small- to large-sized strings.
-Porting Existing Code
-=====================
+For very large amounts of text, use ``TextField``.
-Although Review Board and Tabblo were ground-up development, the other sites
-were ported from existing code. We were interested in hearing how that process
-went.
+``CharField`` has one extra required argument: ``max_length``. This is the
+maximum length (in characters) of the field. The ``max_length`` is enforced
+at the database level and in Django's validation.
-*Johannes Beigel*:
+CommaSeparatedIntegerField
+--------------------------
- We started to "port" the site from Nevow, but we soon realized that we'd
- like to change so many conceptual things (both in the UI part and in the
- application server part) that we started from scratch and used the former
- code merely as a reference.
+A field of integers separated by commas. As in ``CharField``, the
+``max_length`` argument is required.
-*David Cramer*:
+DateField
+---------
- The previous site was written in PHP. Going from PHP to Python was great
- programmatically. The only downfall is you have to be a lot more careful
- with memory management [since Django processes stay around a lot longer
- than PHP processes (which are single cycle)].
-
-How Did It Go?
-==============
-
-Now for the million-dollar question: How did Django treat you? We were especially
-interested in hearing where Django fell down -- it's important to know where
-your tools are weak *before* you run into roadblocks.
-
-*Ned Batchelder*:
-
- Django has really enabled us to experiment with our Web site's
- functionality. Both as a startup heat-seeking customers and businesses,
- and now as a part of HP working with a number of partners, we've had to be
- very nimble when it comes to adapting the software to new demands. The
- separation of functionality into models, views, and controllers has given
- us modularity so we can appropriately choose where to extend and modify.
- The underlying Python environment gives us the opportunity to make use of
- existing libraries to solve problems without reinventing the wheel. PIL, PDFlib,
- ZSI, JSmin, and BeautifulSoup are just a handful of the libraries we've
- pulled in to do some heavy lifting for us.
-
- The most difficult part of our Django use has been the relationship of
- memory objects to database objects, in a few ways. First, Django's ORM
- does not ensure that two references to the same database record are the
- same Python object, so you can get into situations where two parts of the
- code are both trying to modify the same record, and one of the copies is
- stale. Second, the Django development model encourages you to base your
- data objects on database objects. We've found over time more and more uses
- for data objects that are not tied to the database, and we've had to
- migrate away from assuming that data is stored in the database.
-
- For a large, long-lived code base, it definitely makes sense to spend time
- up front anticipating the ways your data will be stored and accessed, and
- building some infrastructure to support those ways.
-
- We've also added our own database migration facility so that developers
- don't have to apply SQL patches to keep their database schemas current.
- Developers who change the schema write a Python function to update the
- database, and these are applied automatically when the server is started.
-
-*Johannes Beigel*:
-
- We consider Django as a very successful platform that perfectly fits
- in the Pythonic way of thinking. Almost everything just worked as
- intended.
-
- One thing that needed a bit of work in our current project was tweaking
- the global ``settings.py`` file and directory structure/configuration
- (for apps, templates, locale data, etc.), because we implemented a highly
- modular and configurable system, where all Django views are actually
- methods of some class instances. But with the omnipotence of dynamic
- Python code, that was still possible.
-
-*David Cramer*:
-
- We managed to push out large database applications in a weekend. This
- would have taken one to two weeks to do on the previous Web site, in PHP. Django
- has shined exactly where we wanted it to.
-
- Now, while Django is a great platform, it can't go without saying that it's
- not built specific to everyone's needs. Upon the initial launch of the
- Django Web site, we had our highest traffic month of the year, and we
- weren't able to keep up. Over the next few months we tweaked bits and
- pieces, mostly hardware and the software serving Django requests. [This
- included modification of our] hardware configuration, optimization of
- Django, [and tuning] the software we were using to serve the requests
- (which, at the time, was lighttpd and FastCGI).
-
- In May of 2007, Blizzard (the creators of World of Warcraft) released
- another quite large patch, as they had done in December when we first
- launched Django. The first thing going through our heads was, "Hey, we
- nearly held up in December, this is nowhere near as big, we should be
- fine." We lasted about 12 hours before the servers started to feel the
- heat. The question was raised again: was Django really the best solution
- for what we want to accomplish?
-
- Thanks to a lot of great support from the community, and a late night, we
- managed to implement several "hot-fixes" to the Web site during those few
- days. The changes (which hopefully have been rolled back into Django by
- the time this book is released) managed to completely reassure everyone
- that while not everyone needs to be able to do 300 Web requests per
- second, the people who do, can, with Django.
-
-*Christian Hammond*:
-
- Django allowed us to build Review Board fairly quickly by forcing us to
- stay organized through its URL, view, and template separations, and by
- providing useful built-in components, such as the authentication app,
- built-in caching, and the database abstraction. Most of this has worked
- really well for us.
-
- Being a dynamic [Web application], we've had to write a lot of JavaScript
- code. This is an area that Django hasn't really helped us with so far.
- Django's templates, template tags, filters, and forms support are great, but
- aren't easily usable from JavaScript code. There are times when we would
- want to use a particular template or filter but had no way of using it
- from JavaScript. I would personally like to see some creative solutions
- for this incorporated into Django.
-
-Team Structure
-==============
+A date, represented in Python by a ``datetime.date`` instance.
+
+DateTimeField
+-------------
+
+A date and time, represented in Python by a ``datetime.datetime`` instance.
+
+DecimalField
+------------
+
+A fixed-precision decimal number, represented in Python by a
+``decimal.Decimal`` instance. Has two **required** arguments:
+
+``max_digits``
+
+ The maximum number of digits allowed in the number
+
+``decimal_places``
+
+ The number of decimal places to store with the number
+
+For example, to store numbers up to 999 with a resolution of 2 decimal places,
+you'd use::
+
+ models.DecimalField(..., max_digits=5, decimal_places=2)
+
+And to store numbers up to approximately one billion with a resolution of 10
+decimal places::
+
+ models.DecimalField(..., max_digits=19, decimal_places=10)
+
+When assigning to a ``DecimalField``, use either a ``decimal.Decimal`` object
+or a string -- not a Python float.
+
+EmailField
+----------
+
+A ``CharField`` that checks that the value is a valid e-mail address.
+
+FileField
+---------
+
+A file-upload field.
+
+.. note::
+ The ``primary_key`` and ``unique`` arguments are not supported, and will
+ raise a ``TypeError`` if used.
+
+Has one **required** argument:
+
+``upload_to``
+
+ A local filesystem path that will be appended to your ``MEDIA_ROOT``
+ setting to determine the value of the ``django.core.files.File.url``
+ attribute.
+
+ This path may contain "strftime formatting" (see the Python docs for the
+ ``time`` standard library module), which will be replaced using the
+ date/time of the file upload (so that uploaded files don't fill up the given
+ directory).
+
+ This may also be a callable, such as a function, which will be called to
+ obtain the upload path, including the filename. This callable must be able
+ to accept two arguments, and return a Unix-style path (with forward slashes)
+ to be passed along to the storage system. The two arguments that will be
+ passed are:
+
+ ====================== ===============================================
+ Argument Description
+ ====================== ===============================================
+ ``instance`` An instance of the model where the
+ ``FileField`` is defined. More specifically,
+ this is the particular instance where the
+ current file is being attached.
+
+ In most cases, this object will not have been
+ saved to the database yet, so if it uses the
+ default ``AutoField``, *it might not yet have a
+ value for its primary key field*.
+
+ ``filename`` The filename that was originally given to the
+ file. This may or may not be taken into account
+ when determining the final destination path.
+ ====================== ===============================================
+
+Also has one optional argument:
+
+``storage``
+
+ Optional. A storage object, which handles the storage and retrieval of your
+ files.
+
+Using a ``FileField`` or an ``ImageField`` (see below) in a model
+takes a few steps:
+
+ 1. In your settings file, you'll need to define ``MEDIA_ROOT`` as the
+ full path to a directory where you'd like Django to store uploaded files.
+ (For performance, these files are not stored in the database.) Define
+ ``MEDIA_URL`` as the base public URL of that directory. Make sure
+ that this directory is writable by the Web server's user account.
+
+ 2. Add the ``FileField`` or ``ImageField`` to your model, making
+ sure to define the ``upload_to`` option to tell Django
+ to which subdirectory of ``MEDIA_ROOT`` it should upload files.
+
+ 3. All that will be stored in your database is a path to the file
+ (relative to ``MEDIA_ROOT``). You'll most likely want to use the
+ convenience ``url`` function provided by
+ Django. For example, if your ``ImageField`` is called ``mug_shot``,
+ you can get the absolute URL to your image in a template with
+ ``{{ object.mug_shot.url }}``.
+
+For example, say your ``MEDIA_ROOT`` is set to ``'/home/media'``, and
+``upload_to`` is set to ``'photos/%Y/%m/%d'``. The ``'%Y/%m/%d'``
+part of ``upload_to`` is strftime formatting; ``'%Y'`` is the
+four-digit year, ``'%m'`` is the two-digit month and ``'%d'`` is the two-digit
+day. If you upload a file on Jan. 15, 2007, it will be saved in the directory
+``/home/media/photos/2007/01/15``.
+
+If you want to retrieve the upload file's on-disk filename, or a URL that refers
+to that file, or the file's size, you can use the
+``name``, ``url`` and ``size`` attributes.
+
+Note that whenever you deal with uploaded files, you should pay close attention
+to where you're uploading them and what type of files they are, to avoid
+security holes. *Validate all uploaded files* so that you're sure the files are
+what you think they are. For example, if you blindly let somebody upload files,
+without validation, to a directory that's within your Web server's document
+root, then somebody could upload a CGI or PHP script and execute that script by
+visiting its URL on your site. Don't allow that.
+
+By default, ``FileField`` instances are
+created as ``varchar(100)`` columns in your database. As with other fields, you
+can change the maximum length using the ``max_length`` argument.
+
+FilePathField
+-------------
+
+A ``CharField`` whose choices are limited to the filenames in a certain
+directory on the filesystem. Has three special arguments, of which the first is
+**required**:
+
+``path``
+
+ Required. The absolute filesystem path to a directory from which this
+ ``FilePathField`` should get its choices. Example: ``"/home/images"``.
+
+``match``
+
+ Optional. A regular expression, as a string, that ``FilePathField``
+ will use to filter filenames. Note that the regex will be applied to the
+ base filename, not the full path. Example: ``"foo.*\.txt$"``, which will
+ match a file called ``foo23.txt`` but not ``bar.txt`` or ``foo23.gif``.
+
+``recursive``
+
+ Optional. Either ``True`` or ``False``. Default is ``False``. Specifies
+ whether all subdirectories of ``path`` should be included.
+
+Of course, these arguments can be used together.
+
+The one potential gotcha is that ``match`` applies to the
+base filename, not the full path. So, this example::
+
+ FilePathField(path="/home/images", match="foo.*", recursive=True)
+
+...will match ``/home/images/bar/foo.gif`` but not ``/home/images/foo/bar.gif``
+because the ``match`` applies to the base filename
+(``foo.gif`` and ``bar.gif``).
+
+By default, ``FilePathField`` instances are
+created as ``varchar(100)`` columns in your database. As with other fields, you
+can change the maximum length using the ``max_length`` argument.
+
+FloatField
+----------
+
+A floating-point number represented in Python by a ``float`` instance.
+
+ImageField
+----------
+
+Like ``FileField``, but validates that the uploaded object is a valid
+image. Has two extra optional arguments:
+
+``height_field``
+
+ Name of a model field which will be auto-populated with the height of the
+ image each time the model instance is saved.
+
+``width_field``
+
+ Name of a model field which will be auto-populated with the width of the
+ image each time the model instance is saved.
+
+In addition to the special attributes that are available for FileField``,
+an ``ImageField`` also has ``height`` and ``width`` attributes, both of which
+correspond to the image's height and width in pixels.
+
+Requires the Python Imaging Library, available at http://www.pythonware.com/products/pil/.
+
+By default, ``ImageField`` instances are
+created as ``varchar(100)`` columns in your database. As with other fields, you
+can change the maximum length using the ``max_length`` argument.
+
+IntegerField
+------------
+
+An integer.
+
+IPAddressField
+--------------
+
+An IP address, in string format (e.g. ``'192.0.2.30'``).
+
+NullBooleanField
+----------------
+
+Like a ``BooleanField``, but allows ``NULL`` as one of the options. Use
+this instead of a ``BooleanField`` with ``null=True``.
+
+PositiveIntegerField
+--------------------
+
+Like an ``IntegerField``, but must be positive.
+
+PositiveSmallIntegerField
+-------------------------
+
+Like a ``PositiveIntegerField``, but only allows values under a certain
+(database-dependent) point.
+
+SlugField
+---------
+
+"Slug" is a newspaper term. A slug is a short label for something,
+containing only letters, numbers, underscores or hyphens. They're generally used
+in URLs.
+
+Like a ``CharField``, you can specify ``max_length``. If ``max_length`` is not
+specified, Django will use a default length of 50.
+
+Implies setting ``db_index`` to ``True``.
+
+SmallIntegerField
+-----------------
+
+Like an ``IntegerField``, but only allows values under a certain
+(database-dependent) point.
+
+TextField
+---------
+
+A large text field.
+
+Also see ``CharField`` for storing smaller bits of text.
+
+TimeField
+---------
+
+A time, represented in Python by a ``datetime.time`` instance. Accepts the same
+auto-population options as ``DateField``.
+
+URLField
+--------
+
+A ``CharField`` for a URL. Has one extra optional argument:
+
+``verify_exists``
+
+ If ``True`` (the default), the URL given will be checked for existence
+ (i.e., the URL actually loads and doesn't give a 404 response). It should
+ be noted that when using the single-threaded development server, validating
+ a url being served by the same server will hang.
+ This should not be a problem for multithreaded servers.
+
+Like all ``CharField`` subclasses, ``URLField`` takes the optional
+``max_length`` argument. If you don't specify
+``max_length``, a default of 200 is used.
+
+XMLField
+--------
+
+A ``TextField`` that checks that the value is valid XML that matches a
+given schema. Takes one required argument:
+
+``schema_path``
+
+ The filesystem path to a RelaxNG schema against which to validate the
+ field. For more on RelaxNG, see http://www.relaxng.org/.
+
+Universal Field Options
+=======================
+
+The following arguments are available to all field types. All are optional.
+
+null
+----
+
+If ``True``, Django will store empty values as ``NULL`` in the database. If
+``False``, saving empty values will likely result in a database error. Default
+is ``False``.
+
+Note that empty string values will always get stored as empty strings, not as
+``NULL``. Only use ``null=True`` for non-string fields such as integers,
+booleans and dates. For both types of fields, you will also need to set
+``blank=True`` if you wish to permit empty values in forms, as the
+``null`` parameter only affects database storage (see
+``blank``).
+
+Avoid using ``null`` on string-based fields such as
+``CharField`` and ``TextField`` unless you have an excellent reason.
+If a string-based field has ``null=True``, that means it has two possible values
+for "no data": ``NULL``, and the empty string. In most cases, it's redundant to
+have two possible values for "no data;" Django's convention is to use the empty
+string, not ``NULL``.
+
+.. note::
+
+ When using the Oracle database backend, the ``null=True`` option will be
+ coerced for string-based fields that have the empty string as a possible
+ value, and the value ``NULL`` will be stored to denote the empty string.
+
+For more on this, see the section "Making Date and Numeric Fields Optional" in
+Chapter 6.
+
+blank
+-----
-Often successful projects are made so by their teams, not their choice of
-technology. We asked our panel how their teams work, and what tools and
-techniques they use to stay on track.
+If ``True``, the field is allowed to be blank. Default is ``False``.
-*Ned Batchelder*:
+Note that this is different than ``null``. ``null`` is
+purely database-related, whereas ``blank`` is validation-related. If
+a field has ``blank=True``, validation on Django's admin site will allow entry
+of an empty value. If a field has ``blank=False``, the field will be required.
- We're a pretty standard Web startup environment: Trac/SVN, five
- developers. We have a staging server, a production server, an ad hoc deploy
- script, and so on.
+choices
+-------
- Memcached rocks.
+An iterable (e.g., a list or tuple) of 2-tuples to use as choices for this
+field.
-*Johannes Beigel*:
+A choices list looks like this::
- We use Trac as our bug tracker and wiki and have recently switched from using
- Subversion+SVK to Mercurial (a Python-written distributed version-
- control system that handles branching/merging like a charm).
+ YEAR_IN_SCHOOL_CHOICES = (
+ ('FR', 'Freshman'),
+ ('SO', 'Sophomore'),
+ ('JR', 'Junior'),
+ ('SR', 'Senior'),
+ ('GR', 'Graduate'),
+ )
- I think we have a very agile development process, but we do not follow a
- "rigid" methodology like Extreme Programming ([though] we borrow many
- ideas from it). We are more like Pragmatic Programmers.
+The first element in each tuple is the actual value to be stored. The second
+element is the human-readable name for the option.
- We have an automated build system (customized but based on SCons) and unit
- tests for almost everything.
+The choices list can be defined either as part of your model class::
-*David Cramer*:
+ class Foo(models.Model):
+ GENDER_CHOICES = (
+ ('M', 'Male'),
+ ('F', 'Female'),
+ )
+ gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
- Our team consists of four Web developers, all working in the same office
- space, so it's quite easy to communicate. We rely on common tools such as
- SVN and Trac.
+or outside your model class altogether::
-*Christian Hammond*:
+ GENDER_CHOICES = (
+ ('M', 'Male'),
+ ('F', 'Female'),
+ )
+ class Foo(models.Model):
+ gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
- Review Board currently has two main developers (myself and David
- Trowbridge) and a couple of contributors. We're hosted on Google Code and
- make use of their Subversion repository, issue tracker, and wiki. We
- actually use Review Board to review our changes before they go in. We test
- on our local computers, both by hand and through unit tests. Our users at
- VMware who use Review Board every day provide a lot of useful feedback and
- bug reports, which we try to incorporate into the program.
+You can also collect your available choices into named groups that can
+be used for organizational purposes in a form::
-Deployment
-==========
+ MEDIA_CHOICES = (
+ ('Audio', (
+ ('vinyl', 'Vinyl'),
+ ('cd', 'CD'),
+ )
+ ),
+ ('Video', (
+ ('vhs', 'VHS Tape'),
+ ('dvd', 'DVD'),
+ )
+ ),
+ ('unknown', 'Unknown'),
+ )
-The Django developers take ease of deployment and scaling very seriously, so
-we're always interested in hearing about real-world trials and tribulations.
+The first element in each tuple is the name to apply to the group. The
+second element is an iterable of 2-tuples, with each 2-tuple containing
+a value and a human-readable name for an option. Grouped options may be
+combined with ungrouped options within a single list (such as the
+`unknown` option in this example).
-*Ned Batchelder*:
+Finally, note that choices can be any iterable object -- not necessarily a list
+or tuple. This lets you construct choices dynamically. But if you find yourself
+hacking ``choices`` to be dynamic, you're probably better off using a
+proper database table with a `ForeignKey``. ``choices`` is
+meant for static data that doesn't change much, if ever.
- We've used caching both at the query and response layers to speed response
- time. We have a classic configuration: a multiplexer, many app servers,
- one database server. This has worked well for us, because we can use
- caching at the app server to avoid database access, and then add app
- servers as needed to handle the volume.
+db_column
+---------
-*Johannes Beigel*:
+The name of the database column to use for this field. If this isn't given,
+Django will use the field's name.
- Linux servers, preferably Debian, with many gigs of RAM. Lighttpd as the Web
- server, Pound as the HTTPS front-end and load balancer if needed, and Memcached
- for caching. SQLite for small databases, Postgres if data grows larger, and
- highly specialized custom database stuff for our search and knowledge
- management components.
+If your database column name is an SQL reserved word, or contains
+characters that aren't allowed in Python variable names -- notably, the
+hyphen -- that's OK. Django quotes column and table names behind the
+scenes.
-*David Cramer*:
+db_index
+--------
- Our structure is still up for debate... [but this is what's current]:
+If ``True``, ``django-admin.py sqlindexes`` will output a
+``CREATE INDEX`` statement for this field.
- When a user requests the site they are sent to a cluster of Squid servers
- using lighttpd. There, servers then check if the user is logged in. If not,
- they're served a cached page. A logged-in user is forwarded to a cluster
- of Web servers running apache2 plus mod_python (each with a large amount of
- memory), which then each rely on a distributed Memcached system and a
- beastly MySQL database server. Static content is hosted on a cluster of
- lighttpd servers. Media, such as large files and videos, are hosted
- (currently) on a server using a minimal Django install using lighttpd plus
- fastcgi. As of right now we're moving toward pushing all media to
- a service similar to Amazon's S3.
+db_tablespace
+-------------
-*Christian Hammond*:
+The name of the database tablespace to use for this field's index, if this field
+is indexed. The default is the project's ``DEFAULT_INDEX_TABLESPACE``
+setting, if set, or the ``db_tablespace`` of the model, if any. If
+the backend doesn't support tablespaces, this option is ignored.
- There are two main production servers right now. One is at VMware and
- consists of an Ubuntu virtual machine running on VMware ESX. We use MySQL
- for the database, Memcached for our caching back-end, and currently Apache
- for the Web server. We have several powerful servers that we can scale
- across when we need to. We may find ourselves moving MySQL or Memcached to
- another virtual machine as our user base increases.
+default
+-------
+
+The default value for the field. This can be a value or a callable object. If
+callable it will be called every time a new object is created.
+
+editable
+--------
+
+If ``False``, the field will not be editable in the admin or via forms
+automatically generated from the model class. Default is ``True``.
+
+help_text
+---------
+
+Extra "help" text to be displayed under the field on the object's admin form.
+It's useful for documentation even if your object doesn't have an admin form.
+
+Note that this value is *not* HTML-escaped when it's displayed in the admin
+interface. This lets you include HTML in ``help_text`` if you so
+desire. For example::
+
+ help_text="Please use the following format: <em>YYYY-MM-DD</em>."
+
+Alternatively you can use plain text and
+``django.utils.html.escape()`` to escape any HTML special characters.
+
+primary_key
+-----------
+
+If ``True``, this field is the primary key for the model.
+
+If you don't specify ``primary_key=True`` for any fields in your model, Django
+will automatically add an ``AutoField`` to hold the primary key, so you
+don't need to set ``primary_key=True`` on any of your fields unless you want to
+override the default primary-key behavior.
+
+``primary_key=True`` implies ``null=False`` and ``unique=True``.
+Only one primary key is allowed on an object.
+
+unique
+------
+
+If ``True``, this field must be unique throughout the table.
+
+This is enforced at the database level and at the level of forms created with
+``ModelForm`` (including forms in the Django admin site). If
+you try to save a model with a duplicate value in a ``unique``
+field, an ``IntegrityError`` will be raised by the model's
+``save`` method.
+
+This option is valid on all field types except ``ManyToManyField``,
+``FileField`` and ``ImageField``.
+
+unique_for_date
+---------------
+
+Set this to the name of a ``DateField`` or ``DateTimeField`` to
+require that this field be unique for the value of the date field.
+
+For example, if you have a field ``title`` that has
+``unique_for_date="pub_date"``, then Django wouldn't allow the entry of two
+records with the same ``title`` and ``pub_date``.
+
+This is enforced at the level of forms created with ``ModelForm`` (including
+forms in the Django admin site) but not at the database level.
+
+unique_for_month
+----------------
+
+Like ``unique_for_date``, but requires the field to be unique with
+respect to the month.
+
+unique_for_year
+---------------
+
+Like ``unique_for_date`` and ``unique_for_month``.
+
+verbose_name
+------------
+
+A human-readable name for the field. If the verbose name isn't given, Django
+will automatically create it using the field's attribute name, converting
+underscores to spaces.
+
+Relationships
+=============
+
+Clearly, the power of relational databases lies in relating tables to each
+other. Django offers ways to define the three most common types of database
+relationships: many-to-one, many-to-many, and one-to-one.
+
+ForeignKey
+----------
+
+A many-to-one relationship. Requires a positional argument: the class to which
+the model is related.
+
+To create a recursive relationship -- an object that has a many-to-one
+relationship with itself -- use ``models.ForeignKey('self')``.
+
+If you need to create a relationship on a model that has not yet been defined,
+you can use the name of the model, rather than the model object itself::
+
+ class Car(models.Model):
+ manufacturer = models.ForeignKey('Manufacturer')
+ # ...
+
+ class Manufacturer(models.Model):
+ # ...
+
+Note, however, that this only refers to models in the same ``models.py`` file.
+
+To refer to models defined in another
+application, you must instead explicitly specify the application label. For
+example, if the ``Manufacturer`` model above is defined in another application
+called ``production``, you'd need to use::
+
+ class Car(models.Model):
+ manufacturer = models.ForeignKey('production.Manufacturer')
+
+Behind the scenes, Django appends ``"_id"`` to the field name to create its
+database column name. In the above example, the database table for the ``Car``
+model will have a ``manufacturer_id`` column. (You can change this explicitly by
+specifying ``db_column``) However, your code should never have to
+deal with the database column name, unless you write custom SQL. You'll always
+deal with the field names of your model object.
+
+``ForeignKey`` accepts an extra set of arguments -- all optional -- that
+define the details of how the relation works.
+
+``limit_choices_to``
+
+ A dictionary of lookup arguments and values
+ that limit the available admin choices for this object. Use this with
+ functions from the Python ``datetime`` module to limit choices of objects by
+ date. For example::
+
+ limit_choices_to = {'pub_date__lte': datetime.now}
+
+ only allows the choice of related objects with a ``pub_date`` before the
+ current date/time to be chosen.
+
+ ``limit_choices_to`` has no effect on the inline FormSets that are created
+ to display related objects in the admin.
- The second production server is the one for Review Board itself. The
- setup is nearly identical to the one at VMware, except the virtual machine
- is being hosted on VMware Server.
+``related_name``
+
+ The name to use for the relation from the related object back to this one.
+
+``to_field``
+
+ The field on the related object that the relation is to. By default, Django
+ uses the primary key of the related object.
+
+ManyToManyField
+---------------
+
+A many-to-many relationship. Requires a positional argument: the class to which
+the model is related. This works exactly the same as it does for
+``ForeignKey``, including all the options regarding recursive relationships
+and lazy relationships.
+
+Behind the scenes, Django creates an intermediary join table to represent the
+many-to-many relationship. By default, this table name is generated using the
+names of the two tables being joined. Since some databases don't support table
+names above a certain length, these table names will be automatically
+truncated to 64 characters and a uniqueness hash will be used. This means you
+might see table names like ``author_books_9cdf4``; this is perfectly normal.
+You can manually provide the name of the join table using the
+``db_table`` option.
+
+``ManyToManyField`` accepts an extra set of arguments -- all optional --
+that control how the relationship functions.
+
+``related_name``
+
+ Same as ``related_name`` in ``ForeignKey``.
+
+``limit_choices_to``
+
+ Same as ``limit_choices_to`` in ``ForeignKey``.
+
+ ``limit_choices_to`` has no effect when used on a ``ManyToManyField`` with a
+ custom intermediate table specified using the
+ ``through`` paramter.
+
+``symmetrical``
+
+ Only used in the definition of ManyToManyFields on self. Consider the
+ following model::
+
+ class Person(models.Model):
+ friends = models.ManyToManyField("self")
+
+ When Django processes this model, it identifies that it has a
+ ``ManyToManyField`` on itself, and as a result, it doesn't add a
+ ``person_set`` attribute to the ``Person`` class. Instead, the
+ ``ManyToManyField`` is assumed to be symmetrical -- that is, if I am
+ your friend, then you are my friend.
+
+ If you do not want symmetry in many-to-many relationships with ``self``, set
+ ``symmetrical`` to ``False``. This will force Django to
+ add the descriptor for the reverse relationship, allowing
+ ``ManyToManyField`` relationships to be non-symmetrical.
+
+``through``
+
+ Django will automatically generate a table to manage many-to-many
+ relationships. However, if you want to manually specify the intermediary
+ table, you can use the ``through`` option to specify
+ the Django model that represents the intermediate table that you want to
+ use.
+
+ The most common use for this option is when you want to associate
+ extra data with a many-to-many relationship.
+
+``db_table``
+
+ The name of the table to create for storing the many-to-many data. If this
+ is not provided, Django will assume a default name based upon the names of
+ the two tables being joined.
+
+OneToOneField
+-------------
+
+A one-to-one relationship. Conceptually, this is similar to a
+``ForeignKey`` with ``unique=True``, but the
+"reverse" side of the relation will directly return a single object.
+
+This is most useful as the primary key of a model which "extends"
+another model in some way; multi-table-inheritance is
+implemented by adding an implicit one-to-one relation from the child
+model to the parent model, for example.
+
+One positional argument is required: the class to which the model will be
+related. This works exactly the same as it does for ``ForeignKey``,
+including all the options regarding recursive relationships and lazy
+relationships.
+
+Additionally, ``OneToOneField`` accepts all of the extra arguments
+accepted by ``ForeignKey``, plus one extra argument:
+
+``parent_link``
+
+ When ``True`` and used in a model which inherits from another
+ (concrete) model, indicates that this field should be used as the
+ link back to the parent class, rather than the extra
+ ``OneToOneField`` which would normally be implicitly created by
+ subclassing.
+
+Model Metadata Options
+======================
+
+Model-specific metadata lives in a ``class Meta`` defined in the body of your
+model class::
+
+ class Book(models.Model):
+ title = models.CharField(maxlength=100)
+
+ class Meta:
+ # model metadata options go here
+ ...
+
+Model metadata is "anything that's not a field," such as ordering options and so forth.
+
+The sections that follow present a list of all possible ``Meta`` options.
+No options are required. Adding ``class Meta`` to a model is completely optional.
+
+abstract
+--------
+
+If ``True``, this model will be an abstract base class. See the Django
+documentation for more on abstract base classes.
+
+db_table
+--------
+
+The name of the database table to use for the model::
+
+ db_table = 'music_album'
+
+Table names
+~~~~~~~~~~~
+
+To save you time, Django automatically derives the name of the database table
+from the name of your model class and the app that contains it. A model's
+database table name is constructed by joining the model's "app label" -- the
+name you used in ``manage.py startapp`` -- to the model's class name, with an
+underscore between them.
+
+For example, if you have an app ``bookstore`` (as created by
+``manage.py startapp bookstore``), a model defined as ``class Book`` will have
+a database table named ``bookstore_book``.
+
+To override the database table name, use the ``db_table`` parameter in
+``class Meta``.
+
+If your database table name is an SQL reserved word, or contains characters that
+aren't allowed in Python variable names -- notably, the hyphen -- that's OK.
+Django quotes column and table names behind the scenes.
+
+db_tablespace
+-------------
+
+The name of the database tablespace to use for the model. If the backend doesn't
+support tablespaces, this option is ignored.
+
+get_latest_by
+-------------
+
+The name of a ``DateField`` or ``DateTimeField`` in the model. This
+specifies the default field to use in your model ``Manager``'s
+``latest`` method.
+
+Example::
+
+ get_latest_by = "order_date"
+
+managed
+-------
+
+Defaults to ``True``, meaning Django will create the appropriate database
+tables in ``django-admin.py syncdb`` and remove them as part of a ``reset``
+management command. That is, Django *manages* the database tables' lifecycles.
+
+If ``False``, no database table creation or deletion operations will be
+performed for this model. This is useful if the model represents an existing
+table or a database view that has been created by some other means. This is
+the *only* difference when ``managed`` is ``False``. All other aspects of
+model handling are exactly the same as normal. This includes
+
+ 1. Adding an automatic primary key field to the model if you don't declare
+ it. To avoid confusion for later code readers, it's recommended to
+ specify all the columns from the database table you are modeling when
+ using unmanaged models.
+
+ 2. If a model with ``managed=False`` contains a
+ ``ManyToManyField`` that points to another
+ unmanaged model, then the intermediary table for the many-to-many join
+ will also not be created. However, the intermediary table between one
+ managed and one unmanaged model *will* be created.
+
+ If you need to change this default behavior, create the intermediary
+ table as an explicit model (with ``managed`` set as needed) and use the
+ ``through`` attribute to make the relation use your
+ custom model.
+
+For tests involving models with ``managed=False``, it's up to you to ensure
+the correct tables are created as part of the test setup.
+
+If you're interested in changing the Python-level behavior of a model class,
+you *could* use ``managed=False`` and create a copy of an existing model.
+However, there's a better approach for that situation: proxy-models.
+
+ordering
+--------
+
+The default ordering for the object, for use when obtaining lists of objects::
+
+ ordering = ['-order_date']
+
+This is a tuple or list of strings. Each string is a field name with an optional
+"-" prefix, which indicates descending order. Fields without a leading "-" will
+be ordered ascending. Use the string "?" to order randomly.
+
+.. note::
+
+ Regardless of how many fields are in ``ordering``, the admin
+ site uses only the first field.
+
+For example, to order by a ``pub_date`` field ascending, use this::
+
+ ordering = ['pub_date']
+
+To order by ``pub_date`` descending, use this::
+
+ ordering = ['-pub_date']
+
+To order by ``pub_date`` descending, then by ``author`` ascending, use this::
+
+ ordering = ['-pub_date', 'author']
+
+proxy
+-----
+
+If set to ``True``, a model which subclasses another model will be treated as
+a proxy model. For more on proxy models, see the Django documentation.
+
+unique_together
+---------------
+
+Sets of field names that, taken together, must be unique::
+
+ unique_together = (("driver", "restaurant"),)
+
+This is a list of lists of fields that must be unique when considered together.
+It's used by ``ModelForm`` forms (including forms in the Django admin site) and
+is enforced at the database level (i.e., the appropriate ``UNIQUE`` statements
+are included in the ``CREATE TABLE`` statement).
+
+For convenience, unique_together can be a single sequence when dealing with a single
+set of fields::
+
+ unique_together = ("driver", "restaurant")
+
+verbose_name
+------------
+
+A human-readable name for the object, singular::
+
+ verbose_name = "pizza"
+
+If this isn't given, Django will use a munged version of the class name:
+``CamelCase`` becomes ``camel case``.
+
+verbose_name_plural
+-------------------
+
+The plural name for the object::
+
+ verbose_name_plural = "stories"
+
+If this isn't given, Django will use ``verbose_name`` + ``"s"``.
View
2,341 appendixB.rst
991 additions, 1,350 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
1,983 appendixC.rst
@@ -1,1517 +1,932 @@
==================================
-Appendix C: Database API Reference
+Appendix C: Generic View Reference
==================================
-Django's database API is the other half of the model API discussed in Appendix
-B. Once you've defined a model, you'll use this API any time you need to
-access the database. You've seen examples of this API in use throughout the
-book; this appendix explains all the various options in detail.
-
-Like the model APIs discussed in Appendix B, though these APIs are considered
-very stable, the Django developers consistently add new shortcuts and
-conveniences. It's a good idea to always check the latest documentation online,
-available at http://www.djangoproject.com/documentation/0.96/db-api/.
-
-Throughout this reference, we'll refer to the following models, which might form
-a simple Weblog application::
-
- from django.db import models
-
- class Blog(models.Model):
- name = models.CharField(max_length=100)
- tagline = models.TextField()
-
- def __str__(self):
- return self.name
-
- class Author(models.Model):
- name = models.CharField(max_length=50)
- email = models.EmailField()
-
- def __str__(self):
- return self.name
-
- class Entry(models.Model):
- blog = models.ForeignKey(Blog)
- headline = models.CharField(max_length=255)
- body_text = models.TextField()
- pub_date = models.DateTimeField()
- authors = models.ManyToManyField(Author)
-
- def __str__(self):
- return self.headline
-
-Creating Objects
-================
-
-To create an object, instantiate it using keyword arguments to the model class, and
-then call ``save()`` to save it to the database::
-
- >>> from mysite.blog.models import Blog
- >>> b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
- >>> b.save()
-
-This performs an ``INSERT`` SQL statement behind the scenes. Django doesn't hit
-the database until you explicitly call ``save()``.
-
-The ``save()`` method has no return value.
-
-To create an object and save it all in one step see the ``create`` manager
-method discussed shortly.
-
-What Happens When You Save?
----------------------------
-
-When you save an object, Django performs the following steps:
-
- #. **Emit a pre_save signal.** This provides a notification that
- an object is about to be saved. You can register a listener that
- will be invoked whenever this signal is emitted. These signals are
- still in development and weren't documented when this book went to
- press; check the online documentation for the latest information.
-
- #. **Preprocess the data.** Each field on the object is asked to
- perform any automated data modification that the field may need
- to perform.
-
- Most fields do *no* preprocessing -- the field data is kept as is.
- Preprocessing is only used on fields that have special behavior,
- like file fields.
-
- #. **Prepare the data for the database.** Each field is asked to provide
- its current value in a data type that can be written to the database.
-
- Most fields require no data preparation. Simple data types, such as
- integers and strings, are "ready to write" as a Python object. However,
- more complex data types often require some modification. For example,
- ``DateFields`` use a Python ``datetime`` object to store data.
- Databases don't store ``datetime`` objects, so the field value
- must be converted into an ISO-compliant date string for insertion
- into the database.
-
- #. **Insert the data into the database.** The preprocessed, prepared
- data is then composed into an SQL statement for insertion into the
- database.
-
- #. **Emit a post_save signal.** As with the ``pre_save`` signal, this
- is used to provide notification that an object has been successfully
- saved. Again, these signals are not yet documented.
-
-Autoincrementing Primary Keys
-------------------------------
-
-For convenience, each model is given an autoincrementing primary key field
-named ``id`` unless you explicitly specify ``primary_key=True`` on a field (see
-the section titled "AutoField" in Appendix B).
-
-If your model has an ``AutoField``, that autoincremented value will be
-calculated and saved as an attribute on your object the first time you call
-``save()``::
+Chapter 11 introduced generic views but leaves out some of the gory details.
+This appendix describes each generic view along with all the options each view can
+take. Be sure to read Chapter 11 before trying to understand the reference
+material that follows. You might want to refer back to the ``Book``,
+``Publisher``, and ``Author`` objects defined in that chapter; the examples that
+follow use these models.
- >>> b2 = Blog(name='Cheddar Talk', tagline='Thoughts on cheese.')
- >>> b2.id # Returns None, because b doesn't have an ID yet.
- None
+Common Arguments to Generic Views
+=================================
+
+Most of these views take a large number of arguments that can change the generic
+view's behavior. Many of these arguments work the same across a large number of
+views. Table C-1 describes each of these common arguments; anytime you see one
+of these arguments in a generic view's argument list, it will work as described in
+the table.
+
+.. table:: Table C-1. Common Arguments to Generic Views
+
+ ========================== ===============================================
+ Argument Description
+ ========================== ===============================================
+ ``allow_empty`` A Boolean specifying whether to display the
+ page if no objects are available. If this is
+ ``False`` and no objects are available, the view
+ will raise a 404 error instead of displaying an
+ empty page. By default, this is ``True``.
+
+ ``context_processors`` A list of additional template-context processors
+ (besides the defaults) to apply to the view's
+ template. See Chapter 9 for information on
+ template context processors.
+
+ ``extra_context`` A dictionary of values to add to the template
+ context. By default, this is an empty
+ dictionary. If a value in the dictionary is
+ callable, the generic view will call it just
+ before rendering the template.
+
+ ``mimetype`` The MIME type to use for the resulting
+ document. It defaults to the value of the
+ ``DEFAULT_MIME_TYPE`` setting, which is
+ ``text/html`` if you haven't changed it.
+
+ ``queryset`` A ``QuerySet`` (i.e., something like
+ ``Author.objects.all()``) to read objects from.
+ See Appendix B for more information about
+ ``QuerySet`` objects. Most generic views require
+ this argument.
+
+ ``template_loader`` The template loader to use when loading the
+ template. By default, it's
+ ``django.template.loader``. See Chapter 9 for
+ information on template loaders.
+
+ ``template_name`` The full name of a template to use in rendering
+ the page. This lets you override the default
+ template name derived from the ``QuerySet``.
+
+ ``template_object_name`` The name of the template variable to
+ use in the template context. By default, this is
+ ``'object'``. Views that list more than one
+ object (i.e., ``object_list`` views and various
+ objects-for-date views) will append ``'_list'``
+ to the value of this parameter.
+ ========================== ===============================================
- >>> b2.save()
- >>> b2.id # Returns the ID of your new object.
- 14
-
-There's no way to tell what the value of an ID will be before you call
-``save()``, because that value is calculated by your database, not by Django.
-
-If a model has an ``AutoField`` but you want to define a new object's ID
-explicitly when saving, just define it explicitly before saving, rather than
-relying on the autoassignment of the ID::
-
- >>> b3 = Blog(id=3, name='Cheddar Talk', tagline='Thoughts on cheese.')
- >>> b3.id
- 3
- >>> b3.save()
- >>> b3.id
- 3
-
-If you assign auto-primary-key values manually, make sure not to use an
-already existing primary key value! If you create a new object with an explicit
-primary key value that already exists in the database, Django will assume you're
-changing the existing record rather than creating a new one.
-
-Given the preceding ``'Cheddar Talk'`` blog example, this example would override the
-previous record in the database::
-
- >>> b4 = Blog(id=3, name='Not Cheddar', tagline='Anything but cheese.')
- >>> b4.save() # Overrides the previous blog with ID=3!
-
-Explicitly specifying auto-primary-key values is mostly useful for bulk-saving
-objects, when you're confident you won't have primary key collision.
-
-Saving Changes to Objects
-=========================
-
-To save changes to an object that's already in the database, use ``save()``.
-
-Given a ``Blog`` instance ``b5`` that has already been saved to the database,
-this example changes its name and updates its record in the database::
-
- >>> b5.name = 'New name'
- >>> b5.save()
-
-This performs an ``UPDATE`` SQL statement behind the scenes. Again, Django
-doesn't hit the database until you explicitly call ``save()``.
-
-.. admonition:: How Django Knows When to ``UPDATE`` and When to ``INSERT``
-
- You may have noticed that Django database objects use the same ``save()`` method
- for creating and changing objects. Django abstracts the need to use
- ``INSERT`` or ``UPDATE`` SQL statements. Specifically, when you call
- ``save()``, Django follows this algorithm:
+"Simple" Generic Views
+======================
- * If the object's primary key attribute is set to a value that evaluates
- to ``True`` (i.e., a value other than ``None`` or the empty string),
- Django executes a ``SELECT`` query to determine whether a record with
- the given primary key already exists.
+The module``django.views.generic.simple`` contains simple views that handle a
+couple of common cases: rendering a template when no view logic is needed and
+issuing a redirect.
- * If the record with the given primary key does already exist, Django
- executes an ``UPDATE`` query.
+Rendering a Template
+--------------------
- * If the object's primary key attribute is *not* set, or if it's set but
- a record doesn't exist, Django executes an ``INSERT``.
+*View function*: ``django.views.generic.simple.direct_to_template``
- Because of this, you should be careful not to specify a primary key value
- explicitly when saving new objects if you cannot guarantee the primary key
- value is unused.
+This view renders a given template, passing it a ``{{ params }}`` template
+variable, which is a dictionary of the parameters captured in the URL.
-Updating ``ForeignKey`` fields works exactly the same way; simply assign an
-object of the right type to the field in question::
+Example
+```````
- >>> joe = Author.objects.create(name="Joe")
- >>> entry.author = joe
- >>> entry.save()
+Given the following URLconf::
-Django will complain if you try to assign an object of the wrong type.
+ from django.conf.urls.defaults import *
+ from django.views.generic.simple import direct_to_template
-Retrieving Objects
-==================
+ urlpatterns = patterns('',
+ (r'^foo/$', direct_to_template, {'template': 'foo_index.html'}),
+ (r'^foo/(?P<id>\d+)/$', direct_to_template, {'template': 'foo_detail.html'}),
+ )
-Throughout the book you've seen objects retrieved using code like the following::
+a request to ``/foo/`` would render the template ``foo_index.html``, and a
+request to ``/foo/15/`` would render ``foo_detail.html`` with a context
+variable ``{{ params.id }}`` that is set to ``15``.
- >>> blogs = Blog.objects.filter(author__name__contains="Joe")
+Required Arguments
+``````````````````
-There are quite a few "moving parts" behind the scenes here: when you
-retrieve objects from the database, you're actually constructing a ``QuerySet``
-using the model's ``Manager``. This ``QuerySet`` knows how to execute SQL and
-return the requested objects.
+ * ``template``: The full name of a template to use.
-Appendix B looked at both of these objects from a model-definition point of
-view; now we'll look at how they operate.
+Redirecting to Another URL
+--------------------------
-A ``QuerySet`` represents a collection of objects from your database. It can
-have zero, one, or many *filters* -- criteria that narrow down the collection
-based on given parameters. In SQL terms, a ``QuerySet`` equates to a ``SELECT``
-statement, and a filter is a limiting clause such as ``WHERE`` or ``LIMIT``.
+*View function*: ``django.views.generic.simple.redirect_to``
-You get a ``QuerySet`` by using your model's ``Manager``. Each model has at
-least one ``Manager``, and it's called ``objects`` by default. Access it
-directly via the model class, like so::
+This view redirects to another URL. The given URL may contain dictionary-style string
+formatting, which will be interpolated against the parameters captured in the
+URL.
- >>> Blog.objects
- <django.db.models.manager.Manager object at 0x137d00d>
+If the given URL is ``None``, Django will return an HTTP 410 ("Gone") message.
-``Manager``\s are accessible only via model classes, rather than from model
-instances, to enforce a separation between "table-level" operations and
-"record-level" operations::
+Example
+```````
- >>> b = Blog(name='Foo', tagline='Bar')
- >>> b.objects
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- AttributeError: Manager isn't accessible via Blog instances.
+This URLconf redirects from ``/foo/<id>/`` to ``/bar/<id>/``::
-The ``Manager`` is the main source of ``QuerySets`` for a model. It acts as a
-"root" ``QuerySet`` that describes all objects in the model's database table.
-For example, ``Blog.objects`` is the initial ``QuerySet`` that contains all
-``Blog`` objects in the database.
+ from django.conf.urls.defaults import *
+ from django.views.generic.simple import redirect_to
-Caching and QuerySets
-=====================
+ urlpatterns = patterns('django.views.generic.simple',
+ ('^foo/(?p<id>\d+)/$', redirect_to, {'url': '/bar/%(id)s/'}),
+ )
-Each ``QuerySet`` contains a cache, to minimize database access. It's important
-to understand how it works, in order to write the most efficient code.
+This example returns a "Gone" response for requests to ``/bar/``::
-In a newly created ``QuerySet``, the cache is empty. The first time a
-``QuerySet`` is evaluated -- and, hence, a database query happens -- Django
-saves the query results in the ``QuerySet``'s cache and returns the results
-that have been explicitly requested (e.g., the next element, if the
-``QuerySet`` is being iterated over). Subsequent evaluations of the
-``QuerySet`` reuse the cached results.
+ from django.views.generic.simple import redirect_to
-Keep this caching behavior in mind, because it may bite you if you don't use
-your ``QuerySet``s correctly. For example, the following will create two
-``QuerySet``\s, evaluate them, and throw them away::
+ urlpatterns = patterns('django.views.generic.simple',
+ ('^bar/$', redirect_to, {'url': None}),
+ )
- print [e.headline for e in Entry.objects.all()]
- print [e.pub_date for e in Entry.objects.all()]
+Required Arguments
+``````````````````
-That means the same database query will be executed twice, effectively doubling
-your database load. Also, there's a possibility the two lists may not include
-the same database records, because an ``Entry`` may have been added or deleted
-in the split second between the two requests.
+ * ``url``: The URL to redirect to, as a string. Or ``None`` to return a 410
+ ("Gone") HTTP response.
-To avoid this problem, simply save the ``QuerySet`` and reuse it::
+List/Detail Generic Views
+=========================
- queryset = Poll.objects.all()
- print [p.headline for p in queryset] # Evaluate the query set.
- print [p.pub_date for p in queryset] # Reuse the cache from the evaluation.
+The list/detail generic views (in the module
+``django.views.generic.list_detail``) handle the common case of displaying a
+list of items at one view and individual "detail" views of those items at
+another.
-Filtering Objects
-=================
+Lists of Objects
+----------------
-The simplest way to retrieve objects from a table is to get all of them.
-To do this, use the ``all()`` method on a ``Manager``::
+*View function*: ``django.views.generic.list_detail.object_list``
- >>> Entry.objects.all()
+Use this view to display a page representing a list of objects.
-The ``all()`` method returns a ``QuerySet`` of all the objects in the database.
+Example
+```````
-Usually, though, you'll need to select only a subset of the complete set of
-objects. To create such a subset, you refine the initial ``QuerySet``, adding filter
-conditions. You'll usually do this using the ``filter()`` and/or ``exclude()``
-methods::
+Given the ``Author`` object from Chapter 5, we can use the ``object_list`` view
+to show a simple list of all authors given the following URLconf snippet::
- >>> y2006 = Entry.objects.filter(pub_date__year=2006)
- >>> not2006 = Entry.objects.exclude(pub_date__year=2006)
+ from mysite.books.models import Author
+ from django.conf.urls.defaults import *
+ from django.views.generic import list_detail
-``filter()`` and ``exclude()`` both take *field lookup* arguments, which are
-discussed in detail shortly.
+ author_list_info = {
+ 'queryset': Author.objects.all(),
+ }
-Chaining Filters
-----------------
+ urlpatterns = patterns('',
+ (r'authors/$', list_detail.object_list, author_list_info)
+ )
-The result of refining a ``QuerySet`` is itself a ``QuerySet``, so it's
-possible to chain refinements together, for example::
+Required Arguments
+``````````````````
- >>> qs = Entry.objects.filter(headline__startswith='What')
- >>> qs = qs..exclude(pub_date__gte=datetime.datetime.now())
- >>> qs = qs.filter(pub_date__gte=datetime.datetime(2005, 1, 1))
+ * ``queryset``: A ``QuerySet`` of objects to list (see Table C-1).
-This takes the initial ``QuerySet`` of all entries in the database, adds a
-filter, then an exclusion, and then another filter. The final result is a
-``QuerySet`` containing all entries with a headline that starts with "What"
-that were published between January 1, 2005, and the current day.
+Optional Arguments
+``````````````````
-It's important to point out here that ``QuerySets`` are lazy -- the act of creating
-a ``QuerySet`` doesn't involve any database activity. In fact, the three preceding lines
-don't make *any* database calls; you can chain filters together all day
-long and Django won't actually run the query until the ``QuerySet`` is
-*evaluated*.
+ * ``paginate_by``: An integer specifying how many objects should be
+ displayed per page. If this is given, the view will paginate objects with
+ ``paginate_by`` objects per page. The view will expect either a ``page``
+ query string parameter (via ``GET``) containing a zero-indexed page
+ number, or a ``page`` variable specified in the URLconf. See the following
+ "Notes on Pagination" section.
-You can evaluate a ``QuerySet`` in any following ways:
+Additionally, this view may take any of these common arguments described in
+Table C-1:
- * *Iterating*: A ``QuerySet`` is iterable, and it executes its database query the first
- time you iterate over it. For example, the following ``QuerySet`` isn't evaluated
- until it's iterated over in the ``for`` loop::
-
- qs = Entry.objects.filter(pub_date__year=2006)
- qs = qs.filter(headline__icontains="bill")
- for e in qs:
- print e.headline
+ * ``allow_empty``
+ * ``context_processors``
+ * ``extra_context``
+ * ``mimetype``
+ * ``template_loader``
+ * ``template_name``
+ * ``template_object_name``
- This prints all headlines from 2006 that contain "bill" but causes
- only one database hit.
+Template Name
+`````````````
- * *Printing it*: A ``QuerySet`` is evaluated when you call ``repr()`` on it.
- This is for convenience in the Python interactive interpreter, so you can
- immediately see your results when using the API interactively.
+If ``template_name`` isn't specified, this view will use the template
+``<app_label>/<model_name>_list.html`` by default. Both the application label and the
+model name are derived from the ``queryset`` parameter. The application label is the
+name of the application that the model is defined in, and the model name is the
+lowercased version of the name of the model class.
- * *Slicing*: As explained in the upcoming "Limiting QuerySets" section,
- a ``QuerySet`` can be sliced using Python's array-slicing syntax.
- Usually slicing a ``QuerySet`` returns another (unevaluated)``QuerySet``,
- but Django will execute the database query if you use the "step"
- parameter of slice syntax.
+In the previous example using ``Author.objects.all()`` as the ``queryset``, the application
+label would be ``books`` and the model name would be ``author``. This means
+the default template would be ``books/author_list.html``.
- * *Converting to a list*: You can force evaluation of a ``QuerySet`` by calling
- ``list()`` on it, for example::
+Template Context
+````````````````
- >>> entry_list = list(Entry.objects.all())
+In addition to ``extra_context``, the template's context will contain the following:
- Be warned, though, that this could have a large memory overhead, because
- Django will load each element of the list into memory. In contrast,
- iterating over a ``QuerySet`` will take advantage of your database to load
- data and instantiate objects only as you need them.
+ * ``object_list``: The list of objects. This variable's name depends on the
+ ``template_object_name`` parameter, which is ``'object'`` by default. If
+ ``template_object_name`` is ``'foo'``, this variable's name will be
+ ``foo_list``.
-.. admonition:: Filtered QuerySets Are Unique
+ * ``is_paginated``: A Boolean representing whether the results are
+ paginated. Specifically, this is set to ``False`` if the number of
+ available objects is less than or equal to ``paginate_by``.
- Each time you refine a ``QuerySet``, you get a brand-new ``QuerySet`` that
- is in no way bound to the previous ``QuerySet``. Each refinement creates a
- separate and distinct ``QuerySet`` that can be stored, used, and reused::
+If the results are paginated, the context will contain these extra variables:
- q1 = Entry.objects.filter(headline__startswith="What")
- q2 = q1.exclude(pub_date__gte=datetime.now())
- q3 = q1.filter(pub_date__gte=datetime.now())
+ * ``results_per_page``: The number of objects per page. (This is the same as
+ the ``paginate_by`` parameter.)
- These three ``QuerySets`` are separate. The first is a base ``QuerySet``
- containing all entries that contain a headline starting with "What". The
- second is a subset of the first, with an additional criterion that excludes
- records whose ``pub_date`` is greater than now. The third is a subset of the
- first, with an additional criterion that selects only the records whose
- ``pub_date`` is greater than now. The initial ``QuerySet`` (``q1``) is
- unaffected by the refinement process.
+ * ``has_next``: A Boolean representing whether there's a next page.
-Limiting QuerySets
-------------------
+ * ``has_previous``: A Boolean representing whether there's a previous page.
-Use Python's array-slicing syntax to limit your ``QuerySet`` to a certain number
-of results. This is the equivalent of SQL's ``LIMIT`` and ``OFFSET`` clauses.
+ * ``page``: The current page number, as an integer. This is 1-based.
-For example, this returns the first five entries (``LIMIT 5``)::
+ * ``next``: The next page number, as an integer. If there's no next page,
+ this will still be an integer representing the theoretical next-page
+ number. This is 1-based.
- >>> Entry.objects.all()[:5]
+ * ``previous``: The previous page number, as an integer. This is 1-based.
-This returns the sixth through tenth entries (``OFFSET 5 LIMIT 5``)::
+ * ``pages``: The total number of pages, as an integer.
- >>> Entry.objects.all()[5:10]
+ * ``hits``: The total number of objects across *all* pages, not just this
+ page.
-Generally, slicing a ``QuerySet`` returns a new ``QuerySet`` -- it doesn't
-evaluate the query. An exception is if you use the "step" parameter
-of Python slice syntax. For example, this would actually execute the query in
-order to return a list of every *second* object of the first ten::
+.. admonition:: A Note on Pagination
- >>> Entry.objects.all()[:10:2]
+ If ``paginate_by`` is specified, Django will paginate the results. You can
+ specify the page number in the URL in one of two ways:
-To retrieve a *single* object rather than a list (e.g., ``SELECT foo FROM bar
-LIMIT 1``), use a simple index instead of a slice. For example, this returns the
-first ``Entry`` in the database, after ordering entries alphabetically by
-headline::
+ * Use the ``page`` parameter in the URLconf. For example, this is what
+ your URLconf might look like::
- >>> Entry.objects.order_by('headline')[0]
+ (r'^objects/page(?P<page>[0-9]+)/$', 'object_list', dict(info_dict))
-This is roughly equivalent to the following::
+ * Pass the page number via the ``page`` query-string parameter. For
+ example, a URL would look like this::
- >>> Entry.objects.order_by('headline')[0:1].get()
+ /objects/?page=3
-Note, however, that the first of these will raise ``IndexError`` while the
-second will raise ``DoesNotExist`` if no objects match the given criteria.
+ In both cases, ``page`` is 1-based, not 0-based, so the first page would be
+ represented as page ``1``.
-Query Methods That Return New QuerySets
----------------------------------------
+Detail Views
+------------
-Django provides a range of ``QuerySet`` refinement methods that modify either
-the types of results returned by the ``QuerySet`` or the way its SQL query is
-executed. These methods are described in the sections that follow. Some of the
-methods take field lookup arguments, which are discussed in detail a bit later
-on.
+*View function*: ``django.views.generic.list_detail.object_detail``
-filter(\*\*lookup)
-~~~~~~~~~~~~~~~~~~
+This view provides a "detail" view of a single object.
-Returns a new ``QuerySet`` containing objects that match the given lookup
-parameters.
+Example
+```````
-exclude(\*\*kwargs)
-~~~~~~~~~~~~~~~~~~~
+Continuing the previous ``object_list`` example, we could add a detail view for a
+given author by modifying the URLconf:
-Returns a new ``QuerySet`` containing objects that do *not* match the given
-lookup parameters.
+.. parsed-literal::
-order_by(\*fields)
-~~~~~~~~~~~~~~~~~~
+ from mysite.books.models import Author
+ from django.conf.urls.defaults import *
+ from django.views.generic import list_detail
-By default, results returned by a ``QuerySet`` are ordered by the ordering
-tuple given by the ``ordering`` option in the model's metadata (see Appendix B). You can
-override this for a particular query using the ``order_by()`` method::
+ author_list_info = {
+ 'queryset' : Author.objects.all(),
+ }
+ **author_detail_info = {**
+ **"queryset" : Author.objects.all(),**
+ **"template_object_name" : "author",**
+ **}**
- >> Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')
+ urlpatterns = patterns('',
+ (r'authors/$', list_detail.object_list, author_list_info),
+ **(r'^authors/(?P<object_id>\d+)/$', list_detail.object_detail, author_detail_info),**
+ )
-This result will be ordered by ``pub_date`` descending, then by
-``headline`` ascending. The negative sign in front of ``"-pub_date"`` indicates
-*descending* order. Ascending order is assumed if the ``-`` is absent. To order
-randomly, use ``"?"``, like so::
+Required Arguments
+``````````````````
- >>> Entry.objects.order_by('?')
+ * ``queryset``: A ``QuerySet`` that will be searched for the object (see Table C-1).
-distinct()
-~~~~~~~~~~
+and either
-Returns a new ``QuerySet`` that uses ``SELECT DISTINCT`` in its SQL query. This
-eliminates duplicate rows from the query results.
+ * ``object_id``: The value of the primary-key field for the object.
-By default, a ``QuerySet`` will not eliminate duplicate rows. In practice, this
-is rarely a problem, because simple queries such as ``Blog.objects.all()`` don't
-introduce the possibility of duplicate result rows.
+or
-However, if your query spans multiple tables, it's possible to get duplicate
-results when a ``QuerySet`` is evaluated. That's when you'd use ``distinct()``.
+ * ``slug``: The slug of the given object. If you pass this field, then the
+ ``slug_field`` argument (see the following section) is also required.
-values(\*fields)
-~~~~~~~~~~~~~~~~
+Optional Arguments
+``````````````````
-Returns a special ``QuerySet`` that evaluates to a list of dictionaries instead
-of model-instance objects. Each of those dictionaries represents an object, with
-the keys corresponding to the attribute names of model objects::
+ * ``slug_field``: The name of the field on the object containing the slug.
+ This is required if you are using the ``slug`` argument, but it must be
+ absent if you're using the ``object_id`` argument.
- # This list contains a Blog object.
- >>> Blog.objects.filter(name__startswith='Beatles')
- [Beatles Blog]
+ * ``template_name_field``: The name of a field on the object whose value is
+ the template name to use. This lets you store template names in your data.
- # This list contains a dictionary.
- >>> Blog.objects.filter(name__startswith='Beatles').values()
- [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]
+ In other words, if your object has a field ``'the_template'`` that
+ contains a string ``'foo.html'``, and you set ``template_name_field`` to
+ ``'the_template'``, then the generic view for this object will use the
+ template ``'foo.html'``.
+
+ If the template named by ``template_name_field`` doesn't exist, the one
+ named by ``template_name`` is used instead. It's a bit of a
+ brain-bender, but it's useful in some cases.
-``values()`` takes optional positional arguments, ``*fields``, which specify
-field names to which the ``SELECT`` should be limited. If you specify the
-fields, each dictionary will contain only the field keys/values for the fields
-you specify. If you don't specify the fields, each dictionary will contain a
-key and value for every field in the database table::
+This view may also take these common arguments (see Table C-1):
- >>> Blog.objects.values()
- [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}],
- >>> Blog.objects.values('id', 'name')
- [{'id': 1, 'name': 'Beatles Blog'}]
+ * ``context_processors``
+ * ``extra_context``
+ * ``mimetype``
+ * ``template_loader``
+ * ``template_name``
+ * ``template_object_name``
-This method is useful when you know you're only going to need values from a
-small number of the available fields and you won't need the functionality of a
-model instance object. It's more efficient to select only the fields you need to
-use.
+Template Name
+`````````````
-dates(field, kind, order)
-~~~~~~~~~~~~~~~~~~~~~~~~~
+If ``template_name`` and ``template_name_field`` aren't specified, this view
+will use the template ``<app_label>/<model_name>_detail.html`` by default.
-Returns a special ``QuerySet`` that evaluates to a list of ``datetime.datetime``
-objects representing all available dates of a particular kind within the
-contents of the ``QuerySet``.
+Template Context
+````````````````
-The ``field`` argument must be the name of a ``DateField`` or ``DateTimeField``
-of your model. The ``kind`` argument must be either ``"year"``, ``"month"``, or
-``"day"``. Each ``datetime.datetime`` object in the result list is "truncated"
-to the given ``type``:
+In addition to ``extra_context``, the template's context will be as follows:
- * ``"year"`` returns a list of all distinct year values for the field.
-
- * ``"month"`` returns a list of all distinct year/month values for the field.
-
- * ``"day"`` returns a list of all distinct year/month/day values for the field.
+ * ``object``: The object. This variable's name depends on the
+ ``template_object_name`` parameter, which is ``'object'`` by default. If
+ ``template_object_name`` is ``'foo'``, this variable's name will be
+ ``foo``.
+
+Date-Based Generic Views
+========================
-``order``, which defaults to ``'ASC'``, should be either ``'ASC'`` or
-``'DESC'``. This specifies how to order the results.
+Date-based generic views are generally used to provide a set of "archive"
+pages for dated material. Think year/month/day archives for a newspaper, or a
+typical blog archive.
-Here are a few examples::
+.. admonition:: Tip:
- >>> Entry.objects.dates('pub_date', 'year')
- [datetime.datetime(2005, 1, 1)]
+ By default, these views ignore objects with dates in the future.
- >>> Entry.objects.dates('pub_date', 'month')
- [datetime.datetime(2005, 2, 1), datetime.datetime(2005, 3, 1)]
+ This means that if you try to visit an archive page in the future, Django
+ will automatically show a 404 ("Page not found") error, even if there are objects
+ published that day.
- >>> Entry.objects.dates('pub_date', 'day')
- [datetime.datetime(2005, 2, 20), datetime.datetime(2005, 3, 20)]
+ Thus, you can publish postdated objects that don't appear publicly until
+ their desired publication date.
- >>> Entry.objects.dates('pub_date', 'day', order='DESC')
- [datetime.datetime(2005, 3, 20), datetime.datetime(2005, 2, 20)]
-
- >>> Entry.objects.filter(headline__contains='Lennon').dates('pub_date', 'day')
- [datetime.datetime(2005, 3, 20)]
-
-select_related()
-~~~~~~~~~~~~~~~~
-
-Returns a ``QuerySet`` that will automatically "follow" foreign key
-relationships, selecting that additional related-object data when it executes
-its query. This is a performance booster that results in (sometimes much)
-larger queries but means later use of foreign key relationships won't require
-database queries.
-
-The following examples illustrate the difference between plain lookups and
-``select_related()`` lookups. Here's standard lookup::
-
- # Hits the database.
- >>> e = Entry.objects.get(id=5)
-
- # Hits the database again to get the related Blog object.
- >>> b = e.blog
-
-And here's ``select_related`` lookup::
-
- # Hits the database.
- >>> e = Entry.objects.select_related().get(id=5)
-
- # Doesn't hit the database, because e.blog has been prepopulated
- # in the previous query.
- >>> b = e.blog
-
-``select_related()`` follows foreign keys as far as possible. If you have the
-following models::
-
- class City(models.Model):
- # ...
+ However, for different types of date-based objects, this isn't appropriate
+ (e.g., a calendar of upcoming events). For these views, setting the
+ ``allow_future`` option to ``True`` will make the future objects appear (and
+ allow users to visit "future" archive pages).
- class Person(models.Model):
- # ...
- hometown = models.ForeignKey(City)
-
- class Book(models.Model):
- # ...
- author = models.ForeignKey(Person)
-
-then a call to ``Book.objects.select_related().get(id=4)`` will cache the
-related ``Person`` *and* the related ``City``::
-
- >>> b = Book.objects.select_related().get(id=4)
- >>> p = b.author # Doesn't hit the database.
- >>> c = p.hometown # Doesn't hit the database.
-
- >>> b = Book.objects.get(id=4) # No select_related() in this example.
- >>> p = b.author # Hits the database.
- >>> c = p.hometown # Hits the database.
-
-Note that ``select_related()`` does not follow foreign keys that have
-``null=True``.
-
-Usually, using ``select_related()`` can vastly improve performance because your
-application can avoid many database calls. However, in situations with deeply nested
-sets of relationships, ``select_related()`` can sometimes end up following "too
-many" relations and can generate queries so large that they end up being slow.
-
-extra()
-~~~~~~~
-
-Sometimes, the Django query syntax by itself can't easily express a complex
-``WHERE`` clause. For these edge cases, Django provides the ``extra()``
-``QuerySet`` modifier -- a hook for injecting specific clauses into the SQL
-generated by a ``QuerySet``.
-
-By definition, these extra lookups may not be portable to different database
-engines (because you're explicitly writing SQL code) and violate the DRY
-principle, so you should avoid them if possible.
-
-Specify one or more of ``params``, ``select``, ``where``, or ``tables``. None
-of the arguments is required, but you should use at least one of them.
-
-The ``select`` argument lets you put extra fields in the ``SELECT`` clause.
-It should be a dictionary mapping attribute names to SQL clauses to use to
-calculate that attribute::
-
- >>> Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
-
-As a result, each ``Entry`` object will have an extra attribute,
-``is_recent``, a Boolean representing whether the entry's ``pub_date`` is
-greater than January 1, 2006.
-
-The next example is more advanced; it does a subquery to give each
-resulting ``Blog`` object an ``entry_count`` attribute, an integer count
-of associated ``Entry`` objects::
-
- >>> subq = 'SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id'
- >>> Blog.objects.extra(select={'entry_count': subq})
-
-(In this particular case, we're exploiting the fact that the query will already
-contain the ``blog_blog`` table in its ``FROM`` clause.)
-
-You can define explicit SQL ``WHERE`` clauses -- perhaps to perform
-nonexplicit joins -- by using ``where``. You can manually add tables to
-the SQL ``FROM`` clause by using ``tables``.
-
-``where`` and ``tables`` both take a list of strings. All ``where``
-parameters are ANDed to any other search criteria::
-
- >>> Entry.objects.extra(where=['id IN (3, 4, 5, 20)'])
-
-The ``select`` and ``where`` parameters described previously may use standard
-Python database string placeholders: ``'%s'`` to indicate parameters the
-database engine should automatically quote. The ``params`` argument is a
-list of any extra parameters to be substituted::
-
- >>> Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
-
-Always use ``params`` instead of embedding values directly into ``select``
-or ``where`` because ``params`` will ensure values are quoted correctly
-according to your particular database.
-
-Here's an example of the wrong way::
-
- Entry.objects.extra(where=["headline='%s'" % name])
-
-Here's an example of the correct way::
-
- Entry.objects.extra(where=['headline=%s'], params=[name])
-
-QuerySet Methods That Do Not Return QuerySets
----------------------------------------------
-
-The following ``QuerySet`` methods evaluate the ``QuerySet`` and return
-something *other than* a ``QuerySet`` -- a single object, value, and so forth.
-
-get(\*\*lookup)
-~~~~~~~~~~~~~~~
-
-Returns the object matching the given lookup parameters, which should be in the
-format described in the "Field Lookups" section. This raises ``AssertionError`` if
-more than one object was found.
-
-``get()`` raises a ``DoesNotExist`` exception if an object wasn't found for the
-given parameters. The ``DoesNotExist`` exception is an attribute of the model
-class, for example::
-
- >>> Entry.objects.get(id='foo') # raises Entry.DoesNotExist
-
-The ``DoesNotExist`` exception inherits from
-``django.core.exceptions.ObjectDoesNotExist``, so you can target multiple
-``DoesNotExist`` exceptions::
-
- >>> from django.core.exceptions import ObjectDoesNotExist
- >>> try:
- ... e = Entry.objects.get(id=3)
- ... b = Blog.objects.get(id=1)
- ... except ObjectDoesNotExist:
- ... print "Either the entry or blog doesn't exist."
-
-create(\*\*kwargs)
-~~~~~~~~~~~~~~~~~~
-
-This is a convenience method for creating an object and saving it all in one step.
-It lets you compress two common steps::
-
- >>> p = Person(first_name="Bruce", last_name="Springsteen")
- >>> p.save()
-
-into a single line::
-
- >>> p = Person.objects.create(first_name="Bruce", last_name="Springsteen")
+Archive Index
+-------------
-get_or_create(\*\*kwargs)
-~~~~~~~~~~~~~~~~~~~~~~~~~
+*View function*: ``django.views.generic.date_based.archive_index``
-This is a convenience method for looking up an object and creating one if it doesn't
-exist. It returns a tuple of ``(object, created)``, where ``object`` is the retrieved or
-created object and ``created`` is a Boolean specifying whether a new object was
-created.
+This view provides a top-level index page showing the "latest" (i.e., most
+recent) objects by date.
-This method is meant as a shortcut to boilerplate code and is mostly useful for
-data-import scripts, for example::
+Example
+```````
- try:
- obj = Person.objects.get(first_name='John', last_name='Lennon')
- except Person.DoesNotExist:
- obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
- obj.save()
+Say a typical book publisher wants a page of recently published books. Given some
+``Book`` object with a ``publication_date`` field, we can use the
+``archive_index`` view for this common task:
-This pattern gets quite unwieldy as the number of fields in a model increases. The
-previous example can be rewritten using ``get_or_create()`` like so::
+.. parsed-literal::
- obj, created = Person.objects.get_or_create(
- first_name = 'John',
- last_name = 'Lennon',
- defaults = {'birthday': date(1940, 10, 9)}
- )
+ from mysite.books.models import Book
+ from django.conf.urls.defaults import *
+ from django.views.generic import date_based
-Any keyword arguments passed to ``get_or_create()`` -- *except* an optional one
-called ``defaults`` -- will be used in a ``get()`` call. If an object is found,
-``get_or_create()`` returns a tuple of that object and ``False``. If an object
-is *not* found, ``get_or_create()`` will instantiate and save a new object,
-returning a tuple of the new object and ``True``. The new object will be created
-according to this algorithm::
-
- defaults = kwargs.pop('defaults', {})
- params = dict([(k, v) for k, v in kwargs.items() if '__' not in k])
- params.update(defaults)
- obj = self.model(**params)
- obj.save()
-
-In English, that means start with any non-``'defaults'`` keyword argument that
-doesn't contain a double underscore (which would indicate a nonexact lookup).
-Then add the contents of ``defaults``, overriding any keys if necessary, and
-use the result as the keyword arguments to the model class.
-
-If you have a field named ``defaults`` and want to use it as an exact lookup in
-``get_or_create()``, just use ``'defaults__exact'`` like so::
-
- Foo.objects.get_or_create(
- defaults__exact = 'bar',
- defaults={'defaults': 'baz'}
+ book_info = {
+ "queryset" : Book.objects.all(),
+ "date_field" : "publication_date"
+ }
+
+ urlpatterns = patterns('',
+ (r'^books/$', date_based.archive_index, book_info),
)
-.. note::
-
- As mentioned earlier, ``get_or_create()`` is mostly useful in scripts that
- need to parse data and create new records if existing ones aren't available.
- But if you need to use ``get_or_create()`` in a view, please make sure to
- use it only in ``POST`` requests unless you have a good reason not to.
- ``GET`` requests shouldn't have any effect on data; use ``POST`` whenever a
- request to a page has a side effect on your data.
-
-count()
-~~~~~~~
-
-Returns an integer representing the number of objects in the database matching
-the ``QuerySet``. ``count()`` never raises exceptions. Here's an example::
-
- # Returns the total number of entries in the database.
- >>> Entry.objects.count()
- 4
-
- # Returns the number of entries whose headline contains 'Lennon'
- >>> Entry.objects.filter(headline__contains='Lennon').count()
- 1
-
-``count()`` performs a ``SELECT COUNT(*)`` behind the scenes, so you should
-always use ``count()`` rather than loading all of the records into Python objects
-and calling ``len()`` on the result.
-
-Depending on which database you're using (e.g., PostgreSQL or MySQL),
-``count()`` may return a long integer instead of a normal Python integer. This
-is an underlying implementation quirk that shouldn't pose any real-world
-problems.
-
-in_bulk(id_list)
-~~~~~~~~~~~~~~~~
-
-Takes a list of primary key values and returns a dictionary mapping each
-primary key value to an instance of the object with the given ID, for example::
-
- >>> Blog.objects.in_bulk([1])
- {1: Beatles Blog}
- >>> Blog.objects.in_bulk([1, 2])
- {1: Beatles Blog, 2: Cheddar Talk}
- >>> Blog.objects.in_bulk([])
- {}
-
-IDs of objects that don't exist are silently dropped from the result dictionary.
-If you pass ``in_bulk()`` an empty list, you'll get an empty dictionary.
-
-latest(field_name=None)
-~~~~~~~~~~~~~~~~~~~~~~~
-
-Returns the latest object in the table, by date, using the ``field_name``
-provided as the date field. This example returns the latest ``Entry`` in the
-table, according to the ``pub_date`` field::
-
- >>> Entry.objects.latest('pub_date')
-
-If your model's ``Meta`` specifies ``get_latest_by``, you can leave off the
-``field_name`` argument to ``latest()``. Django will use the field specified in
-``get_latest_by`` by default.
-
-Like ``get()``, ``latest()`` raises ``DoesNotExist`` if an object doesn't exist
-with the given parameters.
-
-Field Lookups
-=============
-
-Field lookups are how you specify the meat of an SQL ``WHERE`` clause. They're
-specified as keyword arguments to the ``QuerySet`` methods ``filter()``,
-``exclude()``, and ``get()``.
-
-Basic lookup keyword arguments take the form ``field__lookuptype=value``
-(note the double underscore). For example::
-
- >>> Entry.objects.filter(pub_date__lte='2006-01-01')
-
-translates (roughly) into the following SQL::
-
- SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01';
-
-If you pass an invalid keyword argument, a lookup function will raise
-``TypeError``.
-
-The supported lookup types follow.
+Required Arguments
+``````````````````
-exact
------
+ * ``date_field``: The name of the ``DateField`` or ``DateTimeField`` in the
+ ``QuerySet``'s model that the date-based archive should use to determine
+ the objects on the page.
-Performs an exact match::
+ * ``queryset``: A ``QuerySet`` of objects for which the archive serves.
- >>> Entry.objects.get(headline__exact="Man bites dog")
+Optional Arguments
+``````````````````
-This matches any object with the exact headline "Man bites dog".
+ * ``allow_future``: A Boolean specifying whether to include "future" objects
+ on this page, as described in the previous note.
-If you don't provide a lookup type -- that is, if your keyword argument doesn't
-contain a double underscore -- the lookup type is assumed to be ``exact``.
+ * ``num_latest``: The number of latest objects to send to the template
+ context. By default, it's 15.
-For example, the following two statements are equivalent::
+This view may also take these common arguments (see Table C-1):
- >>> Blog.objects.get(id__exact=14) # Explicit form
- >>> Blog.objects.get(id=14) # __exact is implied
-
-This is for convenience, because ``exact`` lookups are the common case.
-
-iexact
-------
-
-Performs a case-insensitive exact match::
-
- >>> Blog.objects.get(name__iexact='beatles blog')
-
-This will match ``'Beatles Blog'``, ``'beatles blog'``,
-``'BeAtLes BLoG'``, and so forth.
-
-contains
---------
-
-Performs a case-sensitive containment test::
-
- Entry.objects.get(headline__contains='Lennon')
-
-This will match the headline ``'Today Lennon honored'`` but not
-``'today lennon honored'``.
-
-SQLite doesn't support case-sensitive ``LIKE`` statements; when using
-SQLite,``contains`` acts like ``icontains``.
-
-.. admonition:: Escaping Percent Signs and Underscores in LIKE Statements
-
- The field lookups that equate to ``LIKE`` SQL statements (``iexact``,
- ``contains``, ``icontains``, ``startswith``, ``istartswith``, ``endswith``,
- and ``iendswith``) will automatically escape the two special characters used in
- ``LIKE`` statements -- the percent sign and the underscore. (In a ``LIKE``
- statement, the percent sign signifies a multiple-character wildcard and the
- underscore signifies a single-character wildcard.)
-
- This means things should work intuitively, so the abstraction doesn't leak.
- For example, to retrieve all the entries that contain a percent sign, just use
- the percent sign as any other character::
-
- Entry.objects.filter(headline__contains='%')
-
- Django takes care of the quoting for you. The resulting SQL will look something
- like this::
-
- SELECT ... WHERE headline LIKE '%\%%';
-
- The same goes for underscores. Both percentage signs and underscores are handled
- for you transparently.
-
-icontains
----------
-
-Performs a case-insensitive containment test::
+ * ``allow_empty``
+ * ``context_processors``
+ * ``extra_context``
+ * ``mimetype``
+ * ``template_loader``
+ * ``template_name``
+
+Template Name
+`````````````
- >>> Entry.objects.get(headline__icontains='Lennon')
+If ``template_name`` isn't specified, this view will use the template
+``<app_label>/<model_name>_archive.html`` by default.
-Unlike ``contains``, ``icontains`` *will* match ``'today lennon honored'``.
+Template Context
+````````````````
-gt, gte, lt, and lte
---------------------
+In addition to ``extra_context``, the template's context will be as follows:
-These represent greater than, greater than or equal to, less than, and less
-than or equal to::
+ * ``date_list``: A list of ``datetime.date`` objects representing all years
+ that have objects available according to ``queryset``. These are ordered
+ in reverse.
+
+ For example, if you have blog entries from 2003 through 2006, this list
+ will contain four ``datetime.date`` objects: one for each of those years.
+
+ * ``latest``: The ``num_latest`` objects in the system, in descending order
+ by ``date_field``. For example, if ``num_latest`` is ``10``, then
+ ``latest`` will be a list of the latest ten objects in ``queryset``.