summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/add_ons.txt45
-rw-r--r--docs/authentication.txt54
-rw-r--r--docs/db-api.txt2
-rw-r--r--docs/django-admin.txt49
-rw-r--r--docs/generic_views.txt97
-rw-r--r--docs/i18n.txt11
-rw-r--r--docs/install.txt14
-rw-r--r--docs/middleware.txt8
-rw-r--r--docs/model-api.txt106
-rw-r--r--docs/settings.txt78
-rw-r--r--docs/sites.txt311
-rw-r--r--docs/templates_python.txt196
-rw-r--r--docs/tutorial01.txt32
13 files changed, 915 insertions, 88 deletions
diff --git a/docs/add_ons.txt b/docs/add_ons.txt
index 28df4f55b6..f7b3056ef0 100644
--- a/docs/add_ons.txt
+++ b/docs/add_ons.txt
@@ -16,11 +16,35 @@ The automatic Django administrative interface. For more information, see
.. _Tutorial 2: http://www.djangoproject.com/documentation/tutorial2/
+auth
+====
+
+Django's authentication framework.
+
+See the `authentication documentation`_.
+
+.. _authentication documentation: http://www.djangoproject.com/documentation/authentication/
+
comments
========
A simple yet flexible comments system. This is not yet documented.
+contenttypes
+============
+
+A light framework for hooking into "types" of content, where each installed
+Django model is a separate content type. This is not yet documented.
+
+csrf
+====
+
+A middleware for preventing Cross Site Request Forgeries
+
+See the `csrf documentation`_.
+
+.. _csrf documentation: http://www.djangoproject.com/documentation/csrf/
+
flatpages
=========
@@ -48,6 +72,17 @@ See the `redirects documentation`_.
.. _redirects documentation: http://www.djangoproject.com/documentation/redirects/
+sites
+=====
+
+A light framework that lets you operate multiple Web sites off of the same
+database and Django installation. It gives you hooks for associating objects to
+one or more sites.
+
+See the `sites documentation`_.
+
+.. _sites documentation: http://www.djangoproject.com/documentation/sites/
+
syndication
===========
@@ -57,16 +92,6 @@ See the `syndication documentation`_.
.. _syndication documentation: http://www.djangoproject.com/documentation/syndication/
-csrf
-====
-
-A middleware for preventing Cross Site Request Forgeries
-
-See the `csrf documentation`_.
-
-.. _csrf documentation: http://www.djangoproject.com/documentation/csrf/
-
-
Other add-ons
=============
diff --git a/docs/authentication.txt b/docs/authentication.txt
index 8e416c3e9e..1be64c045a 100644
--- a/docs/authentication.txt
+++ b/docs/authentication.txt
@@ -338,6 +338,60 @@ introduced in Python 2.4::
* If the user is logged in, execute the view normally. The view code is
free to assume the user is logged in.
+Note that you'll need to map the appropriate Django view to ``/accounts/login/``.
+To do this, add the following line to your URLconf::
+
+ (r'^accounts/login/$', 'django.contrib.auth.views.login'),
+
+Here's what ``django.contrib.auth.views.login`` does::
+
+ * If called via ``GET``, it displays a login form that POSTs to the same
+ URL. More on this in a bit.
+
+ * If called via ``POST``, it tries to log the user in. If login is
+ successful, the view redirects to the URL specified in ``next``. If
+ ``next`` isn't provided, it redirects to ``/accounts/profile/`` (which is
+ currently hard-coded). If login isn't successful, it redisplays the login
+ form.
+
+It's your responsibility to provide the login form in a template called
+``registration/login.html``. This template gets passed three template context
+variables:
+
+ * ``form``: A ``FormWrapper`` object representing the login form. See the
+ `forms documentation`_ for more on ``FormWrapper`` objects.
+ * ``next``: The URL to redirect to after successful login. This may contain
+ a query string, too.
+ * ``site_name``: The name of the current ``Site``, according to the
+ ``SITE_ID`` setting. See the `site framework docs`_.
+
+Here's a sample ``registration/login.html`` template you can use as a starting
+point. It assumes you have a ``base.html`` template that defines a ``content``
+block::
+
+ {% extends "base.html" %}
+
+ {% block content %}
+
+ {% if form.has_errors %}
+ <p>Your username and password didn't match. Please try again.</p>
+ {% endif %}
+
+ <form method="post" action=".">
+ <table>
+ <tr><td><label for="id_username">Username:</label></td><td>{{ form.username }}</td></tr>
+ <tr><td><label for="id_password">Password:</label></td><td>{{ form.password }}</td></tr>
+ </table>
+
+ <input type="submit" value="login" />
+ <input type="hidden" name="next" value="{{ next }}" />
+ </form>
+
+ {% endblock %}
+
+.. _forms documentation: http://www.djangoproject.com/documentation/forms/
+.. _site framework docs: http://www.djangoproject.com/documentation/sites/
+
Limiting access to logged-in users that pass a test
---------------------------------------------------
diff --git a/docs/db-api.txt b/docs/db-api.txt
index e2173afe16..4442a75125 100644
--- a/docs/db-api.txt
+++ b/docs/db-api.txt
@@ -345,7 +345,7 @@ This is roughly equivalent to::
Entry.objects.order_by('headline')[0:1].get()
-Note, however, that the first of these will raise ``IndexError`` while the
+Note, however, that the first of these will raise ``IndexError`` while the
second will raise ``DoesNotExist`` if no objects match the given criteria.
QuerySet methods that return new QuerySets
diff --git a/docs/django-admin.txt b/docs/django-admin.txt
index b314366fee..90f5f5e4ed 100644
--- a/docs/django-admin.txt
+++ b/docs/django-admin.txt
@@ -177,6 +177,16 @@ Port 7000 on IP address 1.2.3.4::
django-admin.py runserver 1.2.3.4:7000
+Serving static files with the development server
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+By default, the development server doesn't serve any static files for your site
+(such as CSS files, images, things under ``MEDIA_ROOT_URL`` and so forth). If
+you want to configure Django to serve static media, read the `serving static files`_
+documentation.
+
+.. _serving static files: http://www.djangoproject.com/documentation/static_files/
+
shell
-----
@@ -200,6 +210,9 @@ sqlall [appname appname ...]
Prints the CREATE TABLE and initial-data SQL statements for the given appnames.
+Refer to the description of ``sqlinitialdata`` for an explanation of how to
+specify initial data.
+
sqlclear [appname appname ...]
--------------------------------------
@@ -215,6 +228,18 @@ sqlinitialdata [appname appname ...]
Prints the initial INSERT SQL statements for the given appnames.
+For each model in each specified app, this command looks for the file
+``<appname>/sql/<modelname>.sql``, where ``<appname>`` is the given appname and
+``<modelname>`` is the model's name in lowercase. For example, if you have an
+app ``news`` that includes a ``Story`` model, ``sqlinitialdata`` will attempt
+to read a file ``news/sql/story.sql`` and append it to the output of this
+command.
+
+Each of the SQL files, if given, is expected to contain valid SQL. The SQL
+files are piped directly into the database after all of the models'
+table-creation statements have been executed. Use this SQL hook to populate
+tables with any necessary initial records, SQL functions or test data.
+
sqlreset [appname appname ...]
--------------------------------------
@@ -240,6 +265,20 @@ startproject [projectname]
Creates a Django project directory structure for the given project name in the
current directory.
+syncdb
+------
+
+Creates the database tables for all apps in ``INSTALLED_APPS`` whose tables
+have not already been created.
+
+Use this command when you've added new applications to your project and want to
+install them in the database. This includes any apps shipped with Django that
+might be in ``INSTALLED_APPS`` by default. When you start a new project, run
+this command to install the default apps.
+
+If you're installing the ``django.contrib.auth`` application, ``syncdb`` will
+give you the option of creating a superuser immediately.
+
validate
--------
@@ -286,6 +325,16 @@ setting the Python path for you.
Displays a help message that includes a terse list of all available actions and
options.
+--version
+---------
+
+Displays the current Django version.
+
+Example output::
+
+ 0.9.1
+ 0.9.1 (SVN)
+
Extra niceties
==============
diff --git a/docs/generic_views.txt b/docs/generic_views.txt
index 597ef96104..5b978af1de 100644
--- a/docs/generic_views.txt
+++ b/docs/generic_views.txt
@@ -62,6 +62,15 @@ Most generic views require the ``queryset`` key, which is a ``QuerySet``
instance; see the `database API docs`_ for more information about ``Queryset``
objects.
+Most views also take an optional ``extra_context`` dictionary that you can use
+to pass any auxiliary information you wish to the view. The values in the
+``extra_context`` dictionary can be either functions (or other callables) or
+other objects. Functions are evaluated just before they are passed to the
+template. However, note that QuerySets retrieve and cache their data when they
+are first evaluated, so if you want to pass in a QuerySet via
+``extra_context`` that is always fresh you need to wrap it in a function or
+lambda that returns the QuerySet.
+
.. _database API docs: http://www.djangoproject.com/documentation/db_api/
"Simple" generic views
@@ -160,10 +169,10 @@ a date in the *future* are not included.
* ``template_loader``: The template loader to use when loading the
template. By default, it's ``django.template.loader``.
- * ``extra_context``: A dictionary of values to add to the template context.
- If a value in the dictionary is callable, the generic view will call it
- just before rendering the template. By default, this is an empty
- dictionary.
+ * ``extra_context``: A dictionary of values to add to the template
+ context. By default, this is an empty dictionary.
+ dictionary is callable, the generic view will call it
+ just before rendering the template.
* ``allow_empty``: A boolean specifying whether to display the page if no
objects are available. If this is ``False`` and no objects are available,
@@ -225,10 +234,10 @@ with a date in the *future* are not displayed.
* ``template_loader``: The template loader to use when loading the
template. By default, it's ``django.template.loader``.
- * ``extra_context``: A dictionary of values to add to the template context.
- If a value in the dictionary is callable, the generic view will call it
- just before rendering the template. By default, this is an empty
- dictionary.
+ * ``extra_context``: A dictionary of values to add to the template
+ context. By default, this is an empty dictionary. If a value in the
+ dictionary is callable, the generic view will call it
+ just before rendering the template.
* ``allow_empty``: A boolean specifying whether to display the page if no
objects are available. If this is ``False`` and no objects are available,
@@ -287,10 +296,10 @@ date in the *future* are not displayed.
* ``template_loader``: The template loader to use when loading the
template. By default, it's ``django.template.loader``.
- * ``extra_context``: A dictionary of values to add to the template context.
- If a value in the dictionary is callable, the generic view will call it
- just before rendering the template. By default, this is an empty
- dictionary.
+ * ``extra_context``: A dictionary of values to add to the template
+ context. By default, this is an empty dictionary. If a value in the
+ dictionary is callable, the generic view will call it
+ just before rendering the template.
* ``allow_empty``: A boolean specifying whether to display the page if no
objects are available. If this is ``False`` and no objects are available,
@@ -360,10 +369,10 @@ in the *future* are not displayed.
* ``template_loader``: The template loader to use when loading the
template. By default, it's ``django.template.loader``.
- * ``extra_context``: A dictionary of values to add to the template context.
- If a value in the dictionary is callable, the generic view will call it
- just before rendering the template. By default, this is an empty
- dictionary.
+ * ``extra_context``: A dictionary of values to add to the template
+ context. By default, this is an empty dictionary. If a value in the
+ dictionary is callable, the generic view will call it
+ just before rendering the template.
* ``allow_empty``: A boolean specifying whether to display the page if no
objects are available. If this is ``False`` and no objects are available,
@@ -436,10 +445,10 @@ a 404 error, regardless of whether any objects exist for future days.
* ``template_loader``: The template loader to use when loading the
template. By default, it's ``django.template.loader``.
- * ``extra_context``: A dictionary of values to add to the template context.
- If a value in the dictionary is callable, the generic view will call it
- just before rendering the template. By default, this is an empty
- dictionary.
+ * ``extra_context``: A dictionary of values to add to the template
+ context. By default, this is an empty dictionary. If a value in the
+ dictionary is callable, the generic view will call it
+ just before rendering the template.
* ``allow_empty``: A boolean specifying whether to display the page if no
objects are available. If this is ``False`` and no objects are available,
@@ -543,10 +552,10 @@ A page representing an individual object.
* ``template_loader``: The template loader to use when loading the
template. By default, it's ``django.template.loader``.
- * ``extra_context``: A dictionary of values to add to the template context.
- If a value in the dictionary is callable, the generic view will call it
- just before rendering the template. By default, this is an empty
- dictionary.
+ * ``extra_context``: A dictionary of values to add to the template
+ context. By default, this is an empty dictionary. If a value in the
+ dictionary is callable, the generic view will call it
+ just before rendering the template.
* ``context_processors``: A list of template-context processors to apply to
the view's template. See the `RequestContext docs`_.
@@ -600,10 +609,10 @@ A page representing a list of objects.
* ``template_loader``: The template loader to use when loading the
template. By default, it's ``django.template.loader``.
- * ``extra_context``: A dictionary of values to add to the template context.
- If a value in the dictionary is callable, the generic view will call it
- just before rendering the template. By default, this is an empty
- dictionary.
+ * ``extra_context``: A dictionary of values to add to the template
+ context. By default, this is an empty dictionary. If a value in the
+ dictionary is callable, the generic view will call it
+ just before rendering the template.
* ``allow_empty``: A boolean specifying whether to display the page if no
objects are available. If this is ``False`` and no objects are available,
@@ -697,10 +706,10 @@ A page representing an individual object.
* ``template_loader``: The template loader to use when loading the
template. By default, it's ``django.template.loader``.
- * ``extra_context``: A dictionary of values to add to the template context.
- If a value in the dictionary is callable, the generic view will call it
- just before rendering the template. By default, this is an empty
- dictionary.
+ * ``extra_context``: A dictionary of values to add to the template
+ context. By default, this is an empty dictionary. If a value in the
+ dictionary is callable, the generic view will call it
+ just before rendering the template.
* ``context_processors``: A list of template-context processors to apply to
the view's template. See the `RequestContext docs`_.
@@ -764,10 +773,10 @@ automatic manipulators that come with Django models.
* ``template_loader``: The template loader to use when loading the
template. By default, it's ``django.template.loader``.
- * ``extra_context``: A dictionary of values to add to the template context.
- If a value in the dictionary is callable, the generic view will call it
- just before rendering the template. By default, this is an empty
- dictionary.
+ * ``extra_context``: A dictionary of values to add to the template
+ context. By default, this is an empty dictionary. If a value in the
+ dictionary is callable, the generic view will call it
+ just before rendering the template.
* ``context_processors``: A list of template-context processors to apply to
the view's template. See the `RequestContext docs`_.
@@ -843,10 +852,10 @@ object. This uses the automatic manipulators that come with Django models.
* ``template_loader``: The template loader to use when loading the
template. By default, it's ``django.template.loader``.
- * ``extra_context``: A dictionary of values to add to the template context.
- If a value in the dictionary is callable, the generic view will call it
- just before rendering the template. By default, this is an empty
- dictionary.
+ * ``extra_context``: A dictionary of values to add to the template
+ context. By default, this is an empty dictionary. If a value in the
+ dictionary is callable, the generic view will call it
+ just before rendering the template.
* ``context_processors``: A list of template-context processors to apply to
the view's template. See the `RequestContext docs`_.
@@ -924,10 +933,10 @@ contain a form that POSTs to the same URL.
* ``template_loader``: The template loader to use when loading the
template. By default, it's ``django.template.loader``.
- * ``extra_context``: A dictionary of values to add to the template context.
- If a value in the dictionary is callable, the generic view will call it
- just before rendering the template. By default, this is an empty
- dictionary.
+ * ``extra_context``: A dictionary of values to add to the template
+ context. By default, this is an empty dictionary. If a value in the
+ dictionary is callable, the generic view will call it
+ just before rendering the template.
* ``context_processors``: A list of template-context processors to apply to
the view's template. See the `RequestContext docs`_.
diff --git a/docs/i18n.txt b/docs/i18n.txt
index 9199a74295..e6660f939d 100644
--- a/docs/i18n.txt
+++ b/docs/i18n.txt
@@ -540,6 +540,17 @@ you can override base translations in your project path. Or, you can just build
a big project out of several apps and put all translations into one big project
message file. The choice is yours.
+.. note::
+
+ If you're using manually configured settings, as described in the
+ `settings documentation`_, the ``locale`` directory in the project
+ directory will not be examined, since Django loses the ability to work out
+ the location of the project directory. (Django normally uses the location
+ of the settings file to determine this, and a settings file doesn't exist
+ if you're manually configuring your settings.)
+
+.. _settings documentation: http://www.djangoproject.com/documentation/settings/#using-settings-without-the-django-settings-module-environment-variable
+
All message file repositories are structured the same way. They are:
* ``$APPPATH/locale/<language>/LC_MESSAGES/django.(po|mo)``
diff --git a/docs/install.txt b/docs/install.txt
index 51746e001d..800c49b596 100644
--- a/docs/install.txt
+++ b/docs/install.txt
@@ -77,9 +77,9 @@ It's easy either way.
Installing the official version
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-1. Download Django-0.92.tar.gz from our `download page`_.
-2. ``tar xzvf Django-0.92.tar.gz``
-3. ``cd Django-0.92``
+1. Download Django-0.91.tar.gz from our `download page`_.
+2. ``tar xzvf Django-0.91.tar.gz``
+3. ``cd Django-0.91``
4. ``sudo python setup.py install``
Note that the last command will automatically download and install setuptools_
@@ -89,6 +89,14 @@ connection.
This will install Django in your Python installation's ``site-packages``
directory.
+.. note::
+
+ Due to recent backwards-incompatible changes, it is strongly recommended
+ that you use the development version (below) for any new applications or
+ if you are just starting to work with Django. The 0.91 release is a
+ dead-end branch that is primarily of use for supporting legacy Django
+ applications.
+
.. _setuptools: http://peak.telecommunity.com/DevCenter/setuptools
Installing the development version
diff --git a/docs/middleware.txt b/docs/middleware.txt
index 7dfa0f3af7..f3dbcb82d1 100644
--- a/docs/middleware.txt
+++ b/docs/middleware.txt
@@ -59,8 +59,12 @@ Adds a few conveniences for perfectionists:
* Performs URL rewriting based on the ``APPEND_SLASH`` and ``PREPEND_WWW``
settings. If ``APPEND_SLASH`` is ``True``, URLs that lack a trailing
- slash will be redirected to the same URL with a trailing slash. If
- ``PREPEND_WWW`` is ``True``, URLs that lack a leading "www." will be
+ slash will be redirected to the same URL with a trailing slash, unless the
+ last component in the path contains a period. So ``foo.com/bar`` is
+ redirected to ``foo.com/bar/``, but ``foo.com/bar/file.txt`` is passed
+ through unchanged.
+
+ If ``PREPEND_WWW`` is ``True``, URLs that lack a leading "www." will be
redirected to the same URL with a leading "www."
Both of these options are meant to normalize URLs. The philosophy is that
diff --git a/docs/model-api.txt b/docs/model-api.txt
index 6d6249ee88..3e40a6f63f 100644
--- a/docs/model-api.txt
+++ b/docs/model-api.txt
@@ -202,22 +202,22 @@ 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.
+ 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.
+ 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 must likely want to use the
- convenience ``get_<fieldname>_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.get_mug_shot_url }}``.
+ (relative to ``MEDIA_ROOT``). You'll must likely want to use the
+ convenience ``get_<fieldname>_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.get_mug_shot_url }}``.
.. _`strftime formatting`: http://docs.python.org/lib/module-time.html#l2h-1941
@@ -1599,6 +1599,39 @@ API. See `Other lookup options`_.
.. _Python DB-API: http://www.python.org/peps/pep-0249.html
.. _Other lookup options: http://www.djangoproject.com/documentation/db_api/#extra-params-select-where-tables
+Overriding default model methods
+--------------------------------
+
+As explained in the `database API docs`_, each model gets a few methods
+automatically -- most notably, ``save()`` and ``delete()``. You can override
+these methods to alter behavior.
+
+A classic use-case for overriding the built-in methods is if you want something
+to happen whenever you save an object. For example::
+
+ class Blog(models.Model):
+ name = models.CharField(maxlength=100)
+ tagline = models.TextField()
+
+ def save(self):
+ do_something()
+ super(Blog, self).save() # Call the "real" save() method.
+ do_something_else()
+
+You can also prevent saving::
+
+ class Blog(models.Model):
+ name = models.CharField(maxlength=100)
+ tagline = models.TextField()
+
+ def save(self):
+ if self.name == "Yoko Ono's blog":
+ return # Yoko shall never have her own blog!
+ else:
+ super(Blog, self).save() # Call the "real" save() method.
+
+.. _database API docs: http://www.djangoproject.com/documentation/db_api/
+
Models across files
===================
@@ -1631,3 +1664,52 @@ read, in part::
'mysite.myapp',
#...
)
+
+Providing initial SQL data
+==========================
+
+Django provides a hook for passing the database arbitrary SQL that's executed
+just after the CREATE TABLE statements. Use this hook, for example, if you want
+to populate default records, or create SQL functions, automatically.
+
+The hook is simple: Django just looks for a file called
+``<appname>/sql/<modelname>.sql``, where ``<appname>`` is your app directory and
+``<modelname>`` is the model's name in lowercase.
+
+In the ``Person`` example model at the top of this document, assuming it lives
+in an app called ``myapp``, you could add arbitrary SQL to the file
+``myapp/sql/person.sql``. Here's an example of what the file might contain::
+
+ INSERT INTO myapp_person (first_name, last_name) VALUES ('John', 'Lennon');
+ INSERT INTO myapp_person (first_name, last_name) VALUES ('Paul', 'McCartney');
+
+Each SQL file, if given, is expected to contain valid SQL. The SQL files are
+piped directly into the database after all of the models' table-creation
+statements have been executed.
+
+The SQL files are read by the ``sqlinitialdata``, ``sqlreset``, ``sqlall`` and
+``reset`` commands in ``manage.py``. Refer to the `manage.py documentation`_
+for more information.
+
+Note that if you have multiple SQL data files, there's no guarantee of the
+order in which they're executed. The only thing you can assume is that, by the
+time your custom data files are executed, all the database tables already will
+have been created.
+
+.. _`manage.py documentation`: http://www.djangoproject.com/documentation/django_admin/#sqlinitialdata-appname-appname
+
+Database-backend-specific SQL data
+----------------------------------
+
+There's also a hook for backend-specific SQL data. For example, you can have
+separate initial-data files for PostgreSQL and MySQL. For each app, Django
+looks for a file called ``<appname>/sql/<modelname>.<backend>.sql``, where
+``<appname>`` is your app directory, ``<modelname>`` is the model's name in
+lowercase and ``<backend>`` is the value of ``DATABASE_ENGINE`` in your
+settings file (e.g., ``postgresql``, ``mysql``).
+
+Backend-specific SQL data is executed before non-backend-specific SQL data. For
+example, if your app contains the files ``sql/person.sql`` and
+``sql/person.postgresql.sql`` and you're installing the app on PostgreSQL,
+Django will execute the contents of ``sql/person.postgresql.sql`` first, then
+``sql/person.sql``.
diff --git a/docs/settings.txt b/docs/settings.txt
index d4666468fc..80000fad5b 100644
--- a/docs/settings.txt
+++ b/docs/settings.txt
@@ -619,6 +619,10 @@ The ID, as an integer, of the current site in the ``django_site`` database
table. This is used so that application data can hook into specific site(s)
and a single database can manage content for multiple sites.
+See the `site framework docs`_.
+
+.. _site framework docs: http://www.djangoproject.com/documentation/sites/
+
TEMPLATE_CONTEXT_PROCESSORS
---------------------------
@@ -724,3 +728,77 @@ Django apps. Just follow these conventions:
* For settings that are sequences, use tuples instead of lists. This is
purely for performance.
* Don't reinvent an already-existing setting.
+
+Using settings without setting DJANGO_SETTINGS_MODULE
+=====================================================
+
+In some cases, you might want to bypass the ``DJANGO_SETTINGS_MODULE``
+environment variable. For example, if you're using the template system by
+itself, you likely don't want to have to set up an environment variable
+pointing to a settings module.
+
+In these cases, you can configure Django's settings manually. Do this by
+calling ``django.conf.settings.configure()``.
+
+Example::
+
+ from django.conf import settings
+
+ settings.configure(DEBUG=True, TEMPLATE_DEBUG=True,
+ TEMPLATE_DIRS=('/home/web-apps/myapp', '/home/web-apps/base'))
+
+Pass ``configure()`` as many keyword arguments as you'd like, with each keyword
+argument representing a setting and its value. Each argument name should be all
+uppercase, with the same name as the settings described above. If a particular
+setting is not passed to ``configure()`` and is needed at some later point,
+Django will use the default setting value.
+
+Custom default settings
+-----------------------
+
+If you'd like default values to come from somewhere other than
+``django.conf.global_settings``, you can pass in a module or class that
+provides the default settings as the ``default_settings`` argument (or as the
+first positional argument) in the call to ``configure()``.
+
+In this example, default settings are taken from ``myapp_defaults``, and the
+``DEBUG`` setting is set to ``True``, regardless of its value in
+``myapp_defaults``::
+
+ from django.conf import settings
+ from myapp import myapp_defaults
+
+ settings.configure(default_settings=myapp_defaults, DEBUG=True)
+
+The following example, which uses ``myapp_defaults`` as a positional argument,
+is equivalent::
+
+ settings.configure(myapp_defaults, DEBUG = True)
+
+Normally, you will not need to override the defaults in this fashion. The
+Django defaults are sufficiently tame that you can safely use them. Be aware
+that if you do pass in a new default module, it entirely *replaces* the Django
+defaults, so you must specify a value for every possible setting that might be
+used in that code you are importing. Check in
+``django.conf.settings.global_settings`` for the full list.
+
+Either configure() or DJANGO_SETTINGS_MODULE is required
+--------------------------------------------------------
+
+If you're not setting the ``DJANGO_SETTINGS_MODULE`` environment variable, you
+*must* call ``configure()`` at some point before using any code that reads
+settings.
+
+If you don't set ``DJANGO_SETTINGS_MODULE`` and don't call ``configure()``,
+Django will raise an ``EnvironmentError`` exception the first time a setting
+is accessed.
+
+If you set ``DJANGO_SETTINGS_MODULE``, access settings values somehow, *then*
+call ``configure()``, Django will raise an ``EnvironmentError`` saying settings
+have already been configured.
+
+Also, it's an error to call ``configure()`` more than once, or to call
+``configure()`` after any setting has been accessed.
+
+It boils down to this: Use exactly one of either ``configure()`` or
+``DJANGO_SETTINGS_MODULE``. Not both, and not neither.
diff --git a/docs/sites.txt b/docs/sites.txt
new file mode 100644
index 0000000000..51f57afe4f
--- /dev/null
+++ b/docs/sites.txt
@@ -0,0 +1,311 @@
+=====================
+The "sites" framework
+=====================
+
+Django comes with an optional "sites" framework. It's a hook for associating
+objects and functionality to particular Web sites, and it's a holding place for
+the domain names and "verbose" names of your Django-powered sites.
+
+Use it if your single Django installation powers more than one site and you
+need to differentiate between those sites in some way.
+
+The whole sites framework is based on two simple concepts:
+
+ * The ``Site`` model, found in ``django.contrib.sites``, has ``domain`` and
+ ``name`` fields.
+ * The ``SITE_ID`` setting specifies the database ID of the ``Site`` object
+ associated with that particular settings file.
+
+How you use this is up to you, but Django uses it in a couple of ways
+automatically via simple conventions.
+
+Example usage
+=============
+
+Why would you use sites? It's best explained through examples.
+
+Associating content with multiple sites
+---------------------------------------
+
+The Django-powered sites LJWorld.com_ and Lawrence.com_ are operated by the
+same news organization -- the Lawrence Journal-World newspaper in Lawrence,
+Kansas. LJWorld.com focuses on news, while Lawrence.com focuses on local
+entertainment. But sometimes editors want to publish an article on *both*
+sites.
+
+The brain-dead way of solving the problem would be to require site producers to
+publish the same story twice: once for LJWorld.com and again for Lawrence.com.
+But that's inefficient for site producers, and it's redundant to store
+multiple copies of the same story in the database.
+
+The better solution is simple: Both sites use the same article database, and an
+article is associated with one or more sites. In Django model terminology,
+that's represented by a ``ManyToManyField`` in the ``Article`` model::
+
+ from django.db import models
+ from django.contrib.sites.models import Site
+
+ class Article(models.Model):
+ headline = models.CharField(maxlength=200)
+ # ...
+ sites = models.ManyToManyField(Site)
+
+This accomplishes several things quite nicely:
+
+ * It lets the site producers edit all content -- on both sites -- in a
+ single interface (the Django admin).
+
+ * It means the same story doesn't have to be published twice in the
+ database; it only has a single record in the database.
+
+ * It lets the site developers use the same Django view code for both sites.
+ The view code that displays a given story just checks to make sure the
+ requested story is on the current site. It looks something like this::
+
+ from django.conf import settings
+
+ def article_detail(request, article_id):
+ try:
+ a = Article.objects.get(id=article_id, sites__id__exact=settings.SITE_ID)
+ except Article.DoesNotExist:
+ raise Http404
+ # ...
+
+.. _ljworld.com: http://www.ljworld.com/
+.. _lawrence.com: http://www.lawrence.com/
+
+Associating content with a single site
+--------------------------------------
+
+Similarly, you can associate a model to the ``Site`` model in a many-to-one
+relationship, using ``ForeignKey``.
+
+For example, if an article is only allowed on a single site, you'd use a model
+like this::
+
+ from django.db import models
+ from django.contrib.sites.models import Site
+
+ class Article(models.Model):
+ headline = models.CharField(maxlength=200)
+ # ...
+ site = models.ForeignKey(Site)
+
+This has the same benefits as described in the last section.
+
+Hooking into the current site from views
+----------------------------------------
+
+On a lower level, you can use the sites framework in your Django views to do
+particular things based on what site in which the view is being called.
+For example::
+
+ from django.conf import settings
+
+ def my_view(request):
+ if settings.SITE_ID == 3:
+ # Do something.
+ else:
+ # Do something else.
+
+Of course, it's ugly to hard-code the site IDs like that. This sort of
+hard-coding is best for hackish fixes that you need done quickly. A slightly
+cleaner way of accomplishing the same thing is to check the current site's
+domain::
+
+ from django.conf import settings
+ from django.contrib.sites.models import Site
+
+ def my_view(request):
+ current_site = Site.objects.get(id=settings.SITE_ID)
+ if current_site.domain == 'foo.com':
+ # Do something
+ else:
+ # Do something else.
+
+The idiom of retrieving the ``Site`` object for the value of
+``settings.SITE_ID`` is quite common, so the ``Site`` model's manager has a
+``get_current()`` method. This example is equivalent to the previous one::
+
+ from django.contrib.sites.models import Site
+
+ def my_view(request):
+ current_site = Site.objects.get_current()
+ if current_site.domain == 'foo.com':
+ # Do something
+ else:
+ # Do something else.
+
+Getting the current domain for display
+--------------------------------------
+
+LJWorld.com and Lawrence.com both have e-mail alert functionality, which lets
+readers sign up to get notifications when news happens. It's pretty basic: A
+reader signs up on a Web form, and he immediately gets an e-mail saying,
+"Thanks for your subscription."
+
+It'd be inefficient and redundant to implement this signup-processing code
+twice, so the sites use the same code behind the scenes. But the "thank you for
+signing up" notice needs to be different for each site. By using ``Site``
+objects, we can abstract the "thank you" notice to use the values of the
+current site's ``name`` and ``domain``.
+
+Here's an example of what the form-handling view looks like::
+
+ from django.contrib.sites.models import Site
+ from django.core.mail import send_mail
+
+ def register_for_newsletter(request):
+ # Check form values, etc., and subscribe the user.
+ # ...
+
+ current_site = Site.objects.get_current()
+ send_mail('Thanks for subscribing to %s alerts' % current_site.name,
+ 'Thanks for your subscription. We appreciate it.\n\n-The %s team.' % current_site.name,
+ 'editor@%s' % current_site.domain,
+ [user.email])
+
+ # ...
+
+On Lawrence.com, this e-mail has the subject line "Thanks for subscribing to
+lawrence.com alerts." On LJWorld.com, the e-mail has the subject "Thanks for
+subscribing to LJWorld.com alerts." Same goes for the e-mail's message body.
+
+Note that an even more flexible (but more heavyweight) way of doing this would
+be to use Django's template system. Assuming Lawrence.com and LJWorld.com have
+different template directories (``TEMPLATE_DIRS``), you could simply farm out
+to the template system like so::
+
+ from django.core.mail import send_mail
+ from django.template import loader, Context
+
+ def register_for_newsletter(request):
+ # Check form values, etc., and subscribe the user.
+ # ...
+
+ subject = loader.get_template('alerts/subject.txt').render(Context({}))
+ message = loader.get_template('alerts/message.txt').render(Context({}))
+ send_mail(subject, message, 'editor@ljworld.com', [user.email])
+
+ # ...
+
+In this case, you'd have to create ``subject.txt`` and ``message.txt`` template
+files for both the LJWorld.com and Lawrence.com template directories. That
+gives you more flexibility, but it's also more complex.
+
+It's a good idea to exploit the ``Site`` objects as much as possible, to remove
+unneeded complexity and redundancy.
+
+Getting the current domain for full URLs
+----------------------------------------
+
+Django's ``get_absolute_url()`` convention is nice for getting your objects'
+URL without the domain name, but in some cases you might want to display the
+full URL -- with ``http://`` and the domain and everything -- for an object.
+To do this, you can use the sites framework. A simple example::
+
+ >>> from django.contrib.sites.models import Site
+ >>> obj = MyModel.objects.get(id=3)
+ >>> obj.get_absolute_url()
+ '/mymodel/objects/3/'
+ >>> Site.objects.get_current().domain
+ 'example.com'
+ >>> 'http://%s%s' % (Site.objects.get_current().domain, obj.get_absolute_url())
+ 'http://example.com/mymodel/objects/3/'
+
+The ``CurrentSiteManager``
+==========================
+
+If ``Site``\s play a key role in your application, consider using the helpful
+``CurrentSiteManager`` in your model(s). It's a model manager_ that
+automatically filters its queries to include only objects associated with the
+current ``Site``.
+
+Use ``CurrentSiteManager`` by adding it to your model explicitly. For example::
+
+ from django.db import models
+ from django.contrib.sites.models import Site
+ from django.contrib.sites.managers import CurrentSiteManager
+
+ class Photo(models.Model):
+ photo = models.FileField(upload_to='/home/photos')
+ photographer_name = models.CharField(maxlength=100)
+ pub_date = models.DateField()
+ site = models.ForeignKey(Site)
+ objects = models.Manager()
+ on_site = CurrentSiteManager()
+
+With this model, ``Photo.objects.all()`` will return all ``Photo`` objects in
+the database, but ``Photo.on_site.all()`` will return only the ``Photo``
+objects associated with the current site, according to the ``SITE_ID`` setting.
+
+Put another way, these two statements are equivalent::
+
+ Photo.objects.filter(site=settings.SITE_ID)
+ Photo.on_site.all()
+
+How did ``CurrentSiteManager`` know which field of ``Photo`` was the ``Site``?
+It defaults to looking for a field called ``site``. If your model has a
+``ForeignKey`` or ``ManyToManyField`` called something *other* than ``site``,
+you need to explicitly pass that as the parameter to ``CurrentSiteManager``.
+The following model, which has a field called ``publish_on``, demonstrates
+this::
+
+ from django.db import models
+ from django.contrib.sites.models import Site
+ from django.contrib.sites.managers import CurrentSiteManager
+
+ class Photo(models.Model):
+ photo = models.FileField(upload_to='/home/photos')
+ photographer_name = models.CharField(maxlength=100)
+ pub_date = models.DateField()
+ publish_on = models.ForeignKey(Site)
+ objects = models.Manager()
+ on_site = CurrentSiteManager('publish_on')
+
+If you attempt to use ``CurrentSiteManager`` and pass a field name that doesn't
+exist, Django will raise a ``ValueError``.
+
+.. _manager: http://www.djangoproject.com/documentation/model_api/#managers
+
+How Django uses the sites framework
+===================================
+
+Although it's not required that you use the sites framework, it's strongly
+encouraged, because Django takes advantage of it in a few places. Even if your
+Django installation is powering only a single site, you should take the two
+seconds to create the site object with your ``domain`` and ``name``, and point
+to its ID in your ``SITE_ID`` setting.
+
+Here's how Django uses the sites framework:
+
+ * In the `redirects framework`_, each redirect object is associated with a
+ particular site. When Django searches for a redirect, it takes into
+ account the current ``SITE_ID``.
+
+ * In the comments framework, each comment is associated with a particular
+ site. When a comment is posted, its ``site`` is set to the current
+ ``SITE_ID``, and when comments are listed via the appropriate template
+ tag, only the comments for the current site are displayed.
+
+ * In the `flatpages framework`_, each flatpage is associated with a
+ particular site. When a flatpage is created, you specify its ``site``,
+ and the ``FlatpageFallbackMiddleware`` checks the current ``SITE_ID`` in
+ retrieving flatpages to display.
+
+ * In the `syndication framework`_, the templates for ``title`` and
+ ``description`` automatically have access to a variable ``{{{ site }}}``,
+ which is the ``Site`` object representing the current site. Also, the
+ hook for providing item URLs will use the ``domain`` from the current
+ ``Site`` object if you don't specify a fully-qualified domain.
+
+ * In the `authentication framework`_, the ``django.contrib.auth.views.login``
+ view passes the current ``Site`` name to the template as ``{{{ site_name }}}``.
+
+ * The shortcut view (``django.views.defaults.shortcut``) uses the domain of
+ the current ``Site`` object when calculating an object's URL.
+
+.. _redirects framework: http://www.djangoproject.com/documentation/redirects/
+.. _flatpages framework: http://www.djangoproject.com/documentation/flatpages/
+.. _syndication framework: http://www.djangoproject.com/documentation/syndication/
+.. _authentication framework: http://www.djangoproject.com/documentation/syndication/
diff --git a/docs/templates_python.txt b/docs/templates_python.txt
index 21ae595624..8ac2effd45 100644
--- a/docs/templates_python.txt
+++ b/docs/templates_python.txt
@@ -7,6 +7,10 @@ perspective -- how it works and how to extend it. If you're just looking for
reference on the language syntax, see
`The Django template language: For template authors`_.
+If you're looking to use the Django template system as part of another
+application -- i.e., without the rest of the framework -- make sure to read
+the `configuration`_ section later in this document.
+
.. _`The Django template language: For template authors`: http://www.djangoproject.com/documentation/templates/
Basics
@@ -739,6 +743,164 @@ Python 2.4 and above::
If you leave off the ``name`` argument, as in the second example above, Django
will use the function's name as the tag name.
+Shortcut for simple tags
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Many template tags take a single argument -- a string or a template variable
+reference -- and return a string after doing some processing based solely on
+the input argument and some external information. For example, the
+``current_time`` tag we wrote above is of this variety: we give it a format
+string, it returns the time as a string.
+
+To ease the creation of the types of tags, Django provides a helper function,
+``simple_tag``. This function, which is a method of
+``django.template.Library``, takes a function that accepts one argument, wraps
+it in a ``render`` function and the other necessary bits mentioned above and
+registers it with the template system.
+
+Our earlier ``current_time`` function could thus be written like this::
+
+ # This version of do_current_time takes only a single argument and returns
+ # a string.
+
+ def do_current_time(token):
+ try:
+ # Splitting by None == splitting by spaces.
+ tag_name, format_string = token.contents.split(None, 1)
+ except ValueError:
+ raise template.TemplateSyntaxError, "%r tag requires an argument" % token.contents[0]
+ if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
+ raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tag_name
+ return datetime.datetime.now().strftime(self.format_string[1:-1])
+
+ register.simple_tag(do_current_time)
+
+In Python 2.4, the decorator syntax also works::
+
+ @simple_tag
+ def do_current_time(token):
+ ...
+
+Inclusion tags
+~~~~~~~~~~~~~~
+
+Another type of template tag that is sometimes useful is when you want to
+display some data that is computed at render time in a template fragment. For
+example, in Django's admin interface, there is a line of buttons along the
+bottom of the `create/edit record` screen. These buttons always look the same,
+but the link targets change depending upon the object being edited. So they
+are a perfect example for using a small template that is filled in with
+details from the current object. To save typing, it would also be nice if we
+could wrap this whole display up in a single tag (in the admin templates this
+is the ``submit_row`` tag).
+
+We call these sorts of tags `inclusion tags`. In your template, you pass in
+any appropriate arguments and the tag uses those arguments, together with the
+current context to render a template and include the result in the output.
+
+Writing inclusion tags is probably best demonstrated by example. We will write
+a tag that outputs a list of choices for a Poll object, such as was created in
+the tutorials_. We will use this tag like this::
+
+ {{ show_results poll }}
+
+and the output will be something like this::
+
+ <ul>
+ <li>First choice</li>
+ <li>Second choice</li>
+ <li>Third choice</li>
+ </ul>
+
+First, we define the function which takes the argument and produces a
+dictionary of data for the result. The important point here is we only need to
+return a dictionary, not anything more complex. This will be used to substitue
+for values in the template fragment, just as when templates are used
+elsewhere.
+
+::
+
+ def show_results(poll):
+ choices = poll.choice_set.all()
+ return {'choices': choices}
+
+We also need to create the template that is used to render the output. This
+template is a fixed feature of the tag: the tag writer specifies it, not the
+template designer. In our case, the template is very simple::
+
+ <ul>
+ {% for choice in choices %}
+ <li> {{ choice }} </li>
+ {% endfor %}
+ </ul>
+
+Now we can create the inclusion tag. Suppose the above template is in a file
+called ``results.html`` in a directory that is searched by the template
+loader. We register our new tag similarly to a normal tag.
+
+::
+
+ # Here, register is a django.template.Library instance, as before
+ register.inclusion_tag('results.html')(show_results)
+
+As always, Python 2.4 decorator syntax works as well, so we could have
+written
+
+::
+
+ @inclusion_tag('results.html')
+ def show_results(poll):
+ ...
+
+when first creating the function.
+
+In some cases, an inclusion tag might require a large number of arguments to
+display itself properly. In essence, it would depend largely on the current
+context it was being rendered with. We can make these sorts of tags easier to
+write by telling the ``inclusion_tag`` function that the whole context
+should be passed in as an argument to the function. This will be done
+invisibly as far as the template tag user is concerned: they will not need to
+do anything to pass in the context.
+
+For example, suppose we are writing an inclusion tag that will always be used
+in a context that contains ``home_link`` and ``home_title`` variables that
+point back to the main page. We can write a tag that is used like this::
+
+ {{ jump_link }}
+
+and renders this::
+
+ Jump directly to <a href="http://example.com/home">Home</a>
+
+The tag function is almost as simple as before. This time it takes no
+arguments except the ``context`` (and the parameter `must` be called
+``context`` in this case; the special parameter named is used internally by
+Django to fill in the values correctly).
+
+::
+
+ # The first argument *must* be called "context" here.
+ def jump_link(context):
+ return {
+ 'link': context['home_link'],
+ 'title': context['home_title'],
+ }
+
+Our template is very simple again::
+
+ Jump directly to <a href="{{ link }}">{{ title }}</a>.
+
+Assuming the template is in a file called ``link.html``, we register this new
+tag as follows::
+
+ register.inclusion_tag('link.html', takes_context = True)(jump_link)
+
+The ``takes_context`` parameter here defaults to *False*. When it is set to
+*True*, our tag is passed the implicit context as in this example. That is the
+only difference between this case and our previous use of ``inclusion_tag``.
+
+.. _tutorials: http://www.djangoproject.com/documentation/tutorial1/#creating-models
+
Setting a variable in the context
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -876,3 +1038,37 @@ The only new concept here is the ``self.nodelist.render(context)`` in
For more examples of complex rendering, see the source code for ``{% if %}``,
``{% for %}``, ``{% ifequal %}`` and ``{% ifchanged %}``. They live in
``django/template/defaulttags.py``.
+
+.. _configuration:
+
+Configuring the template system in standalone mode
+==================================================
+
+.. note::
+
+ This section is only of interest to people trying to use the template
+ system as an output component in another application. If you are using the
+ template system as part of a Django application, nothing here applies to
+ you.
+
+Normally, Django will load all the configuration information it needs from its
+own default configuration file, combined with the settings in the module given
+in the ``DJANGO_SETTINGS_MODULE`` environment variable. But if you're using the
+template system independently of the rest of Django, the environment variable
+approach isn't very convenient, because you probably want to configure the
+template system in line with the rest of your application rather than dealing
+with settings files and pointing to them via environment variables.
+
+To solve this problem, you need to use the manual configuration option
+described in the `settings file`_ documentation. Simply import the appropriate
+pieces of the templating system and then, *before* you call any of the
+templating functions, call ``django.conf.settings.configure()`` with any
+settings you wish to specify. You might want to consider setting at least
+``TEMPLATE_DIRS`` (if you are going to use template loaders),
+``DEFAULT_CHARSET`` (although the default of ``utf-8`` is probably fine) and
+``TEMPLATE_DEBUG``. All available settings are described in the
+`settings documentation`_, and any setting starting with *TEMPLATE_*
+is of obvious interest.
+
+.. _settings file: http://www.djangoproject.com/documentation/settings/#using-settings-without-the-django-settings-module-environment-variable
+.. _settings documentation: http://www.djangoproject.com/documentation/settings/
diff --git a/docs/tutorial01.txt b/docs/tutorial01.txt
index 03d4eac635..c353e1ab4b 100644
--- a/docs/tutorial01.txt
+++ b/docs/tutorial01.txt
@@ -445,13 +445,13 @@ Once you're in the shell, explore the database API::
# objects.all() displays all the polls in the database.
>>> Poll.objects.all()
- [<Poll object>]
+ [<Poll: Poll object>]
-Wait a minute. ``<Poll object>`` is, utterly, an unhelpful representation of
-this object. Let's fix that by editing the polls model
-(in the ``polls/models.py`` file) and adding a ``__str__()`` method to
-both ``Poll`` and ``Choice``::
+Wait a minute. ``<Poll: Poll object>`` is, utterly, an unhelpful
+representation of this object. Let's fix that by editing the polls model (in
+the ``polls/models.py`` file) and adding a ``__str__()`` method to both
+``Poll`` and ``Choice``::
class Poll(models.Model):
# ...
@@ -487,30 +487,30 @@ Let's jump back into the Python interactive shell by running
# Make sure our __str__() addition worked.
>>> Poll.objects.all()
- [What's up?]
+ [<Poll: What's up?>]
# Django provides a rich database lookup API that's entirely driven by
# keyword arguments.
>>> Poll.objects.filter(id=1)
- [What's up?]
+ [<Poll: What's up?>]
>>> Poll.objects.filter(question__startswith='What')
- [What's up?]
+ [<Poll: What's up?>]
# Get the poll whose year is 2005. Of course, if you're going through this
# tutorial in another year, change as appropriate.
>>> Poll.objects.get(pub_date__year=2005)
- What's up?
+ <Poll: What's up?>
>>> Poll.objects.get(id=2)
Traceback (most recent call last):
...
- DoesNotExist: Poll does not exist for {'id': 2}
+ DoesNotExist: Poll matching query does not exist.
# Lookup by a primary key is the most common case, so Django provides a
# shortcut for primary-key exact lookups.
# The following is identical to Poll.objects.get(id=1).
>>> Poll.objects.get(pk=1)
- What's up?
+ <Poll: What's up?>
# Make sure our custom method worked.
>>> p = Poll.objects.get(pk=1)
@@ -522,18 +522,18 @@ Let's jump back into the Python interactive shell by running
# of available choices and returns the new Choice object.
>>> p = Poll.objects.get(pk=1)
>>> p.choice_set.create(choice='Not much', votes=0)
- Not much
+ <Choice: Not much>
>>> p.choice_set.create(choice='The sky', votes=0)
- The sky
+ <Choice: The sky>
>>> c = p.choice_set.create(choice='Just hacking again', votes=0)
# Choice objects have API access to their related Poll objects.
>>> c.poll
- What's up?
+ <Poll: What's up?>
# And vice versa: Poll objects get access to Choice objects.
>>> p.choice_set.all()
- [Not much, The sky, Just hacking again]
+ [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
>>> p.choice_set.count()
3
@@ -542,7 +542,7 @@ Let's jump back into the Python interactive shell by running
# This works as many levels deep as you want. There's no limit.
# Find all Choices for any poll whose pub_date is in 2005.
>>> Choice.objects.filter(poll__pub_date__year=2005)
- [Not much, The sky, Just hacking again]
+ [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
# Let's delete one of the choices. Use delete() for that.
>>> c = p.choice_set.filter(choice__startswith='Just hacking')