diff options
| author | Jeremy Dunck <jdunck@gmail.com> | 2007-06-18 16:48:27 +0000 |
|---|---|---|
| committer | Jeremy Dunck <jdunck@gmail.com> | 2007-06-18 16:48:27 +0000 |
| commit | bdcc95e5cce2754d78055f86d561ba2be92ba854 (patch) | |
| tree | 08a7e4c86244cb42fe577aec5c03a57b023822c2 /docs | |
| parent | 48c9f87e1f3ba9523d79c09f52c0ccc6221f08bf (diff) | |
gis: Merged revisions 4786-5490 via svnmerge from
http://code.djangoproject.com/svn/django/trunk
git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@5492 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'docs')
43 files changed, 2465 insertions, 532 deletions
diff --git a/docs/add_ons.txt b/docs/add_ons.txt index 9809cf46f8..ffc4f7420f 100644 --- a/docs/add_ons.txt +++ b/docs/add_ons.txt @@ -6,8 +6,16 @@ Django aims to follow Python's `"batteries included" philosophy`_. It ships with a variety of extra, optional tools that solve common Web-development problems. -This code lives in ``django/contrib`` in the Django distribution. Here's a -rundown of the packages in ``contrib``: +This code lives in ``django/contrib`` in the Django distribution. This document +gives a rundown of the packages in ``contrib``, along with any dependencies +those packages have. + +.. admonition:: Note + + For most of these add-ons -- specifically, the add-ons that include either + models or template tags -- you'll need to add the package name (e.g., + ``'django.contrib.admin'``) to your ``INSTALLED_APPS`` setting and re-run + ``manage.py syncdb``. .. _"batteries included" philosophy: http://docs.python.org/tut/node12.html#batteries-included @@ -17,7 +25,9 @@ admin The automatic Django administrative interface. For more information, see `Tutorial 2`_. -.. _Tutorial 2: ../tutorial2/ +.. _Tutorial 2: ../tutorial02/ + +Requires the auth_ and contenttypes_ contrib packages to be installed. auth ==== @@ -137,6 +147,8 @@ See the `flatpages documentation`_. .. _flatpages documentation: ../flatpages/ +Requires the sites_ contrib package to be installed as well. + localflavor =========== @@ -147,13 +159,20 @@ contains a ``USZipCodeField`` that you can use to validate U.S. zip codes. markup ====== -A collection of template filters that implement these common markup languages: +A collection of template filters that implement common markup languages: + + * ``textile`` -- implements `Textile`_ + * ``markdown`` -- implements `Markdown`_ + * ``restructuredtext`` -- implements `ReST (ReStructured Text)`_ - * `Textile`_ - * `Markdown`_ - * `ReST (ReStructured Text)`_ +In each case, the filter expects formatted markup as a string and returns a +string representing the marked-up text. For example, the ``textile`` filter +converts text that is marked-up in Textile format to HTML. -For documentation, read the source code in django/contrib/markup/templatetags/markup.py. +To activate these filters, add ``'django.contrib.markup'`` to your +``INSTALLED_APPS`` setting. Once you've done that, use ``{% load markup %}`` in +a template, and you'll have access to these filters. For more documentation, +read the source code in django/contrib/markup/templatetags/markup.py. .. _Textile: http://en.wikipedia.org/wiki/Textile_%28markup_language%29 .. _Markdown: http://en.wikipedia.org/wiki/Markdown diff --git a/docs/api_stability.txt b/docs/api_stability.txt index 508336e0ef..cfaffeac6b 100644 --- a/docs/api_stability.txt +++ b/docs/api_stability.txt @@ -100,14 +100,14 @@ change: .. _caching: ../cache/ .. _custom template tags and libraries: ../templates_python/ -.. _database lookup: ../db_api/ -.. _django-admin utility: ../django_admin/ +.. _database lookup: ../db-api/ +.. _django-admin utility: ../django-admin/ .. _fastcgi integration: ../fastcgi/ .. _flatpages: ../flatpages/ .. _generic views: ../generic_views/ .. _internationalization: ../i18n/ .. _legacy database integration: ../legacy_databases/ -.. _model definition: ../model_api/ +.. _model definition: ../model-api/ .. _mod_python integration: ../modpython/ .. _redirects: ../redirects/ .. _request/response objects: ../request_response/ diff --git a/docs/authentication.txt b/docs/authentication.txt index aff336f67a..972ca42073 100644 --- a/docs/authentication.txt +++ b/docs/authentication.txt @@ -144,7 +144,7 @@ custom methods: Raises ``django.contrib.auth.models.SiteProfileNotAvailable`` if the current site doesn't allow profiles. -.. _Django model: ../model_api/ +.. _Django model: ../model-api/ .. _DEFAULT_FROM_EMAIL: ../settings/#default-from-email Manager functions @@ -161,8 +161,8 @@ The ``User`` model has a custom manager that has the following helper functions: * ``make_random_password(length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789')`` Returns a random password with the given length and given string of allowed characters. (Note that the default value of ``allowed_chars`` - doesn't contain ``"I"`` or letters that look like it, to avoid user - confusion. + doesn't contain letters that can cause user confusion, including + ``1``, ``I`` and ``0``). Basic usage ----------- @@ -204,9 +204,12 @@ The ``password`` attribute of a ``User`` object is a string in this format:: That's hashtype, salt and hash, separated by the dollar-sign character. -Hashtype is either ``sha1`` (default) or ``md5`` -- the algorithm used to -perform a one-way hash of the password. Salt is a random string used to salt -the raw password to create the hash. +Hashtype is either ``sha1`` (default), ``md5`` or ``crypt`` -- the algorithm +used to perform a one-way hash of the password. Salt is a random string used +to salt the raw password to create the hash. Note that the ``crypt`` method is +only supported on platforms that have the standard Python ``crypt`` module +available, and ``crypt`` support is only available in the Django development +version. For example:: @@ -387,14 +390,15 @@ introduced in Python 2.4:: ``login_required`` does the following: - * If the user isn't logged in, redirect to ``/accounts/login/``, passing - the current absolute URL in the query string as ``next``. For example: + * If the user isn't logged in, redirect to ``settings.LOGIN_URL`` + (``/accounts/login/`` by default), passing the current absolute URL + in the query string as ``next``. For example: ``/accounts/login/?next=/polls/3/``. * If the user is logged in, execute the view normally. The view code is free to assume the user is logged in. -Note that you'll need to map the appropriate Django view to ``/accounts/login/``. -To do this, add the following line to your URLconf:: +Note that you'll need to map the appropriate Django view to ``settings.LOGIN_URL``. +For example, using the defaults, add the following line to your URLconf:: (r'^accounts/login/$', 'django.contrib.auth.views.login'), @@ -405,9 +409,9 @@ Here's what ``django.contrib.auth.views.login`` does: * 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. + ``next`` isn't provided, it redirects to ``settings.LOGIN_REDIRECT_URL`` + (which defaults to ``/accounts/profile/``). 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`` by default. This template gets passed three @@ -487,7 +491,7 @@ Logs a user out, then redirects to the login page. **Optional arguments:** * ``login_url``: The URL of the login page to redirect to. This - will default to ``/accounts/login/`` if not supplied. + will default to ``settings.LOGIN_URL`` if not supplied. ``django.contrib.auth.views.password_change`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -569,7 +573,7 @@ successful login. **Optional arguments:** * ``login_url``: The URL of the login page to redirect to. This - will default to ``/accounts/login/`` if not supplied. + will default to ``settings.LOGIN_URL`` if not supplied. Built-in manipulators --------------------- @@ -636,7 +640,7 @@ Note that ``user_passes_test`` does not automatically check that the ``User`` is not anonymous. ``user_passes_test()`` takes an optional ``login_url`` argument, which lets you -specify the URL for your login page (``/accounts/login/`` by default). +specify the URL for your login page (``settings.LOGIN_URL`` by default). Example in Python 2.3 syntax:: @@ -680,7 +684,7 @@ parameter. Example:: my_view = permission_required('polls.can_vote', login_url='/loginpage/')(my_view) As in the ``login_required`` decorator, ``login_url`` defaults to -``'/accounts/login/'``. +``settings.LOGIN_URL``. Limiting access to generic views -------------------------------- @@ -726,7 +730,7 @@ Django developers are currently discussing. Default permissions ------------------- -Three basic permissions -- add, create and delete -- are automatically created +Three basic permissions -- add, change and delete -- are automatically created for each Django model that has a ``class Admin`` set. Behind the scenes, these permissions are added to the ``auth_permission`` database table when you run ``manage.py syncdb``. @@ -757,7 +761,7 @@ This example model creates three custom permissions:: The only thing this does is create those extra permissions when you run ``syncdb``. -.. _model Meta attribute: ../model_api/#meta-options +.. _model Meta attribute: ../model-api/#meta-options API reference ------------- diff --git a/docs/cache.txt b/docs/cache.txt index 054d99819d..e245e100e7 100644 --- a/docs/cache.txt +++ b/docs/cache.txt @@ -66,10 +66,19 @@ deleting arbitrary data in the cache. All data is stored directly in memory, so there's no overhead of database or filesystem usage. After installing Memcached itself, you'll need to install the Memcached Python -bindings. They're in a single Python module, memcache.py, available at -ftp://ftp.tummy.com/pub/python-memcached/ . If that URL is no longer valid, -just go to the Memcached Web site (http://www.danga.com/memcached/) and get the -Python bindings from the "Client APIs" section. +bindings. Two versions of this are available. Choose and install *one* of the +following modules: + + * The fastest available option is a module called ``cmemcache``, available + at http://gijsbert.org/cmemcache/ . (This module is only compatible with + the Django development version. Django 0.96 is only compatible with the + second option, below.) + + * If you can't install ``cmemcache``, you can install ``python-memcached``, + available at ftp://ftp.tummy.com/pub/python-memcached/ . If that URL is + no longer valid, just go to the Memcached Web site + (http://www.danga.com/memcached/) and get the Python bindings from the + "Client APIs" section. To use Memcached with Django, set ``CACHE_BACKEND`` to ``memcached://ip:port/``, where ``ip`` is the IP address of the Memcached diff --git a/docs/contributing.txt b/docs/contributing.txt index 1d2b635b76..31409f27bd 100644 --- a/docs/contributing.txt +++ b/docs/contributing.txt @@ -279,6 +279,15 @@ Please follow these coding standards when writing code for inclusion in Django: * Mark all strings for internationalization; see the `i18n documentation`_ for details. + * Please don't put your name in the code you contribute. Our policy is to + keep contributors' names in the ``AUTHORS`` file distributed with Django + -- not scattered throughout the codebase itself. Feel free to include a + change to the ``AUTHORS`` file in your patch if you make more than a + single trivial change. + +Template style +-------------- + * In Django template code, put one (and only one) space between the curly brackets and the tag contents. @@ -290,6 +299,9 @@ Please follow these coding standards when writing code for inclusion in Django: {{foo}} +View style +---------- + * In Django views, the first parameter in a view function should be called ``request``. @@ -303,11 +315,72 @@ Please follow these coding standards when writing code for inclusion in Django: def my_view(req, foo): # ... - * Please don't put your name in the code you contribute. Our policy is to - keep contributors' names in the ``AUTHORS`` file distributed with Django - -- not scattered throughout the codebase itself. Feel free to include a - change to the ``AUTHORS`` file in your patch if you make more than a - single trivial change. +Model style +----------- + + * Field names should be all lowercase, using underscores instead of + camelCase. + + Do this:: + + class Person(models.Model): + first_name = models.CharField(maxlength=20) + last_name = models.CharField(maxlength=40) + + Don't do this:: + + class Person(models.Model): + FirstName = models.CharField(maxlength=20) + Last_Name = models.CharField(maxlength=40) + + * The ``class Meta`` should appear *after* the fields are defined, with + a single blank line separating the fields and the class definition. + + Do this:: + + class Person(models.Model): + first_name = models.CharField(maxlength=20) + last_name = models.CharField(maxlength=40) + + class Meta: + verbose_name_plural = 'people' + + Don't do this:: + + class Person(models.Model): + first_name = models.CharField(maxlength=20) + last_name = models.CharField(maxlength=40) + class Meta: + verbose_name_plural = 'people' + + Don't do this, either:: + + class Person(models.Model): + class Meta: + verbose_name_plural = 'people' + + first_name = models.CharField(maxlength=20) + last_name = models.CharField(maxlength=40) + + * The order of model inner classes and standard methods should be as + follows (noting that these are not all required): + + * All database fields + * ``class Meta`` + * ``class Admin`` + * ``def __str__()`` + * ``def save()`` + * ``def get_absolute_url()`` + * Any custom methods + + * If ``choices`` is defined for a given model field, define the choices as + a tuple of tuples, with an all-uppercase name, either near the top of the + model module or just above the model class. Example:: + + GENDER_CHOICES = ( + ('M', 'Male'), + ('F', 'Female'), + ) Committing code =============== @@ -396,10 +469,11 @@ To run the tests, ``cd`` to the ``tests/`` directory and type:: ./runtests.py --settings=path.to.django.settings Yes, the unit tests need a settings module, but only for database connection -info -- the ``DATABASE_ENGINE``, ``DATABASE_USER`` and ``DATABASE_PASSWORD``. -You will also need a ``ROOT_URLCONF`` setting (its value is ignored; it just -needs to be present) and a ``SITE_ID`` setting (any integer value will do) in -order for all the tests to pass. +info -- the ``DATABASE_NAME`` (required, but will be ignored), +``DATABASE_ENGINE``, ``DATABASE_USER`` and ``DATABASE_PASSWORD`` settings. You +will also need a ``ROOT_URLCONF`` setting (its value is ignored; it just needs +to be present) and a ``SITE_ID`` setting (any integer value will do) in order +for all the tests to pass. The unit tests will not touch your existing databases; they create a new database, called ``django_test_db``, which is deleted when the tests are diff --git a/docs/databases.txt b/docs/databases.txt index 3545b58d47..b73f39843c 100644 --- a/docs/databases.txt +++ b/docs/databases.txt @@ -69,9 +69,12 @@ For now, InnoDB is probably your best choice. MySQLdb ------- -`MySQLdb`_ is the Python interface to MySQL. 1.2.1 is the first version that -has support for MySQL 4.1 and newer. If you are trying to use an older version -of MySQL, then 1.2.0 *might* work for you. +`MySQLdb`_ is the Python interface to MySQL. Version 1.2.1p2 or later is +required for full MySQL support in Django. Earlier versions will not work with +the ``mysql`` backend. + +If you are trying to use an older version of MySQL and the ``mysql_old`` +backend, then 1.2.0 *might* work for you. .. _MySQLdb: http://sourceforge.net/projects/mysql-python diff --git a/docs/databrowse.txt b/docs/databrowse.txt new file mode 100644 index 0000000000..9c03e7e4ea --- /dev/null +++ b/docs/databrowse.txt @@ -0,0 +1,60 @@ +========== +Databrowse +========== + +Databrowse is a Django application that lets you browse your data. + +As the Django admin dynamically creates an admin interface by introspecting +your models, Databrowse dynamically creates a rich, browsable Web site by +introspecting your models. + +.. admonition:: Note + + Databrowse is **very** new and is currently under active development. It + may change substantially before the next Django release. + + With that said, it's easy to use, and it doesn't require writing any + code. So you can play around with it today, with very little investment in + time or coding. + +How to use Databrowse +===================== + + 1. Point Django at the default Databrowse templates. There are two ways to + do this: + + * Add ``'django.contrib.databrowse'`` to your ``INSTALLED_APPS`` + setting. This will work if your ``TEMPLATE_LOADERS`` setting includes + the ``app_directories`` template loader (which is the case by + default). See the `template loader docs`_ for more. + + * Otherwise, determine the full filesystem path to the + ``django/contrib/databrowse/templates`` directory, and add that + directory to your ``TEMPLATE_DIRS`` setting. + + 2. Register a number of models with the Databrowse site:: + + from django.contrib import databrowse + + databrowse.site.register(SomeModel) + databrowse.site.register(SomeOtherModel) + + Note that you should register the model *classes*, not instances. + + It doesn't matter where you put this, as long as it gets executed at + some point. A good place for it is in your URLconf file (``urls.py``). + + 3. Change your URLconf to import the ``databrowse`` module:: + + from django.contrib import databrowse + + ...and add the following line to your URLconf:: + + (r'^databrowse/(.*)', databrowse.site.root), + + The prefix doesn't matter -- you can use ``databrowse/`` or ``db/`` or + whatever you'd like. + + 4. Run the Django server and visit ``/databrowse/`` in your browser. + +.. _template loader docs: ../templates_python/#loader-types diff --git a/docs/db-api.txt b/docs/db-api.txt index 64db3def96..e7b8183f6c 100644 --- a/docs/db-api.txt +++ b/docs/db-api.txt @@ -6,7 +6,7 @@ Once you've created your `data models`_, Django automatically gives you a database-abstraction API that lets you create, retrieve, update and delete objects. This document explains that API. -.. _`data models`: ../model_api/ +.. _`data models`: ../model-api/ Throughout this reference, we'll refer to the following models, which comprise a weblog application:: @@ -85,7 +85,7 @@ There's no way to tell what the value of an ID will be before you call unless you explicitly specify ``primary_key=True`` on a field. See the `AutoField documentation`_.) -.. _AutoField documentation: ../model_api/#autofield +.. _AutoField documentation: ../model-api/#autofield Explicitly specifying auto-primary-key values ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -112,7 +112,7 @@ the previous record in the database:: b4 = Blog(id=3, name='Not Cheddar', tagline='Anything but cheese.') b4.save() # Overrides the previous blog with ID=3! -See _`How Django knows to UPDATE vs. INSERT`, below, for the reason this +See `How Django knows to UPDATE vs. INSERT`_, below, for the reason this happens. Explicitly specifying auto-primary-key values is mostly useful for bulk-saving @@ -134,6 +134,15 @@ the database until you explicitly call ``save()``. The ``save()`` method has no return value. +Updating ``ForeignKey`` fields works exactly the same way; simply assign an +object of the right type to the field in question:: + + joe = Author.objects.create(name="Joe") + entry.author = joe + entry.save() + +Django will complain if you try to assign an object of the wrong type. + How Django knows to UPDATE vs. INSERT ------------------------------------- @@ -143,8 +152,8 @@ or ``UPDATE`` SQL statements. Specifically, when you call ``save()``, Django follows this algorithm: * 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 + ``True`` (i.e., a value other than ``None`` or the empty string), Django + executes a ``SELECT`` query to determine whether a record with the given primary key already exists. * If the record with the given primary key does already exist, Django executes an ``UPDATE`` query. @@ -379,7 +388,7 @@ The lookup parameters (``**kwargs``) should be in the format described in `Field lookups`_ below. Multiple parameters are joined via ``AND`` in the underlying SQL statement, and the whole thing is enclosed in a ``NOT()``. -This example excludes all entries whose ``pub_date`` is the current date/time +This example excludes all entries whose ``pub_date`` is later than 2005-1-3 AND whose ``headline`` is "Hello":: Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello') @@ -389,8 +398,8 @@ In SQL terms, that evaluates to:: SELECT ... WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello') -This example excludes all entries whose ``pub_date`` is the current date/time -OR whose ``headline`` is "Hello":: +This example excludes all entries whose ``pub_date`` is later than 2005-1-3 +AND whose headline is NOT "Hello":: Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline='Hello') @@ -525,19 +534,19 @@ Examples:: [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)] - + ``none()`` ~~~~~~~~~~ **New in Django development version** -Returns an ``EmptyQuerySet`` -- a ``QuerySet`` that always evaluates to +Returns an ``EmptyQuerySet`` -- a ``QuerySet`` that always evaluates to an empty list. This can be used in cases where you know that you should return an empty result set and your caller is expecting a ``QuerySet`` object (instead of returning an empty list, for example.) Examples:: - + >>> Entry.objects.none() [] @@ -589,7 +598,7 @@ related ``Person`` *and* the related ``City``:: p = b.author # Doesn't hit the database. c = p.hometown # Doesn't hit the database. - sv = Book.objects.get(id=4) # No select_related() in this example. + b = Book.objects.get(id=4) # No select_related() in this example. p = b.author # Hits the database. c = p.hometown # Hits the database. @@ -610,7 +619,7 @@ follow:: c = p.hometown # Requires a database call. The ``depth`` argument is new in the Django development version. - + ``extra(select=None, where=None, params=None, tables=None)`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -714,7 +723,7 @@ QuerySet methods that do not return QuerySets The following ``QuerySet`` methods evaluate the ``QuerySet`` and return something *other than* a ``QuerySet``. -These methods do not use a cache (see _`Caching and QuerySets` below). Rather, +These methods do not use a cache (see `Caching and QuerySets`_ below). Rather, they query the database each time they're called. ``get(**kwargs)`` @@ -906,8 +915,8 @@ The database API supports the following lookup types: exact ~~~~~ -Exact match. If the value provided for comparison is ``None``, it will -be interpreted as an SQL ``NULL`` (See isnull_ for more details). +Exact match. If the value provided for comparison is ``None``, it will +be interpreted as an SQL ``NULL`` (See isnull_ for more details). Examples:: @@ -1136,7 +1145,7 @@ such as January 3, July 3, etc. isnull ~~~~~~ -Takes either ``True`` or ``False``, which correspond to SQL queries of +Takes either ``True`` or ``False``, which correspond to SQL queries of ``IS NULL`` and ``IS NOT NULL``, respectively. Example:: @@ -1149,10 +1158,10 @@ SQL equivalent:: .. admonition:: ``__isnull=True`` vs ``__exact=None`` - There is an important difference between ``__isnull=True`` and + There is an important difference between ``__isnull=True`` and ``__exact=None``. ``__exact=None`` will *always* return an empty result - set, because SQL requires that no value is equal to ``NULL``. - ``__isnull`` determines if the field is currently holding the value + set, because SQL requires that no value is equal to ``NULL``. + ``__isnull`` determines if the field is currently holding the value of ``NULL`` without performing a comparison. search @@ -1181,7 +1190,7 @@ The pk lookup shortcut ---------------------- For convenience, Django provides a ``pk`` lookup type, which stands for -"primary_key". +"primary_key". In the example ``Blog`` model, the primary key is the ``id`` field, so these three statements are equivalent:: @@ -1190,14 +1199,14 @@ three statements are equivalent:: Blog.objects.get(id=14) # __exact is implied Blog.objects.get(pk=14) # pk implies id__exact -The use of ``pk`` isn't limited to ``__exact`` queries -- any query term +The use of ``pk`` isn't limited to ``__exact`` queries -- any query term can be combined with ``pk`` to perform a query on the primary key of a model:: # Get blogs entries with id 1, 4 and 7 Blog.objects.filter(pk__in=[1,4,7]) # Get all blog entries with id > 14 - Blog.objects.filter(pk__gt=14) - + Blog.objects.filter(pk__gt=14) + ``pk`` lookups also work across joins. For example, these three statements are equivalent:: @@ -1229,8 +1238,8 @@ whose ``headline`` contains ``'Lennon'``:: Blog.objects.filter(entry__headline__contains='Lennon') -Escaping parenthesis and underscores in LIKE statements -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Escaping percent signs and underscores in LIKE statements +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The field lookups that equate to ``LIKE`` SQL statements (``iexact``, ``contains``, ``icontains``, ``startswith``, ``istartswith``, ``endswith`` @@ -1748,25 +1757,26 @@ Shortcuts As you develop views, you will discover a number of common idioms in the way you use the database API. Django encodes some of these idioms as -shortcuts that can be used to simplify the process of writing views. +shortcuts that can be used to simplify the process of writing views. These +functions are in the ``django.shortcuts`` module. get_object_or_404() ------------------- One common idiom to use ``get()`` and raise ``Http404`` if the -object doesn't exist. This idiom is captured by ``get_object_or_404()``. -This function takes a Django model as its first argument and an -arbitrary number of keyword arguments, which it passes to the manager's +object doesn't exist. This idiom is captured by ``get_object_or_404()``. +This function takes a Django model as its first argument and an +arbitrary number of keyword arguments, which it passes to the manager's ``get()`` function. It raises ``Http404`` if the object doesn't -exist. For example:: - +exist. For example:: + # Get the Entry with a primary key of 3 e = get_object_or_404(Entry, pk=3) -When you provide a model to this shortcut function, the default manager -is used to execute the underlying ``get()`` query. If you don't want to -use the default manager, or you want to search a list of related objects, -you can provide ``get_object_or_404()`` with a manager object, instead. +When you provide a model to this shortcut function, the default manager +is used to execute the underlying ``get()`` query. If you don't want to +use the default manager, or if you want to search a list of related objects, +you can provide ``get_object_or_404()`` with a manager object instead. For example:: # Get the author of blog instance `e` with a name of 'Fred' @@ -1779,8 +1789,8 @@ For example:: get_list_or_404() ----------------- -``get_list_or_404`` behaves the same was as ``get_object_or_404()`` --- except the it uses using ``filter()`` instead of ``get()``. It raises +``get_list_or_404`` behaves the same way as ``get_object_or_404()`` +-- except that it uses ``filter()`` instead of ``get()``. It raises ``Http404`` if the list is empty. Falling back to raw SQL @@ -1801,4 +1811,4 @@ interface to your database. You can access your database via other tools, programming languages or database frameworks; there's nothing Django-specific about your database. -.. _Executing custom SQL: ../model_api/#executing-custom-sql +.. _Executing custom SQL: ../model-api/#executing-custom-sql diff --git a/docs/distributions.txt b/docs/distributions.txt index 63206c535e..4ec265f93c 100644 --- a/docs/distributions.txt +++ b/docs/distributions.txt @@ -47,16 +47,18 @@ Fedora ------ A Django package is available for `Fedora Linux`_, in the "Fedora Extras" -repository. The `current Fedora package`_ is based on Django 0.95.1, and can be -installed by typing ``yum install Django``. +repository. The `current Fedora package`_ is based on Django 0.96, and can be +installed by typing ``yum install Django``. The previous link is for the i386 +binary. Users of other architectures should be able to use that as a starting +point to find their preferred version. .. _Fedora Linux: http://fedora.redhat.com/ -.. _current Fedora package: http://fedoraproject.org/extras/6/i386/repodata/repoview/Django-0-0.95.1-1.fc6.html +.. _current Fedora package: http://download.fedora.redhat.com/pub/fedora/linux/extras/6/i386/repoview/Django.html Gentoo ------ -A Django build is available for `Gentoo Linux`_, and is based on Django 0.95.1. +A Django build is available for `Gentoo Linux`_, and is based on Django 0.96. The `current Gentoo build`_ can be installed by typing ``emerge django``. .. _Gentoo Linux: http://www.gentoo.org/ diff --git a/docs/django-admin.txt b/docs/django-admin.txt index 28e28089cc..d20db7edc9 100644 --- a/docs/django-admin.txt +++ b/docs/django-admin.txt @@ -29,6 +29,9 @@ Generally, when working on a single Django project, it's easier to use ``--settings`` command line option, if you need to switch between multiple Django settings files. +The command-line examples throughout this document use ``django-admin.py`` to +be consistent, but any example can use ``manage.py`` just as well. + Usage ===== @@ -58,7 +61,7 @@ Prints the admin-index template snippet for the given appnames. Use admin-index template snippets if you want to customize the look and feel of your admin's index page. See `Tutorial 2`_ for more information. -.. _Tutorial 2: ../tutorial2/ +.. _Tutorial 2: ../tutorial02/ createcachetable [tablename] ---------------------------- @@ -100,23 +103,24 @@ if you're ever curious to see the full list of defaults. dumpdata [appname appname ...] ------------------------------ -Output to standard output all data in the database associated with the named +Output to standard output all data in the database associated with the named application(s). By default, the database will be dumped in JSON format. If you want the output -to be in another format, use the ``--format`` option (e.g., ``format=xml``). -You may specify any Django serialization backend (including any user specified -serialization backends named in the ``SERIALIZATION_MODULES`` setting). +to be in another format, use the ``--format`` option (e.g., ``format=xml``). +You may specify any Django serialization backend (including any user specified +serialization backends named in the ``SERIALIZATION_MODULES`` setting). The +``--indent`` option can be used to pretty-print the output. If no application name is provided, all installed applications will be dumped. -The output of ``dumpdata`` can be used as input for ``loaddata``. +The output of ``dumpdata`` can be used as input for ``loaddata``. flush ----- -Return the database to the state it was in immediately after syncdb was -executed. This means that all data will be removed from the database, any +Return the database to the state it was in immediately after syncdb was +executed. This means that all data will be removed from the database, any post-synchronization handlers will be re-executed, and the ``initial_data`` fixture will be re-installed. @@ -178,37 +182,37 @@ Django will search in three locations for fixtures: 3. In the literal path named by the fixture Django will load any and all fixtures it finds in these locations that match -the provided fixture names. +the provided fixture names. -If the named fixture has a file extension, only fixtures of that type +If the named fixture has a file extension, only fixtures of that type will be loaded. For example:: django-admin.py loaddata mydata.json - -would only load JSON fixtures called ``mydata``. The fixture extension -must correspond to the registered name of a serializer (e.g., ``json`` or + +would only load JSON fixtures called ``mydata``. The fixture extension +must correspond to the registered name of a serializer (e.g., ``json`` or ``xml``). -If you omit the extension, Django will search all available fixture types +If you omit the extension, Django will search all available fixture types for a matching fixture. For example:: django-admin.py loaddata mydata - + would look for any fixture of any fixture type called ``mydata``. If a fixture directory contained ``mydata.json``, that fixture would be loaded -as a JSON fixture. However, if two fixtures with the same name but different -fixture type are discovered (for example, if ``mydata.json`` and -``mydata.xml`` were found in the same fixture directory), fixture -installation will be aborted, and any data installed in the call to +as a JSON fixture. However, if two fixtures with the same name but different +fixture type are discovered (for example, if ``mydata.json`` and +``mydata.xml`` were found in the same fixture directory), fixture +installation will be aborted, and any data installed in the call to ``loaddata`` will be removed from the database. -The fixtures that are named can include directory components. These +The fixtures that are named can include directory components. These directories will be included in the search path. For example:: django-admin.py loaddata foo/bar/mydata.json - -would search ``<appname>/fixtures/foo/bar/mydata.json`` for each installed -application, ``<dirname>/foo/bar/mydata.json`` for each directory in + +would search ``<appname>/fixtures/foo/bar/mydata.json`` for each installed +application, ``<dirname>/foo/bar/mydata.json`` for each directory in ``FIXTURE_DIRS``, and the literal path ``foo/bar/mydata.json``. Note that the order in which fixture files are processed is undefined. However, @@ -217,16 +221,18 @@ one fixture can reference data in another fixture. If the database backend supports row-level constraints, these constraints will be checked at the end of the transaction. +The ``dumpdata`` command can be used to generate input for ``loaddata``. + .. admonition:: MySQL and Fixtures - Unfortunately, MySQL isn't capable of completely supporting all the + Unfortunately, MySQL isn't capable of completely supporting all the features of Django fixtures. If you use MyISAM tables, MySQL doesn't - support transactions or constraints, so you won't get a rollback if - multiple transaction files are found, or validation of fixture data. - If you use InnoDB tables, you won't be able to have any forward - references in your data files - MySQL doesn't provide a mechanism to - defer checking of row constraints until a transaction is committed. - + support transactions or constraints, so you won't get a rollback if + multiple transaction files are found, or validation of fixture data. + If you use InnoDB tables, you won't be able to have any forward + references in your data files - MySQL doesn't provide a mechanism to + defer checking of row constraints until a transaction is committed. + reset [appname appname ...] --------------------------- Executes the equivalent of ``sqlreset`` for the given appnames. @@ -289,7 +295,7 @@ 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 +(such as CSS files, images, things under ``MEDIA_URL`` and so forth). If you want to configure Django to serve static media, read the `serving static files`_ documentation. @@ -326,7 +332,7 @@ 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 +Refer to the description of ``sqlcustom`` for an explanation of how to specify initial data. sqlclear [appname appname ...] @@ -342,7 +348,7 @@ Prints the custom 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 +app ``news`` that includes a ``Story`` model, ``sqlcustom`` will attempt to read a file ``news/sql/story.sql`` and append it to the output of this command. @@ -366,7 +372,7 @@ Prints the DROP TABLE SQL, then the CREATE TABLE SQL, for the given appnames. sqlsequencereset [appname appname ...] ---------------------------------------------- -Prints the SQL statements for resetting PostgreSQL sequences for the given +Prints the SQL statements for resetting sequences for the given appnames. See http://simon.incutio.com/archive/2004/04/21/postgres for more information. @@ -397,9 +403,10 @@ 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. -``syncdb`` will also search for and install any fixture named ``initial_data``. -See the documentation for ``loaddata`` for details on the specification of -fixture data files. +``syncdb`` will also search for and install any fixture named ``initial_data`` +with an appropriate extension (e.g. ``json`` or ``xml``). See the +documentation for ``loaddata`` for details on the specification of fixture +data files. test ---- @@ -471,7 +478,7 @@ Example usage:: django-admin.py dumpdata --indent=4 -Specifies the number of spaces that will be used for indentation when +Specifies the number of spaces that will be used for indentation when pretty-printing output. By default, output will *not* be pretty-printed. Pretty-printing will only be enabled if the indent option is provided. @@ -512,7 +519,8 @@ and `2` is verbose output. ------------ Example usage:: - django-admin.py manage.py --adminmedia=/tmp/new-admin-style/ + + django-admin.py --adminmedia=/tmp/new-admin-style/ Tells Django where to find the various CSS and JavaScript files for the admin interface when running the development server. Normally these files are served diff --git a/docs/documentation.txt b/docs/documentation.txt index bacfb176b1..decb066fa1 100644 --- a/docs/documentation.txt +++ b/docs/documentation.txt @@ -42,25 +42,25 @@ On the Web The most recent version of the Django documentation lives at http://www.djangoproject.com/documentation/ . These HTML pages are generated -automatically from the text files in source control every 15 minutes. That -means they reflect the "latest and greatest" in Django -- they include the very -latest corrections and additions, and they discuss the latest Django features, +automatically from the text files in source control. That means they reflect +the "latest and greatest" in Django -- they include the very latest +corrections and additions, and they discuss the latest Django features, which may only be available to users of the Django development version. (See "Differences between versions" below.) -A key advantage of the Web-based documentation is the comment section at the -bottom of each document. This is an area for anybody to submit changes, -corrections and suggestions about the given document. The Django developers -frequently monitor the comments there and use them to improve the documentation -for everybody. +We encourage you to help improve the docs by submitting changes, corrections +and suggestions in the `ticket system`_. The Django developers actively monitor +the ticket system and use your feedback to improve the documentation for +everybody. -We encourage you to help improve the docs: it's easy! Note, however, that -comments should explicitly relate to the documentation, rather than asking -broad tech-support questions. If you need help with your particular Django -setup, try the `django-users mailing list`_ instead of posting a comment to the -documentation. +Note, however, that tickets should explicitly relate to the documentation, +rather than asking broad tech-support questions. If you need help with your +particular Django setup, try the `django-users mailing list`_ or the +`#django IRC channel`_ instead. +.. _ticket system: http://code.djangoproject.com/simpleticket?component=Documentation .. _django-users mailing list: http://groups.google.com/group/django-users +.. _#django IRC channel: irc://irc.freenode.net/django In plain text ------------- @@ -94,12 +94,10 @@ Formatting The text documentation is written in ReST (ReStructured Text) format. That means it's easy to read but is also formatted in a way that makes it easy to -convert into other formats, such as HTML. If you're interested, the script that -converts the ReST text docs into djangoproject.com's HTML lives at -`djangoproject.com/django_website/apps/docs/parts/build_documentation.py`_ in -the Django Subversion repository. +convert into other formats, such as HTML. If you have the `reStructuredText`_ +library installed, you can use ``rst2html`` to generate your own HTML files. -.. _djangoproject.com/django_website/apps/docs/parts/build_documentation.py: http://code.djangoproject.com/browser/djangoproject.com/django_website/apps/docs/parts/build_documentation.py +.. _reStructuredText: http://docutils.sourceforge.net/rst.html Differences between versions ============================ @@ -134,14 +132,6 @@ We follow this policy: frozen document that says "These docs are frozen for Django version XXX" and links to the current version of that document. - * Once a document is frozen for a Django release, we remove comments from - that page, in favor of having comments on the latest version of that - document. This is for the sake of maintainability and usability, so that - users have one, and only one, place to leave comments on a particular - document. We realize that some people may be stuck on a previous version - of Django, but we believe the usability problems with multiple versions - of a document the outweigh the benefits. - * The `main documentation Web page`_ includes links to documentation for all previous versions. diff --git a/docs/email.txt b/docs/email.txt index 1f4ce4ef42..66948e5294 100644 --- a/docs/email.txt +++ b/docs/email.txt @@ -19,13 +19,23 @@ In two lines:: send_mail('Subject here', 'Here is the message.', 'from@example.com', ['to@example.com'], fail_silently=False) - + +Mail is sent using the SMTP host and port specified in the `EMAIL_HOST`_ and +`EMAIL_PORT`_ settings. The `EMAIL_HOST_USER`_ and `EMAIL_HOST_PASSWORD`_ +settings, if set, are used to authenticate to the SMTP server, and the +`EMAIL_USE_TLS`_ setting controls whether a secure connection is used. + .. note:: - The character set of email sent with ``django.core.mail`` will be set to + The character set of e-mail sent with ``django.core.mail`` will be set to the value of your `DEFAULT_CHARSET setting`_. - -.. _DEFAULT_CHARSET setting: ../settings/#DEFAULT_CHARSET + +.. _DEFAULT_CHARSET setting: ../settings/#default-charset +.. _EMAIL_HOST: ../settings/#email-host +.. _EMAIL_PORT: ../settings/#email-port +.. _EMAIL_HOST_USER: ../settings/#email-host-user +.. _EMAIL_HOST_PASSWORD: ../settings/#email-host-password +.. _EMAIL_USE_TLS: ../settings/#email-use-tls send_mail() =========== @@ -174,3 +184,72 @@ from the request's POST data, sends that to admin@example.com and redirects to return HttpResponse('Make sure all fields are entered and valid.') .. _Header injection: http://securephp.damonkohler.com/index.php/Email_Injection + +The EmailMessage and SMTPConnection classes +=========================================== + +**New in Django development version** + +Django's ``send_mail()`` and ``send_mass_mail()`` functions are actually thin +wrappers that make use of the ``EmailMessage`` and ``SMTPConnection`` classes +in ``django.core.mail``. If you ever need to customize the way Django sends +e-mail, you can subclass these two classes to suit your needs. + +.. note:: + Not all features of the ``EmailMessage`` class are available through the + ``send_mail()`` and related wrapper functions. If you wish to use advanced + features, such as BCC'ed recipients or multi-part e-mail, you'll need to + create ``EmailMessage`` instances directly. + +In general, ``EmailMessage`` is responsible for creating the e-mail message +itself. ``SMTPConnection`` is responsible for the network connection side of +the operation. This means you can reuse the same connection (an +``SMTPConnection`` instance) for multiple messages. + +The ``EmailMessage`` class is initialized as follows:: + + email = EmailMessage(subject, body, from_email, to, bcc, connection) + +All of these parameters are optional. If ``from_email`` is omitted, the value +from ``settings.DEFAULT_FROM_EMAIL`` is used. Both the ``to`` and ``bcc`` +parameters are lists of addresses, as strings. + +For example:: + + email = EmailMessage('Hello', 'Body goes here', 'from@example.com', + ['to1@example.com', 'to2@example.com'], + ['bcc@example.com']) + +The class has the following methods: + + * ``send()`` sends the message, using either the connection that is + specified in the ``connection`` attribute, or creating a new connection + if none already exists. + + * ``message()`` constructs a ``django.core.mail.SafeMIMEText`` object (a + sub-class of Python's ``email.MIMEText.MIMEText`` class) holding the + message to be sent. If you ever need to extend the `EmailMessage` class, + you'll probably want to override this method to put the content you wish + into the MIME object. + + * ``recipients()`` returns a list of all the recipients of the message, + whether they're recorded in the ``to`` or ``bcc`` attributes. This is + another method you might need to override when sub-classing, because the + SMTP server needs to be told the full list of recipients when the message + is sent. If you add another way to specify recipients in your class, they + need to be returned from this method as well. + +The ``SMTPConnection`` class is initialized with the host, port, username and +password for the SMTP server. If you don't specify one or more of those +options, they are read from your settings file. + +If you're sending lots of messages at once, the ``send_messages()`` method of +the ``SMTPConnection`` class is useful. It takes a list of ``EmailMessage`` +instances (or subclasses) and sends them over a single connection. For example, +if you have a function called ``get_notification_email()`` that returns a +list of ``EmailMessage`` objects representing some periodic e-mail you wish to +send out, you could send this with:: + + connection = SMTPConnection() # Use default settings for connection + messages = get_notification_email() + connection.send_messages(messages) diff --git a/docs/faq.txt b/docs/faq.txt index 33e8ef01b4..bdd8c5360e 100644 --- a/docs/faq.txt +++ b/docs/faq.txt @@ -278,7 +278,7 @@ How do I get started? .. _`Download the code`: http://www.djangoproject.com/download/ .. _`installation guide`: ../install/ -.. _tutorial: ../tutorial1/ +.. _tutorial: ../tutorial01/ .. _documentation: ../ .. _ask questions: http://www.djangoproject.com/community/ @@ -328,8 +328,9 @@ Do I have to use mod_python? Although we recommend mod_python for production use, you don't have to use it, thanks to the fact that Django uses an arrangement called WSGI_. Django can -talk to any WSGI-enabled server. The most common non-mod_python deployment -setup is FastCGI. See `How to use Django with FastCGI`_ for full information. +talk to any WSGI-enabled server. Other non-mod_python deployment setups are +FastCGI, SCGI or AJP. See `How to use Django with FastCGI, SCGI or AJP`_ for +full information. Also, see the `server arrangements wiki page`_ for other deployment strategies. @@ -337,7 +338,7 @@ If you just want to play around and develop things on your local computer, use the development Web server that comes with Django. Things should Just Work. .. _WSGI: http://www.python.org/peps/pep-0333.html -.. _How to use Django with FastCGI: ../fastcgi/ +.. _How to use Django with FastCGI, SCGI or AJP: ../fastcgi/ .. _server arrangements wiki page: http://code.djangoproject.com/wiki/ServerArrangements How do I install mod_python on Windows? @@ -381,9 +382,9 @@ Why do I get an error about importing DJANGO_SETTINGS_MODULE? Make sure that: * The environment variable DJANGO_SETTINGS_MODULE is set to a fully-qualified - Python module (i.e. "mysite.settings.main"). + Python module (i.e. "mysite.settings"). - * Said module is on ``sys.path`` (``import mysite.settings.main`` should work). + * Said module is on ``sys.path`` (``import mysite.settings`` should work). * The module doesn't contain syntax errors (of course). @@ -511,7 +512,7 @@ type, create an initial data file and put something like this in it:: As explained in the `SQL initial data file`_ documentation, this SQL file can contain arbitrary SQL, so you can make any sorts of changes you need to make. -.. _SQL initial data file: ../model_api/#providing-initial-sql-data +.. _SQL initial data file: ../model-api/#providing-initial-sql-data Why is Django leaking memory? ----------------------------- diff --git a/docs/fastcgi.txt b/docs/fastcgi.txt index 5ecaac8666..81888bba76 100644 --- a/docs/fastcgi.txt +++ b/docs/fastcgi.txt @@ -1,11 +1,17 @@ -============================== -How to use Django with FastCGI -============================== +=========================================== +How to use Django with FastCGI, SCGI or AJP +=========================================== Although the `current preferred setup`_ for running Django is Apache_ with -`mod_python`_, many people use shared hosting, on which FastCGI is the only -viable option. In some setups, FastCGI also allows better security -- and, -possibly, better performance -- than mod_python. +`mod_python`_, many people use shared hosting, on which protocols such as +FastCGI, SCGI or AJP are the only viable options. In some setups, these protocols +also allow better security -- and, possibly, better performance -- than mod_python. + +.. admonition:: Note + + This document primarily focuses on FastCGI. Other protocols, such as SCGI + and AJP, are also supported, through the ``flup`` Python package. See the + "Protocols" section below for specifics about SCGI and AJP. Essentially, FastCGI is an efficient way of letting an external application serve pages to a Web server. The Web server delegates the incoming Web requests @@ -74,10 +80,26 @@ your ``manage.py`` is), and then run ``manage.py`` with the ``runfcgi`` option:: If you specify ``help`` as the only option after ``runfcgi``, it'll display a list of all the available options. -You'll need to specify either a ``socket`` or both ``host`` and ``port``. Then, -when you set up your Web server, you'll just need to point it at the host/port +You'll need to specify either a ``socket``, ``protocol`` or both ``host`` and ``port``. +Then, when you set up your Web server, you'll just need to point it at the host/port or socket you specified when starting the FastCGI server. +Protocols +--------- + +Django supports all the protocols that flup_ does, namely fastcgi_, `SCGI`_ and +`AJP1.3`_ (the Apache JServ Protocol, version 1.3). Select your preferred +protocol by using the ``protocol=<protocol_name>`` option with +``./manage.py runfcgi`` -- where ``<protocol_name>`` may be one of: ``fcgi`` +(the default), ``scgi`` or ``ajp``. For example:: + + ./manage.py runfcgi --protocol=scgi + +.. _flup: http://www.saddi.com/software/flup/ +.. _fastcgi: http://www.fastcgi.com/ +.. _SCGI: http://python.ca/scgi/protocol.txt +.. _AJP1.3: http://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html + Examples -------- @@ -181,7 +203,7 @@ This is probably the most common case, if you're using Django's admin site:: DocumentRoot /home/user/public_html Alias /media /home/user/python/django/contrib/admin/media RewriteEngine On - RewriteRule ^/(media.*)$ /$1 [QSA,L] + RewriteRule ^/(media.*)$ /$1 [QSA,L,PT] RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^/(.*)$ /mysite.fcgi/$1 [QSA,L] </VirtualHost> diff --git a/docs/flatpages.txt b/docs/flatpages.txt index cb910e812d..1422f16b6b 100644 --- a/docs/flatpages.txt +++ b/docs/flatpages.txt @@ -84,9 +84,9 @@ Flatpages are represented by a standard `Django model`_, which lives in `django/contrib/flatpages/models.py`_. You can access flatpage objects via the `Django database API`_. -.. _Django model: ../model_api/ +.. _Django model: ../model-api/ .. _django/contrib/flatpages/models.py: http://code.djangoproject.com/browser/django/trunk/django/contrib/flatpages/models.py -.. _Django database API: ../db_api/ +.. _Django database API: ../db-api/ Flatpage templates ================== diff --git a/docs/forms.txt b/docs/forms.txt index f76f6d27ef..f6cb55a3f6 100644 --- a/docs/forms.txt +++ b/docs/forms.txt @@ -517,10 +517,10 @@ to put punctuation at the end of your validation messages. When are validators called? --------------------------- -After a form has been submitted, Django first checks to see that all the -required fields are present and non-empty. For each field that passes that -test *and if the form submission contained data* for that field, all the -validators for that field are called in turn. The emphasized portion in the +After a form has been submitted, Django validates each field in turn. First, +if the field is required, Django checks that it is present and non-empty. Then, +if that test passes *and the form submission contained data* for that field, all +the validators for that field are called in turn. The emphasized portion in the last sentence is important: if a form field is not submitted (because it contains no data -- which is normal HTML behavior), the validators are not run against the field. @@ -567,6 +567,7 @@ check for the given property: * isValidANSIDate * isValidANSITime * isValidEmail + * isValidFloat * isValidImage * isValidImageURL * isValidPhone @@ -615,15 +616,19 @@ fails. If no message is passed in, a default message is used. ``other_value``, then the validators in ``validator_list`` are all run against the current field. +``RequiredIfOtherFieldGiven`` + Takes a field name of the current field is only required if the other + field has a value. + +``RequiredIfOtherFieldsGiven`` + Similar to ``RequiredIfOtherFieldGiven``, except that it takes a list of + field names and if any one of the supplied fields has a value provided, + the current field being validated is required. + ``RequiredIfOtherFieldNotGiven`` Takes the name of the other field and this field is only required if the other field has no value. -``RequiredIfOtherFieldsNotGiven`` - Similar to ``RequiredIfOtherFieldNotGiven``, except that it takes a list - of field names and if any one of the supplied fields does not have a value - provided, the field being validated is required. - ``RequiredIfOtherFieldEquals`` and ``RequiredIfOtherFieldDoesNotEqual`` Each of these validator classes takes a field name and a value (in that order). If the given field does (or does not have, in the latter case) the @@ -650,8 +655,8 @@ fails. If no message is passed in, a default message is used. ``NumberIsInRange`` Takes two boundary numbers, ``lower`` and ``upper``, and checks that the field is greater than ``lower`` (if given) and less than ``upper`` (if - given). - + given). + Both checks are inclusive. That is, ``NumberIsInRange(10, 20)`` will allow values of both 10 and 20. This validator only checks numeric values (e.g., float and integer values). @@ -660,10 +665,10 @@ fails. If no message is passed in, a default message is used. Takes an integer argument and when called as a validator, checks that the field being validated is a power of the integer. -``IsValidFloat`` +``IsValidDecimal`` Takes a maximum number of digits and number of decimal places (in that - order) and validates whether the field is a float with less than the - maximum number of digits and decimal place. + order) and validates whether the field is a decimal with no more than the + maximum number of digits and decimal places. ``MatchesRegularExpression`` Takes a regular expression (a string) as a parameter and validates the @@ -691,5 +696,5 @@ fails. If no message is passed in, a default message is used. document for more details). .. _`generic views`: ../generic_views/ -.. _`models API`: ../model_api/ +.. _`models API`: ../model-api/ .. _settings: ../settings/ diff --git a/docs/generic_views.txt b/docs/generic_views.txt index 7659a428c5..359a82506a 100644 --- a/docs/generic_views.txt +++ b/docs/generic_views.txt @@ -44,7 +44,7 @@ simple weblog app that drives the blog on djangoproject.com:: (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\w{1,2})/$', 'archive_day', info_dict), (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$', 'archive_month', info_dict), (r'^(?P<year>\d{4})/$', 'archive_year', info_dict), - (r'^/?$', 'archive_index', info_dict), + (r'^$', 'archive_index', info_dict), ) As you can see, this URLconf defines a few options in ``info_dict``. @@ -71,7 +71,7 @@ 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: ../db_api/ +.. _database API docs: ../db-api/ "Simple" generic views ====================== @@ -99,6 +99,9 @@ which is a dictionary of the parameters captured in the URL. dictionary is callable, the generic view will call it just before rendering the template. + * ``mimetype``: The MIME type to use for the resulting document. Defaults + to the value of the ``DEFAULT_CONTENT_TYPE`` setting. + **Example:** Given the following URL patterns:: @@ -222,7 +225,7 @@ In addition to ``extra_context``, the template's context will be: by ``date_field``. For example, if ``num_latest`` is ``10``, then ``latest`` will be a list of the latest 10 objects in ``queryset``. -.. _RequestContext docs: ../templates_python/#subclassing-context-djangocontext +.. _RequestContext docs: ../templates_python/#subclassing-context-requestcontext ``django.views.generic.date_based.archive_year`` ------------------------------------------------ diff --git a/docs/i18n.txt b/docs/i18n.txt index 4a05e53ddf..27abadacc9 100644 --- a/docs/i18n.txt +++ b/docs/i18n.txt @@ -175,7 +175,7 @@ class, though:: verbose_name = _('my thing') verbose_name_plural = _('mythings') -.. _Django models: ../model_api/ +.. _Django models: ../model-api/ Pluralization ~~~~~~~~~~~~~ @@ -236,7 +236,7 @@ To pluralize, specify both the singular and plural forms with the ``{% plural %}`` tag, which appears within ``{% blocktrans %}`` and ``{% endblocktrans %}``. Example:: - {% blocktrans count list|count as counter %} + {% blocktrans count list|length as counter %} There is only one {{ name }} object. {% plural %} There are {{ counter }} {{ name }} objects. @@ -310,7 +310,7 @@ To create or update a message file, run this command:: ...where ``de`` is the language code for the message file you want to create. The language code, in this case, is in locale format. For example, it's -``pt_BR`` for Brazilian and ``de_AT`` for Austrian German. +``pt_BR`` for Brazilian Portugese and ``de_AT`` for Austrian German. The script should be run from one of three places: @@ -463,8 +463,8 @@ following this algorithm: Notes: * In each of these places, the language preference is expected to be in the - standard language format, as a string. For example, Brazilian is - ``pt-br``. + standard language format, as a string. For example, Brazilian Portugese + is ``pt-br``. * If a base language is available but the sublanguage specified is not, Django uses the base language. For example, if a user specifies ``de-at`` (Austrian German) but Django only has ``de`` available, Django uses diff --git a/docs/install.txt b/docs/install.txt index 3eede02af0..4f5a4bbe31 100644 --- a/docs/install.txt +++ b/docs/install.txt @@ -11,8 +11,8 @@ Being a Python Web framework, Django requires Python. It works with any Python version 2.3 and higher. -Get Python at www.python.org. If you're running Linux or Mac OS X, you probably -already have it installed. +Get Python at http://www.python.org. If you're running Linux or Mac OS X, you +probably already have it installed. Install Apache and mod_python ============================= @@ -45,19 +45,20 @@ Get your database running ========================= If you plan to use Django's database API functionality, you'll need to -make sure a database server is running. Django works with PostgreSQL_ -(recommended), MySQL_ and SQLite_. +make sure a database server is running. Django works with PostgreSQL_, +MySQL_ and SQLite_. Additionally, you'll need to make sure your Python database bindings are installed. -* If you're using PostgreSQL, you'll need the psycopg_ package (version 2 is - recommended with ``postgresql_psycopg2`` backend, version 1.1 works also with the - ``postgresql``` backend). - +* If you're using PostgreSQL, you'll need the psycopg_ package. Django supports + both version 1 and 2. (When you configure Django's database layer, specify + either ``postgresql`` [for version 1] or ``postgresql_psycopg2`` [for version 2].) + If you're on Windows, check out the unofficial `compiled Windows version`_. - + * If you're using MySQL, you'll need MySQLdb_, version 1.2.1p2 or higher. + You will also want to read the database-specific notes for the `MySQL backend`_. * If you're using SQLite, you'll need pysqlite_. Use version 2.0.3 or higher. @@ -69,6 +70,36 @@ installed. .. _MySQLdb: http://sourceforge.net/projects/mysql-python .. _SQLite: http://www.sqlite.org/ .. _pysqlite: http://initd.org/tracker/pysqlite +.. _MySQL backend: ../databases/ + +Remove any old versions of Django +================================= + +If you are upgrading your installation of Django from a previous version, +you will need to uninstall the old Django version before installing the +new version. + +If you installed Django using ``setup.py install``, uninstalling +is as simple as deleting the ``django`` directory from your Python +``site-packages``. + +If you installed Django from a Python Egg, remove the Django ``.egg`` file, +and remove the reference to the egg in the file named ``easy-install.pth``. +This file should also be located in your ``site-packages`` directory. + +.. admonition:: Where are my ``site-packages`` stored? + + The location of the ``site-packages`` directory depends on the operating + system, and the location in which Python was installed. However, the + following locations are common: + + * If you're using Linux: ``/usr/lib/python2.X/site-packages`` + + * If you're using Windows: ``C:\Python2.X\lib\site-packages`` + + * If you're using MacOSX: ``/Library/Python2.X/site-packages`` or + ``/Library/Frameworks/Python.framework/Versions/2.X/lib/python2.X/site-packages/`` + (in later releases). Install the Django code ======================= @@ -86,25 +117,17 @@ Installing the official version Distribution-provided packages will typically allow for automatic installation of dependancies and easy upgrade paths. - 2. Download Django-0.95.tar.gz from our `download page`_. - - 3. ``tar xzvf Django-0.95.tar.gz`` + 2. Download the latest release from our `download page`_. - 4. ``cd Django-0.95`` + 3. Untar the downloaded file (e.g. ``tar xzvf Django-NNN.tar.gz``). - 5. ``sudo python setup.py install`` + 4. Change into the downloaded directory (e.g. ``cd Django-NNN``). -Note that the last command will automatically download and install setuptools_ -if you don't already have it installed. This requires a working Internet -connection and may cause problems on Python 2.5. If you run into problems, -try using our development version by following the instructions below. The -development version no longer uses setuptools nor requires an Internet -connection. + 5. Run ``sudo python setup.py install``. The command will install Django in your Python installation's ``site-packages`` directory. -.. _setuptools: http://peak.telecommunity.com/DevCenter/setuptools .. _distribution specific notes: ../distributions/ Installing the development version diff --git a/docs/legacy_databases.txt b/docs/legacy_databases.txt index 8230c11f61..ca3927e52f 100644 --- a/docs/legacy_databases.txt +++ b/docs/legacy_databases.txt @@ -9,7 +9,7 @@ utilities to automate as much of this process as possible. This document assumes you know the Django basics, as covered in the `official tutorial`_. -.. _official tutorial: ../tutorial1/ +.. _official tutorial: ../tutorial01/ Give Django your database parameters ==================================== @@ -39,11 +39,11 @@ Auto-generate the models Django comes with a utility that can create models by introspecting an existing database. You can view the output by running this command:: - django-admin.py inspectdb --settings=path.to.settings + python manage.py inspectdb Save this as a file by using standard Unix output redirection:: - django-admin.py inspectdb --settings=path.to.settings > models.py + python manage.py inspectdb > models.py This feature is meant as a shortcut, not as definitive model generation. See the `django-admin.py documentation`_ for more information. @@ -52,7 +52,7 @@ Once you've cleaned up your models, name the file ``models.py`` and put it in the Python package that holds your app. Then add the app to your ``INSTALLED_APPS`` setting. -.. _django-admin.py documentation: ../django_admin/ +.. _django-admin.py documentation: ../django-admin/ Install the core Django tables ============================== @@ -60,7 +60,7 @@ Install the core Django tables Next, run the ``manage.py syncdb`` command to install any extra needed database records such as admin permissions and content types:: - django-admin.py init --settings=path.to.settings + python manage.py syncdb See whether it worked ===================== diff --git a/docs/man/django-admin.1 b/docs/man/django-admin.1 new file mode 100644 index 0000000000..fec5053ccb --- /dev/null +++ b/docs/man/django-admin.1 @@ -0,0 +1,162 @@ +.TH "django-admin.py" "1" "June 2007" "Django Project" "" +.SH "NAME" +django\-admin.py \- Utility script for the Django web framework +.SH "SYNOPSIS" +.B django\-admin.py +.I <action> +.B [options] +.sp +.SH "DESCRIPTION" +This utility script provides commands for creation and maintenance of Django +projects and apps. +.sp +With the exception of +.BI startproject, +all commands listed below can also be performed with the +.BI manage.py +script found at the top level of each Django project directory. +.sp +.SH "ACTIONS" +.TP +.BI "adminindex [" "appname ..." "]" +Prints the admin\-index template snippet for the given app name(s). +.TP +.BI "createcachetable [" "tablename" "]" +Creates the table needed to use the SQL cache backend +.TP +.B dbshell +Runs the command\-line client for the current +.BI DATABASE_ENGINE. +.TP +.B diffsettings +Displays differences between the current +.B settings.py +and Django's default settings. Settings that don't appear in the defaults are +followed by "###". +.TP +.B inspectdb +Introspects the database tables in the database specified in settings.py and outputs a Django +model module. +.TP +.BI "install [" "appname ..." "]" +Executes +.B sqlall +for the given app(s) in the current database. +.TP +.BI "reset [" "appname ..." "]" +Executes +.B sqlreset +for the given app(s) in the current database. +.TP +.BI "runfcgi [" "KEY=val" "] [" "KEY=val" "] " "..." +Runs this project as a FastCGI application. Requires flup. Use +.B runfcgi help +for help on the KEY=val pairs. +.TP +.BI "runserver [" "\-\-noreload" "] [" "\-\-adminmedia=ADMIN_MEDIA_PATH" "] [" "port|ipaddr:port" "]" +Starts a lightweight Web server for development. +.TP +.BI "shell [" "\-\-plain" "]" +Runs a Python interactive interpreter. Tries to use IPython, if it's available. +The +.BI \-\-plain +option forces the use of the standard Python interpreter even when IPython is +installed. +.TP +.BI "sql [" "appname ..." "]" +Prints the CREATE TABLE SQL statements for the given app name(s). +.TP +.BI "sqlall [" "appname ..." "]" +Prints the CREATE TABLE, initial\-data and CREATE INDEX SQL statements for the +given model module name(s). +.TP +.BI "sqlclear [" "appname ..." "]" +Prints the DROP TABLE SQL statements for the given app name(s). +.TP +.BI "sqlindexes [" "appname ..." "]" +Prints the CREATE INDEX SQL statements for the given model module name(s). +.TP +.BI "sqlinitialdata [" "appname ..." "]" +Prints the initial INSERT SQL statements for the given app name(s). +.TP +.BI "sqlreset [" "appname ..." "]" +Prints the DROP TABLE SQL, then the CREATE TABLE SQL, for the given app +name(s). +.TP +.BI "sqlsequencereset [" "appname ..." "]" +Prints the SQL statements for resetting PostgreSQL sequences for the +given app name(s). +.TP +.BI "startapp [" "appname" "]" +Creates a Django app directory structure for the given app name in +the current directory. +.TP +.BI "startproject [" "projectname" "]" +Creates a Django project directory structure for the given project name +in the current directory. +.TP +.BI syncdb +Creates the database tables for all apps in INSTALLED_APPS whose tables +haven't already been created. +.TP +.BI "test [" "\-\-verbosity" "] [" "appname ..." "]" +Runs the test suite for the specified applications, or the entire project if +no apps are specified +.TP +.BI validate +Validates all installed models. +.SH "OPTIONS" +.TP +.I \-\-version +Show program's version number and exit. +.TP +.I \-h, \-\-help +Show this help message and exit. +.TP +.I \-\-settings=SETTINGS +Python path to settings module, e.g. "myproject.settings.main". If +this isn't provided, the DJANGO_SETTINGS_MODULE environment variable +will be used. +.TP +.I \-\-pythonpath=PYTHONPATH +Lets you manually add a directory the Python path, +e.g. "/home/djangoprojects/myproject". +.TP +.I \-\-plain +Use plain Python, not IPython, for the "shell" command. +.TP +.I \-\-noinput +Do not prompt the user for input. +.TP +.I \-\-noreload +Disable the development server's auto\-reloader. +.TP +.I \-\-verbosity=VERBOSITY +Verbosity level: 0=minimal output, 1=normal output, 2=all output. +.TP +.I \-\-adminmedia=ADMIN_MEDIA_PATH +Specifies the directory from which to serve admin media when using the development server. + +.SH "ENVIRONMENT" +.TP +.I DJANGO_SETTINGS_MODULE +In the absence of the +.BI \-\-settings +option, this environment variable defines the settings module to be read. +It should be in Python-import form, e.g. "myproject.settings". + +.SH "SEE ALSO" +Full descriptions of all these options, with examples, as well as documentation +for the rest of the Django framework, can be found on the Django site: +.sp +.I http://www.djangoproject.com/documentation/ +.sp +or in the distributed documentation. +.SH "AUTHORS/CREDITS" +Originally developed at World Online in Lawrence, Kansas, USA. Refer to the +AUTHORS file in the Django distribution for contributors. +.sp +.SH "LICENSE" +New BSD license. For the full license text refer to the LICENSE file in the +Django distribution. + diff --git a/docs/model-api.txt b/docs/model-api.txt index 155ef63271..09440f2b56 100644 --- a/docs/model-api.txt +++ b/docs/model-api.txt @@ -21,7 +21,7 @@ A companion to this document is the `official repository of model examples`_. (In the Django source distribution, these examples are in the ``tests/modeltests`` directory.) -.. _Database API reference: http://www.djangoproject.com/documentation/db_api/ +.. _Database API reference: ../db-api/ .. _official repository of model examples: http://www.djangoproject.com/documentation/models/ Quick example @@ -57,7 +57,7 @@ Some technical notes: syntax, but it's worth noting Django uses SQL tailored to the database backend specified in your `settings file`_. -.. _settings file: http://www.djangoproject.com/documentation/settings/ +.. _settings file: ../settings/ Fields ====== @@ -184,6 +184,35 @@ A date and time field. Takes the same extra options as ``DateField``. The admin represents this as two ``<input type="text">`` fields, with JavaScript shortcuts. +``DecimalField`` +~~~~~~~~~~~~~~~~ + +**New in Django development version** + +A fixed-precision decimal number, represented in Python by a ``Decimal`` instance. +Has two **required** arguments: + + ====================== =================================================== + Argument Description + ====================== =================================================== + ``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) + +The admin represents this as an ``<input type="text">`` (a single-line input). + ``EmailField`` ~~~~~~~~~~~~~~ @@ -194,14 +223,23 @@ This doesn't accept ``maxlength``; its ``maxlength`` is automatically set to ``FileField`` ~~~~~~~~~~~~~ -A file-upload field. +A file-upload field. Has one **required** argument: + + ====================== =================================================== + Argument Description + ====================== =================================================== + ``upload_to`` A local filesystem path that will be appended to + your ``MEDIA_ROOT`` setting to determine the + output of the ``get_<fieldname>_url()`` helper + function. + ====================== =================================================== -Has an extra required argument, ``upload_to``, a local filesystem path to -which files should be upload. This path may contain `strftime formatting`_, -which will be replaced by the date/time of the file upload (so that -uploaded files don't fill up the given directory). +This path may contain `strftime formatting`_, which will be replaced by the +date/time of the file upload (so that uploaded files don't fill up the given +directory). -The admin represents this as an ``<input type="file">`` (a file-upload widget). +The admin represents this field as an ``<input type="file">`` (a file-upload +widget). Using a ``FileField`` or an ``ImageField`` (see below) in a model takes a few steps: @@ -231,6 +269,13 @@ For example, say your ``MEDIA_ROOT`` is set to ``'/home/media'``, and 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 +``get_FOO_filename()``, ``get_FOO_url()`` and ``get_FOO_size()`` methods. +They are all documented here__. + +__ ../db-api/#get-foo-filename + 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 @@ -246,7 +291,7 @@ visiting its URL on your site. Don't allow that. A field whose choices are limited to the filenames in a certain directory on the filesystem. Has three special arguments, of which the first is -required: +**required**: ====================== =================================================== Argument Description @@ -281,28 +326,16 @@ because the ``match`` applies to the base filename (``foo.gif`` and ``FloatField`` ~~~~~~~~~~~~~~ -A floating-point number. Has two **required** arguments: +**Changed in Django development version** - ====================== =================================================== - Argument Description - ====================== =================================================== - ``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.FloatField(..., max_digits=5, decimal_places=2) +A floating-point number represented in Python by a ``float`` instance. -And to store numbers up to approximately one billion with a resolution of 10 -decimal places:: +The admin represents this as an ``<input type="text">`` (a single-line input). - models.FloatField(..., max_digits=19, decimal_places=10) +**NOTE:** The semantics of ``FloatField`` have changed in the Django +development version. See the `Django 0.96 documentation`_ for the old behavior. -The admin represents this as an ``<input type="text">`` (a single-line input). +.. _Django 0.96 documentation: http://www.djangoproject.com/documentation/0.96/model-api/#floatfield ``ImageField`` ~~~~~~~~~~~~~~ @@ -312,9 +345,14 @@ image. Has two extra optional arguments, ``height_field`` and ``width_field``, which, if set, will be auto-populated with the height and width of the image each time a model instance is saved. +In addition to the special ``get_FOO_*`` methods that are available for +``FileField``, an ``ImageField`` also has ``get_FOO_height()`` and +``get_FOO_width()`` methods. These are documented elsewhere_. + Requires the `Python Imaging Library`_. .. _Python Imaging Library: http://www.pythonware.com/products/pil/ +.. _elsewhere: ../db-api/#get-foo-height-and-get-foo-width ``IntegerField`` ~~~~~~~~~~~~~~~~ @@ -409,6 +447,11 @@ and doesn't give a 404 response). The admin represents this as an ``<input type="text">`` (a single-line input). +``URLField`` takes an optional argument, ``maxlength``, the maximum length (in +characters) of the field. The maxlength is enforced at the database level and +in Django's validation. If you don't specify ``maxlength``, a default of 200 +is used. + ``USStateField`` ~~~~~~~~~~~~~~~~ @@ -437,8 +480,10 @@ If ``True``, Django will store empty values as ``NULL`` in the database. Default is ``False``. Note that empty string values will always get stored as empty strings, not -as ``NULL`` -- so use ``null=True`` for non-string fields such as integers, -booleans and dates. +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_, below). Avoid using ``null`` on string-based fields such as ``CharField`` and ``TextField`` unless you have an excellent reason. If a string-based field @@ -450,7 +495,7 @@ string, not ``NULL``. ``blank`` ~~~~~~~~~ -If ``True``, the field is allowed to be blank. +If ``True``, the field is allowed to be blank. Default is ``False``. Note that this is different than ``null``. ``null`` is purely database-related, whereas ``blank`` is validation-related. If a field has @@ -501,7 +546,7 @@ For each model field that has ``choices`` set, Django will add a method to retrieve the human-readable name for the field's current value. See `get_FOO_display`_ in the database API documentation. -.. _get_FOO_display: ../db_api/#get-foo-display +.. _get_FOO_display: ../db-api/#get-foo-display 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 @@ -626,7 +671,7 @@ that takes the parameters ``field_data, all_data`` and raises Django comes with quite a few validators. They're in ``django.core.validators``. -.. _validator docs: http://www.djangoproject.com/documentation/forms/#validators +.. _validator docs: ../forms/#validators Verbose field names ------------------- @@ -734,10 +779,10 @@ relationship should work. All are optional: ``limit_choices_to`` A dictionary of lookup arguments and values (see the `Database API reference`_) that limit the available admin choices for this object. Use this - with ``models.LazyDate`` to limit choices of objects - by date. For example:: + with functions from the Python ``datetime`` module + to limit choices of objects by date. For example:: - limit_choices_to = {'pub_date__lte': models.LazyDate()} + 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 @@ -792,8 +837,8 @@ relationship should work. All are optional: the related object. ======================= ============================================================ -.. _`Database API reference`: http://www.djangoproject.com/documentation/db_api/ -.. _related objects documentation: http://www.djangoproject.com/documentation/db_api/#related-objects +.. _`Database API reference`: ../db-api/ +.. _related objects documentation: ../db-api/#related-objects Many-to-many relationships ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -963,7 +1008,7 @@ Example:: See the `docs for latest()`_ for more. -.. _docs for latest(): http://www.djangoproject.com/documentation/db_api/#latest-field-name-none +.. _docs for latest(): ../db-api/#latest-field-name-none ``order_with_respect_to`` ------------------------- @@ -1307,13 +1352,13 @@ A few special cases to note about ``list_display``: * Usually, elements of ``list_display`` that aren't actual database fields can't be used in sorting (because Django does all the sorting at the database level). - + However, if an element of ``list_display`` represents a certain database field, you can indicate this fact by setting the ``admin_order_field`` attribute of the item. - + For example:: - + class Person(models.Model): first_name = models.CharField(maxlength=50) color_code = models.CharField(maxlength=6) @@ -1325,7 +1370,7 @@ A few special cases to note about ``list_display``: return '<span style="color: #%s;">%s</span>' % (self.color_code, self.first_name) colored_first_name.allow_tags = True colored_first_name.admin_order_field = 'first_name' - + The above will tell Django to order by the ``first_name`` field when trying to sort by ``colored_first_name`` in the admin. @@ -1397,7 +1442,7 @@ if one of the ``list_display`` fields is a ``ForeignKey``. For more on ``select_related()``, see `the select_related() docs`_. -.. _the select_related() docs: http://www.djangoproject.com/documentation/db_api/#select-related +.. _the select_related() docs: ../db-api/#select-related ``ordering`` ------------ @@ -1502,7 +1547,7 @@ The way ``Manager`` classes work is documented in the `Retrieving objects`_ section of the database API docs, but this section specifically touches on model options that customize ``Manager`` behavior. -.. _Retrieving objects: http://www.djangoproject.com/documentation/db_api/#retrieving-objects +.. _Retrieving objects: ../db-api/#retrieving-objects Manager names ------------- @@ -1750,6 +1795,15 @@ But this template code is good:: <a href="{{ object.get_absolute_url }}">{{ object.name }}</a> +.. note:: + The string you return from ``get_absolute_url()`` must contain only ASCII + characters (required by the URI spec, `RFC 2396`_) that have been + URL-encoded, if necessary. Code and templates using ``get_absolute_url()`` + should be able to use the result directly without needing to do any + further processing. + +.. _RFC 2396: http://www.ietf.org/rfc/rfc2396.txt + The ``permalink`` decorator ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1758,16 +1812,38 @@ slightly violates the DRY principle: the URL for this object is defined both in the URLConf file and in the model. You can further decouple your models from the URLconf using the ``permalink`` -decorator. This decorator is passed the view function and any parameters you -would use for accessing this instance directly. Django then works out the -correct full URL path using the URLconf. For example:: +decorator. This decorator is passed the view function, a list of positional +parameters and (optionally) a dictionary of named parameters. Django then +works out the correct full URL path using the URLconf, substituting the +parameters you have given into the URL. For example, if your URLconf +contained a line such as:: + + (r'^/people/(\d+)/$', 'people.views.details'), + +...your model could have a ``get_absolute_url`` method that looked like this:: from django.db.models import permalink def get_absolute_url(self): - return ('people.views.details', str(self.id)) + return ('people.views.details', [str(self.id)]) get_absolute_url = permalink(get_absolute_url) +Similarly, if you had a URLconf entry that looked like:: + + (r'/archive/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/$', archive_view) + +...you could reference this using ``permalink()`` as follows:: + + def get_absolute_url(self): + return ('archive_view', (), { + 'year': self.created.year, + 'month': self.created.month, + 'day': self.created.day}) + get_absolute_url = permalink(get_absolute_url) + +Notice that we specify an empty sequence for the second argument in this case, +because we only want to pass keyword arguments, not named arguments. + In this way, you're tying the model's absolute URL to the view that is used to display it, without repeating the URL information anywhere. You can still use the ``get_absolute_url`` method in templates, as before. @@ -1789,21 +1865,23 @@ rows. Example:: row = cursor.fetchone() return row -``connection`` and ``cursor`` simply use the standard `Python DB-API`_. If -you're not familiar with the Python DB-API, note that the SQL statement in -``cursor.execute()`` uses placeholders, ``"%s"``, rather than adding parameters -directly within the SQL. If you use this technique, the underlying database -library will automatically add quotes and escaping to your parameter(s) as -necessary. (Also note that Django expects the ``"%s"`` placeholder, *not* the -``"?"`` placeholder, which is used by the SQLite Python bindings. This is for -the sake of consistency and sanity.) +``connection`` and ``cursor`` mostly implement the standard `Python DB-API`_ +(except when it comes to `transaction handling`_). If you're not familiar with +the Python DB-API, note that the SQL statement in ``cursor.execute()`` uses +placeholders, ``"%s"``, rather than adding parameters directly within the SQL. +If you use this technique, the underlying database library will automatically +add quotes and escaping to your parameter(s) as necessary. (Also note that +Django expects the ``"%s"`` placeholder, *not* the ``"?"`` placeholder, which is +used by the SQLite Python bindings. This is for the sake of consistency and +sanity.) A final note: If all you want to do is a custom ``WHERE`` clause, you can just just the ``where``, ``tables`` and ``params`` arguments to the standard lookup 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 +.. _Other lookup options: ../db-api/#extra-params-select-where-tables +.. _transaction handling: ../transactions/ Overriding default model methods -------------------------------- @@ -1836,7 +1914,7 @@ You can also prevent saving:: else: super(Blog, self).save() # Call the "real" save() method. -.. _database API docs: http://www.djangoproject.com/documentation/db_api/ +.. _database API docs: ../db-api/ Models across files =================== @@ -1893,7 +1971,7 @@ 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 +The SQL files are read by the ``sqlcustom``, ``sqlreset``, ``sqlall`` and ``reset`` commands in ``manage.py``. Refer to the `manage.py documentation`_ for more information. @@ -1902,7 +1980,7 @@ 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 +.. _`manage.py documentation`: ../django-admin/#sqlcustom-appname-appname Database-backend-specific SQL data ---------------------------------- diff --git a/docs/modpython.txt b/docs/modpython.txt index 2c999753c7..388a6168f3 100644 --- a/docs/modpython.txt +++ b/docs/modpython.txt @@ -13,14 +13,15 @@ other server arrangements. Django requires Apache 2.x and mod_python 3.x, and you should use Apache's `prefork MPM`_, as opposed to the `worker MPM`_. -You may also be interested in `How to use Django with FastCGI`_. +You may also be interested in `How to use Django with FastCGI, SCGI or AJP`_ +(which also covers SCGI and AJP). .. _Apache: http://httpd.apache.org/ .. _mod_python: http://www.modpython.org/ .. _mod_perl: http://perl.apache.org/ .. _prefork MPM: http://httpd.apache.org/docs/2.2/mod/prefork.html .. _worker MPM: http://httpd.apache.org/docs/2.2/mod/worker.html -.. _How to use Django with FastCGI: ../fastcgi/ +.. _How to use Django with FastCGI, SCGI or AJP: ../fastcgi/ Basic configuration =================== @@ -37,7 +38,8 @@ Then edit your ``httpd.conf`` file and add the following:: PythonDebug On </Location> -...and replace ``mysite.settings`` with the Python path to your settings file. +...and replace ``mysite.settings`` with the Python import path to your Django +project's settings file. This tells Apache: "Use mod_python for any URL at or under '/mysite/', using the Django mod_python handler." It passes the value of ``DJANGO_SETTINGS_MODULE`` @@ -49,9 +51,29 @@ whereas ``<Location>`` points at places in the URL structure of a Web site. ``<Directory>`` would be meaningless here. Also, if you've manually altered your ``PYTHONPATH`` to put your Django project -on it, you'll need to tell mod_python:: +on it, you'll need to tell mod_python: - PythonPath "['/path/to/project'] + sys.path" +.. parsed-literal:: + + <Location "/mysite/"> + SetHandler python-program + PythonHandler django.core.handlers.modpython + SetEnv DJANGO_SETTINGS_MODULE mysite.settings + PythonDebug On + **PythonPath "['/path/to/project'] + sys.path"** + </Location> + +.. caution:: + + If you're using Windows, remember that the path will contain backslashes. + This string is passed through Python's string parser twice, so you need to + escape each backslash **twice**:: + + PythonPath "['c:\\\\path\\\\to\\\\project'] + sys.path" + + Or, use raw strings:: + + PythonPath "[r'c:\\path\\to\\project'] + sys.path" You can also add directives such as ``PythonAutoReload Off`` for performance. See the `mod_python documentation`_ for a full list of options. @@ -146,7 +168,7 @@ If, however, you have no option but to serve media files on the same Apache ``VirtualHost`` as Django, here's how you can turn off mod_python for a particular part of the site:: - <Location "/media/"> + <Location "/media"> SetHandler None </Location> @@ -163,7 +185,7 @@ the ``media`` subdirectory and any URL that ends with ``.jpg``, ``.gif`` or SetEnv DJANGO_SETTINGS_MODULE mysite.settings </Location> - <Location "media"> + <Location "/media"> SetHandler None </Location> @@ -197,6 +219,41 @@ Here are two recommended approaches: 2. Or, copy the admin media files so that they live within your Apache document root. +Using eggs with mod_python +========================== + +If you installed Django from a Python egg_ or are using eggs in your Django +project, some extra configuration is required. Create an extra file in your +project (or somewhere else) that contains something like the following:: + + import os + os.environ['PYTHON_EGG_CACHE'] = '/some/directory' + +Here, ``/some/directory`` is a directory that the Apache webserver process can +write to. It will be used as the location for any unpacking of code the eggs +need to do. + +Then you have to tell mod_python to import this file before doing anything +else. This is done using the PythonImport_ directive to mod_python. You need +to ensure that you have specified the ``PythonInterpreter`` directive to +mod_python as described above__ (you need to do this even if you aren't +serving multiple installations in this case). Then add the ``PythonImport`` +line inside the ``Location`` or ``VirtualHost`` section. For example:: + + PythonInterpreter my_django + PythonImport /path/to/my/project/file.py my_django + +Note that you can use an absolute path here (or a normal dotted import path), +as described in the `mod_python manual`_. We use an absolute path in the +above example because if any Python path modifications are required to access +your project, they will not have been done at the time the ``PythonImport`` +line is processed. + +.. _Egg: http://peak.telecommunity.com/DevCenter/PythonEggs +.. _PythonImport: http://www.modpython.org/live/current/doc-html/dir-other-pimp.html +.. _mod_python manual: PythonImport_ +__ `Multiple Django installations on the same Apache`_ + Error handling ============== @@ -242,3 +299,5 @@ as necessary. .. _Expat Causing Apache Crash: http://www.dscpl.com.au/articles/modpython-006.html .. _mod_python FAQ entry: http://modpython.org/FAQ/faqw.py?req=show&file=faq02.013.htp .. _Getting mod_python Working: http://www.dscpl.com.au/articles/modpython-001.html + + diff --git a/docs/newforms.txt b/docs/newforms.txt index d7ef4d2599..1511791a7d 100644 --- a/docs/newforms.txt +++ b/docs/newforms.txt @@ -9,28 +9,30 @@ framework. This document explains how to use this new library. Migration plan ============== -``django.newforms`` currently is only available in Django beginning -with the 0.96 release. the Django development version -- i.e., it's -not available in the Django 0.95 release. For the next Django release, -our plan is to do the following: +``django.newforms`` is new in Django's 0.96 release, but, as it won't be new +forever, we plan to rename it to ``django.forms`` in the future. The current +``django.forms`` package will be available as ``django.oldforms`` until Django +1.0, when we plan to remove it for good. - * As of revision [4208], we've copied the current ``django.forms`` to - ``django.oldforms``. This allows you to upgrade your code *now* rather - than waiting for the backwards-incompatible change and rushing to fix - your code after the fact. Just change your import statements like this:: +That has direct repercussions on the forward compatibility of your code. Please +read the following migration plan and code accordingly: + + * The old forms framework (the current ``django.forms``) has been copied to + ``django.oldforms``. Thus, you can start upgrading your code *now*, + rather than waiting for the future backwards-incompatible change, by + changing your import statements like this:: from django import forms # old from django import oldforms as forms # new - * At an undecided future date, we will move the current ``django.newforms`` - to ``django.forms``. This will be a backwards-incompatible change, and - anybody who is still using the old version of ``django.forms`` at that - time will need to change their import statements, as described in the - previous bullet. + * In the next Django release (0.97), we will move the current + ``django.newforms`` to ``django.forms``. This will be a + backwards-incompatible change, and anybody who is still using the old + version of ``django.forms`` at that time will need to change their import + statements, as described in the previous bullet. * We will remove ``django.oldforms`` in the release *after* the next Django - release -- the release that comes after the release in which we're - creating the new ``django.forms``. + release -- either 0.98 or 1.0, whichever comes first. With this in mind, we recommend you use the following import statement when using ``django.newforms``:: @@ -184,7 +186,7 @@ e-mail address:: >>> f.is_valid() False -Access the ``Form`` attribute ``errors`` to get a dictionary of error messages:: +Access the ``errors`` attribute to get a dictionary of error messages:: >>> f.errors {'sender': [u'Enter a valid e-mail address.'], 'subject': [u'This field is required.']} @@ -197,6 +199,10 @@ You can access ``errors`` without having to call ``is_valid()`` first. The form's data will be validated the first time either you call ``is_valid()`` or access ``errors``. +The validation routines will only get called once, regardless of how many times +you access ``errors`` or call ``is_valid()``. This means that if validation has +side effects, those side effects will only be triggered once. + Behavior of unbound forms ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -224,7 +230,7 @@ object. Regardless of whether you pass it a string in the format it's valid. Once you've created a ``Form`` instance with a set of data and validated it, -you can access the clean data via the ``clean_data`` attribute of the ``Form`` +you can access the clean data via the ``cleaned_data`` attribute of the ``Form`` object:: >>> data = {'subject': 'hello', @@ -234,7 +240,7 @@ object:: >>> f = ContactForm(data) >>> f.is_valid() True - >>> f.clean_data + >>> f.cleaned_data {'cc_myself': True, 'message': u'Hi there', 'sender': u'foo@example.com', 'subject': u'hello'} Note that any text-based field -- such as ``CharField`` or ``EmailField`` -- @@ -242,7 +248,7 @@ always cleans the input into a Unicode string. We'll cover the encoding implications later in this document. If your data does *not* validate, your ``Form`` instance will not have a -``clean_data`` attribute:: +``cleaned_data`` attribute:: >>> data = {'subject': '', ... 'message': 'Hi there', @@ -251,15 +257,15 @@ If your data does *not* validate, your ``Form`` instance will not have a >>> f = ContactForm(data) >>> f.is_valid() False - >>> f.clean_data + >>> f.cleaned_data Traceback (most recent call last): ... - AttributeError: 'ContactForm' object has no attribute 'clean_data' + AttributeError: 'ContactForm' object has no attribute 'cleaned_data' -``clean_data`` will always *only* contain a key for fields defined in the +``cleaned_data`` will always *only* contain a key for fields defined in the ``Form``, even if you pass extra data when you define the ``Form``. In this example, we pass a bunch of extra fields to the ``ContactForm`` constructor, -but ``clean_data`` contains only the form's fields:: +but ``cleaned_data`` contains only the form's fields:: >>> data = {'subject': 'hello', ... 'message': 'Hi there', @@ -271,20 +277,48 @@ but ``clean_data`` contains only the form's fields:: >>> f = ContactForm(data) >>> f.is_valid() True - >>> f.clean_data # Doesn't contain extra_field_1, etc. + >>> f.cleaned_data # Doesn't contain extra_field_1, etc. {'cc_myself': True, 'message': u'Hi there', 'sender': u'foo@example.com', 'subject': u'hello'} +``cleaned_data`` will include a key and value for *all* fields defined in the +``Form``, even if the data didn't include a value for fields that are not +required. In this example, the data dictionary doesn't include a value for the +``nick_name`` field, but ``cleaned_data`` includes it, with an empty value:: + + >>> class OptionalPersonForm(Form): + ... first_name = CharField() + ... last_name = CharField() + ... nick_name = CharField(required=False) + >>> data = {'first_name': u'John', 'last_name': u'Lennon'} + >>> f = OptionalPersonForm(data) + >>> f.is_valid() + True + >>> f.cleaned_data + {'nick_name': u'', 'first_name': u'John', 'last_name': u'Lennon'} + +In this above example, the ``cleaned_data`` value for ``nick_name`` is set to an +empty string, because ``nick_name`` is ``CharField``, and ``CharField``\s treat +empty values as an empty string. Each field type knows what its "blank" value +is -- e.g., for ``DateField``, it's ``None`` instead of the empty string. For +full details on each field's behavior in this case, see the "Empty value" note +for each field in the "Built-in ``Field`` classes" section below. + +You can write code to perform validation for particular form fields (based on +their name) or for the form as a whole (considering combinations of various +fields). More information about this is in the `Custom form and field +validation`_ section, below. + Behavior of unbound forms ~~~~~~~~~~~~~~~~~~~~~~~~~ -It's meaningless to request "clean" data in a form with no data, but, for the +It's meaningless to request "cleaned" data in a form with no data, but, for the record, here's what happens with unbound forms:: >>> f = ContactForm() - >>> f.clean_data + >>> f.cleaned_data Traceback (most recent call last): ... - AttributeError: 'ContactForm' object has no attribute 'clean_data' + AttributeError: 'ContactForm' object has no attribute 'cleaned_data' Outputting forms as HTML ------------------------ @@ -454,7 +488,7 @@ field:: If ``auto_id`` is set to a string containing the format character ``'%s'``, then the form output will include ``<label>`` tags, and will generate ``id`` attributes based on the format string. For example, for a format string -``'field_%s'``, a field named ``subject`` will get the ``id`` +``'field_%s'``, a field named ``subject`` will get the ``id`` value ``'field_subject'``. Continuing our example:: >>> f = ContactForm(auto_id='id_for_%s') @@ -493,8 +527,9 @@ How errors are displayed If you render a bound ``Form`` object, the act of rendering will automatically run the form's validation if it hasn't already happened, and the HTML output -will include the validation errors as a ``<ul>`` near the field. The particular -positioning of the error messages depends on the output method you're using:: +will include the validation errors as a ``<ul class="errorlist">`` near the +field. The particular positioning of the error messages depends on the output +method you're using:: >>> data = {'subject': '', ... 'message': 'Hi there', @@ -556,7 +591,8 @@ The field-specific output honors the form object's ``auto_id`` setting:: <input type="text" name="message" id="id_message" /> For a field's list of errors, access the field's ``errors`` attribute. This -is a list-like object that is displayed as an HTML ``<ul>`` when printed:: +is a list-like object that is displayed as an HTML ``<ul class="errorlist">`` +when printed:: >>> data = {'subject': 'hi', 'message': '', 'sender': '', 'cc_myself': ''} >>> f = ContactForm(data, auto_id=False) @@ -573,10 +609,114 @@ is a list-like object that is displayed as an HTML ``<ul>`` when printed:: >>> str(f['subject'].errors) '' +Using forms in views and templates +---------------------------------- + +Let's put this all together and use the ``ContactForm`` example in a Django +view and template. + +Simple view example +~~~~~~~~~~~~~~~~~~~ + +This example view displays the contact form by default and validates/processes +it if accessed via a POST request:: + + def contact(request): + if request.method == 'POST': + form = ContactForm(request.POST) + if form.is_valid(): + # Do form processing here... + return HttpResponseRedirect('/url/on_success/') + else: + form = ContactForm() + return render_to_response('contact.html', {'form': form}) + +Simple template example +~~~~~~~~~~~~~~~~~~~~~~~ + +The template in the above view example, ``contact.html``, is responsible for +displaying the form as HTML. To do this, we can use the techniques outlined in +the "Outputting forms as HTML" section above. + +The simplest way to display a form's HTML is to use the variable on its own, +like this:: + + <form method="post"> + <table>{{ form }}</table> + <input type="submit" /> + </form> + +The above template code will display the form as an HTML table, using the +``form.as_table()`` method explained previously. This works because Django's +template system displays an object's ``__str__()`` value, and the ``Form`` +class' ``__str__()`` method calls its ``as_table()`` method. + +The following is equivalent but a bit more explicit:: + + <form method="post"> + <table>{{ form.as_table }}</table> + <input type="submit" /> + </form> + +``form.as_ul`` and ``form.as_p`` are also available, as you may expect. + +Note that in the above two examples, we included the ``<form>``, ``<table>`` +``<input type="submit" />``, ``</table>`` and ``</form>`` tags. The form +convenience methods (``as_table()``, ``as_ul()`` and ``as_p()``) do not include +that HTML. + +Complex template output +~~~~~~~~~~~~~~~~~~~~~~~ + +As we've stressed several times, the ``as_table()``, ``as_ul()`` and ``as_p()`` +methods are just shortcuts for the common case. You can also work with the +individual fields for complete template control over the form's design. + +The easiest way is to iterate over the form's fields, with +``{% for field in form %}``. For example:: + + <form method="post"> + <dl> + {% for field in form %} + <dt>{{ field.label }}</dt> + <dd>{{ field }}</dd> + {% if field.help_text %}<dd>{{ field.help_text }}</dd>{% endif %} + {% if field.errors %}<dd class="myerrors">{{ field.errors }}</dd>{% endif %} + {% endfor %} + </dl> + <input type="submit" /> + </form> + +This iteration technique is useful if you want to apply the same HTML +formatting to each field, or if you don't know the names of the form fields +ahead of time. Note that the fields will be iterated over in the order in which +they're defined in the ``Form`` class. + +Alternatively, you can arrange the form's fields explicitly, by name. Do that +by accessing ``{{ form.fieldname }}``, where ``fieldname`` is the field's name. +For example:: + + <form method="post"> + <ul class="myformclass"> + <li>{{ form.sender.label }} {{ form.sender }}</li> + <li class="helptext">{{ form.sender.help_text }}</li> + {% if form.sender.errors %}<ul class="errorlist">{{ form.sender.errors }}</ul>{% endif %} + + <li>{{ form.subject.label }} {{ form.subject }}</li> + <li class="helptext">{{ form.subject.help_text }}</li> + {% if form.subject.errors %}<ul class="errorlist">{{ form.subject.errors }}</ul>{% endif %} + + ... + </ul> + </form> + Subclassing forms ----------------- -If you subclass a custom ``Form`` class, the resulting ``Form`` class will +If you have multiple ``Form`` classes that share fields, you can use +subclassing to remove redundancy. + +When you subclass a custom ``Form`` class, the resulting subclass will include all fields of the parent class(es), followed by the fields you define in the subclass. @@ -646,7 +786,7 @@ Core field arguments Each ``Field`` class constructor takes at least these arguments. Some ``Field`` classes take additional, field-specific arguments, but the following -should *always* be available: +should *always* be accepted: ``required`` ~~~~~~~~~~~~ @@ -704,7 +844,7 @@ field.) The ``label`` argument lets you specify the "human-friendly" label for this field. This is used when the ``Field`` is displayed in a ``Form``. -As explained in _`Outputting forms as HTML` above, the default label for a +As explained in "Outputting forms as HTML" above, the default label for a ``Field`` is generated from the field name by converting all underscores to spaces and upper-casing the first letter. Specify ``label`` if that default behavior doesn't result in an adequate label. @@ -779,14 +919,15 @@ validation if a particular field's value is not given. ``initial`` values are ~~~~~~~~~~ The ``widget`` argument lets you specify a ``Widget`` class to use when -rendering this ``Field``. See _`Widgets` below for more information. +rendering this ``Field``. See "Widgets" below for more information. ``help_text`` ~~~~~~~~~~~~~ The ``help_text`` argument lets you specify descriptive text for this ``Field``. If you provide ``help_text``, it will be displayed next to the -``Field`` when the ``Field`` is rendered in a ``Form``. +``Field`` when the ``Field`` is rendered by one of the convenience ``Form`` +methods (e.g., ``as_ul()``). Here's a full example ``Form`` that implements ``help_text`` for two of its fields. We've specified ``auto_id=False`` to simplify the output:: @@ -860,6 +1001,638 @@ level and at the form instance level, and the latter gets precedence:: <tr><th>Url:</th><td><input type="text" name="url" /></td></tr> <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr> +Built-in ``Field`` classes +-------------------------- + +Naturally, the ``newforms`` library comes with a set of ``Field`` classes that +represent common validation needs. This section documents each built-in field. + +For each field, we describe the default widget used if you don't specify +``widget``. We also specify the value returned when you provide an empty value +(see the section on ``required`` above to understand what that means). + +``BooleanField`` +~~~~~~~~~~~~~~~~ + + * Default widget: ``CheckboxInput`` + * Empty value: ``None`` + * Normalizes to: A Python ``True`` or ``False`` value. + * Validates nothing (i.e., it never raises a ``ValidationError``). + +``CharField`` +~~~~~~~~~~~~~ + + * Default widget: ``TextInput`` + * Empty value: ``''`` (an empty string) + * Normalizes to: A Unicode object. + * Validates nothing, unless ``max_length`` or ``min_length`` is provided. + +Has two optional arguments for validation, ``max_length`` and ``min_length``. +If provided, these arguments ensure that the string is at most or at least the +given length. + +``ChoiceField`` +~~~~~~~~~~~~~~~ + + * Default widget: ``Select`` + * Empty value: ``''`` (an empty string) + * Normalizes to: A Unicode object. + * Validates that the given value exists in the list of choices. + +Takes one extra argument, ``choices``, which is an iterable (e.g., a list or +tuple) of 2-tuples to use as choices for this field. + +``DateField`` +~~~~~~~~~~~~~ + + * Default widget: ``TextInput`` + * Empty value: ``None`` + * Normalizes to: A Python ``datetime.date`` object. + * Validates that the given value is either a ``datetime.date``, + ``datetime.datetime`` or string formatted in a particular date format. + +Takes one optional argument, ``input_formats``, which is a list of formats used +to attempt to convert a string to a valid ``datetime.date`` object. + +If no ``input_formats`` argument is provided, the default input formats are:: + + '%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2006-10-25', '10/25/2006', '10/25/06' + '%b %d %Y', '%b %d, %Y', # 'Oct 25 2006', 'Oct 25, 2006' + '%d %b %Y', '%d %b, %Y', # '25 Oct 2006', '25 Oct, 2006' + '%B %d %Y', '%B %d, %Y', # 'October 25 2006', 'October 25, 2006' + '%d %B %Y', '%d %B, %Y', # '25 October 2006', '25 October, 2006' + +``DateTimeField`` +~~~~~~~~~~~~~~~~~ + + * Default widget: ``TextInput`` + * Empty value: ``None`` + * Normalizes to: A Python ``datetime.datetime`` object. + * Validates that the given value is either a ``datetime.datetime``, + ``datetime.date`` or string formatted in a particular datetime format. + +Takes one optional argument, ``input_formats``, which is a list of formats used +to attempt to convert a string to a valid ``datetime.datetime`` object. + +If no ``input_formats`` argument is provided, the default input formats are:: + + '%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59' + '%Y-%m-%d %H:%M', # '2006-10-25 14:30' + '%Y-%m-%d', # '2006-10-25' + '%m/%d/%Y %H:%M:%S', # '10/25/2006 14:30:59' + '%m/%d/%Y %H:%M', # '10/25/2006 14:30' + '%m/%d/%Y', # '10/25/2006' + '%m/%d/%y %H:%M:%S', # '10/25/06 14:30:59' + '%m/%d/%y %H:%M', # '10/25/06 14:30' + '%m/%d/%y', # '10/25/06' + +``EmailField`` +~~~~~~~~~~~~~~ + + * Default widget: ``TextInput`` + * Empty value: ``''`` (an empty string) + * Normalizes to: A Unicode object. + * Validates that the given value is a valid e-mail address, using a + moderately complex regular expression. + +Has two optional arguments for validation, ``max_length`` and ``min_length``. +If provided, these arguments ensure that the string is at most or at least the +given length. + +``IntegerField`` +~~~~~~~~~~~~~~~~ + + * Default widget: ``TextInput`` + * Empty value: ``None`` + * Normalizes to: A Python integer or long integer. + * Validates that the given value is an integer. Leading and trailing + whitespace is allowed, as in Python's ``int()`` function. + +``MultipleChoiceField`` +~~~~~~~~~~~~~~~~~~~~~~~ + + * Default widget: ``SelectMultiple`` + * Empty value: ``[]`` (an empty list) + * Normalizes to: A list of Unicode objects. + * Validates that every value in the given list of values exists in the list + of choices. + +Takes one extra argument, ``choices``, which is an iterable (e.g., a list or +tuple) of 2-tuples to use as choices for this field. + +``NullBooleanField`` +~~~~~~~~~~~~~~~~~~~~ + + * Default widget: ``NullBooleanSelect`` + * Empty value: ``None`` + * Normalizes to: A Python ``True``, ``False`` or ``None`` value. + * Validates nothing (i.e., it never raises a ``ValidationError``). + +``RegexField`` +~~~~~~~~~~~~~~ + + * Default widget: ``TextInput`` + * Empty value: ``''`` (an empty string) + * Normalizes to: A Unicode object. + * Validates that the given value matches against a certain regular + expression. + +Takes one required argument, ``regex``, which is a regular expression specified +either as a string or a compiled regular expression object. + +Also takes the following optional arguments: + + ====================== ===================================================== + Argument Description + ====================== ===================================================== + ``max_length`` Ensures the string has at most this many characters. + ``min_length`` Ensures the string has at least this many characters. + ``error_message`` Error message to return for failed validation. If no + message is provided, a generic error message will be + used. + ====================== ===================================================== + +``TimeField`` +~~~~~~~~~~~~~ + + * Default widget: ``TextInput`` + * Empty value: ``None`` + * Normalizes to: A Python ``datetime.time`` object. + * Validates that the given value is either a ``datetime.time`` or string + formatted in a particular time format. + +Takes one optional argument, ``input_formats``, which is a list of formats used +to attempt to convert a string to a valid ``datetime.time`` object. + +If no ``input_formats`` argument is provided, the default input formats are:: + + '%H:%M:%S', # '14:30:59' + '%H:%M', # '14:30' + +``URLField`` +~~~~~~~~~~~~ + + * Default widget: ``TextInput`` + * Empty value: ``''`` (an empty string) + * Normalizes to: A Unicode object. + * Validates that the given value is a valid URL. + +Takes the following optional arguments: + + ======================== ===================================================== + Argument Description + ======================== ===================================================== + ``max_length`` Ensures the string has at most this many characters. + ``min_length`` Ensures the string has at least this many characters. + ``verify_exists`` If ``True``, the validator will attempt to load the + given URL, raising ``ValidationError`` if the page + gives a 404. Defaults to ``False``. + ``validator_user_agent`` String used as the user-agent used when checking for + a URL's existence. Defaults to the value of the + ``URL_VALIDATOR_USER_AGENT`` setting. + ======================== ===================================================== + +Slightly complex built-in ``Field`` classes +------------------------------------------- + +The following are not yet documented here. See the unit tests, linked-to from +the bottom of this document, for examples of their use. + +``ComboField`` +~~~~~~~~~~~~~~ + +``MultiValueField`` +~~~~~~~~~~~~~~~~~~~ + +``SplitDateTimeField`` +~~~~~~~~~~~~~~~~~~~~~~ + +Creating custom fields +---------------------- + +If the built-in ``Field`` classes don't meet your needs, you can easily create +custom ``Field`` classes. To do this, just create a subclass of +``django.newforms.Field``. Its only requirements are that it implement a +``clean()`` method and that its ``__init__()`` method accept the core arguments +mentioned above (``required``, ``label``, ``initial``, ``widget``, +``help_text``). + +Custom form and field validation +--------------------------------- + +Form validation happens when the data is cleaned. If you want to customise +this process, there are various places you can change, each one serving a +different purpose. Thee types of cleaning methods are run during form +processing. These are normally executed when you call the ``is_valid()`` +method on a form. There are other things that can trigger cleaning and +validation (accessing the ``errors`` attribute or calling ``full_clean()`` +directly), but normally they won't be needed. + +In general, any cleaning method can raise ``ValidationError`` if there is a +problem with the data it is processing, passing the relevant error message to +the ``ValidationError`` constructor. If no ``ValidationError`` is raised, the +method should return the cleaned (normalised) data as a Python object. + +If you detect multiple errors during a cleaning method and wish to signal all +of them to the form submitter, it is possible to pass a list of errors to the +``ValidationError`` constructor. + +The three types of cleaning methods are: + + * The ``clean()`` method on a Field subclass. This is responsible + for cleaning the data in a way that is generic for that type of field. + For example, a FloatField will turn the data into a Python ``float`` or + raise a ``ValidationError``. + + * The ``clean_<fieldname>()`` method in a form subclass -- where + ``<fieldname>`` is replaced with the name of the form field attribute. + This method does any cleaning that is specific to that particular + attribute, unrelated to the type of field that it is. This method is not + passed any parameters. You will need to look up the value of the field + in ``self.cleaned_data`` and remember that it will be a Python object + at this point, not the original string submitted in the form (it will be + in ``cleaned_data`` because the general field ``clean()`` method, above, + has already cleaned the data once). + + For example, if you wanted to validate that the contents of a + ``CharField`` called ``serialnumber`` was unique, + ``clean_serialnumber()`` would be the right place to do this. You don't + need a specific field (it's just a ``CharField``), but you want a + formfield-specific piece of validation and, possibly, + cleaning/normalizing the data. + + * The Form subclass's ``clean()`` method. This method can perform + any validation that requires access to multiple fields from the form at + once. This is where you might put in things to check that if field ``A`` + is supplied, field ``B`` must contain a valid email address and the + like. The data that this method returns is the final ``cleaned_data`` + attribute for the form, so don't forget to return the full list of + cleaned data if you override this method (by default, ``Form.clean()`` + just returns ``self.cleaned_data``). + + Note that any errors raised by your ``Form.clean()`` override will not + be associated with any field in particular. They go into a special + "field" (called ``__all__``, which you can access via the + ``non_field_errors()`` method if you need to. + +These methods are run in the order given above, one field at a time. That is, +for each field in the form (in the order they are declared in the form +definition), the ``Field.clean()`` method (or it's override) is run, then +``clean_<fieldname>()``. Finally, once those two methods are run for every +field, the ``Form.clean()`` method, or it's override, is executed. + +As mentioned above, any of these methods can raise a ``ValidationError``. For +any field, if the ``Field.clean()`` method raises a ``ValidationError``, any +field-specific cleaning method is not called. However, the cleaning methods +for all remaining fields are still executed. + +The ``clean()`` method for the ``Form`` class or subclass is always run. If +that method raises a ``ValidationError``, ``cleaned_data`` will be an empty +dictionary. + +The previous paragraph means that if you are overriding ``Form.clean()``, you +should iterate through ``self.cleaned_data.items()``, possibly considering the +``_errors`` dictionary attribute on the form as well. In this way, you will +already know which fields have passed their individual validation requirements. + +A simple example +~~~~~~~~~~~~~~~~ + +Here's a simple example of a custom field that validates its input is a string +containing comma-separated e-mail addresses, with at least one address. We'll +keep it simple and assume e-mail validation is contained in a function called +``is_valid_email()``. The full class:: + + from django import newforms as forms + + class MultiEmailField(forms.Field): + def clean(self, value): + emails = value.split(',') + for email in emails: + if not is_valid_email(email): + raise forms.ValidationError('%s is not a valid e-mail address.' % email) + if not emails: + raise forms.ValidationError('Enter at least one e-mail address.') + return emails + +Let's alter the ongoing ``ContactForm`` example to demonstrate how you'd use +this in a form. Simply use ``MultiEmailField`` instead of ``forms.EmailField``, +like so:: + + class ContactForm(forms.Form): + subject = forms.CharField(max_length=100) + message = forms.CharField() + senders = MultiEmailField() + cc_myself = forms.BooleanField() + +Generating forms for models +=========================== + +If you're building a database-driven app, chances are you'll have forms that +map closely to Django models. For instance, you might have a ``BlogComment`` +model, and you want to create a form that lets people submit comments. In this +case, it would be redundant to define the field types in your form, because +you've already defined the fields in your model. + +For this reason, Django provides a few helper functions that let you create a +``Form`` class from a Django model. + +``form_for_model()`` +-------------------- + +The method ``django.newforms.form_for_model()`` creates a form based on the +definition of a specific model. Pass it the model class, and it will return a +``Form`` class that contains a form field for each model field. + +For example:: + + >>> from django.newforms import form_for_model + + # Create the form class. + >>> ArticleForm = form_for_model(Article) + + # Create an empty form instance. + >>> f = ArticleForm() + +It bears repeating that ``form_for_model()`` takes the model *class*, not a +model instance, and it returns a ``Form`` *class*, not a ``Form`` instance. + +Field types +~~~~~~~~~~~ + +The generated ``Form`` class will have a form field for every model field. Each +model field has a corresponding default form field. For example, a +``CharField`` on a model is represented as a ``CharField`` on a form. A +model ``ManyToManyField`` is represented as a ``MultipleChoiceField``. Here is +the full list of conversions: + + =============================== ======================================== + Model field Form field + =============================== ======================================== + ``AutoField`` Not represented in the form + ``BooleanField`` ``BooleanField`` + ``CharField`` ``CharField`` with ``max_length`` set to + the model field's ``maxlength`` + ``CommaSeparatedIntegerField`` ``CharField`` + ``DateField`` ``DateField`` + ``DateTimeField`` ``DateTimeField`` + ``DecimalField`` ``DecimalField`` + ``EmailField`` ``EmailField`` + ``FileField`` ``CharField`` + ``FilePathField`` ``CharField`` + ``FloatField`` ``FloatField`` + ``ForeignKey`` ``ModelChoiceField`` (see below) + ``ImageField`` ``CharField`` + ``IntegerField`` ``IntegerField`` + ``IPAddressField`` ``CharField`` + ``ManyToManyField`` ``ModelMultipleChoiceField`` (see + below) + ``NullBooleanField`` ``CharField`` + ``PhoneNumberField`` ``USPhoneNumberField`` + (from ``django.contrib.localflavor.us``) + ``PositiveIntegerField`` ``IntegerField`` + ``PositiveSmallIntegerField`` ``IntegerField`` + ``SlugField`` ``CharField`` + ``SmallIntegerField`` ``IntegerField`` + ``TextField`` ``CharField`` with ``widget=Textarea`` + ``TimeField`` ``TimeField`` + ``URLField`` ``URLField`` with ``verify_exists`` set + to the model field's ``verify_exists`` + ``USStateField`` ``CharField`` with + ``widget=USStateSelect`` + (``USStateSelect`` is from + ``django.contrib.localflavor.us``) + ``XMLField`` ``CharField`` with ``widget=Textarea`` + =============================== ======================================== + + +.. note:: + The ``FloatField`` form field and ``DecimalField`` model and form fields + are new in the development version. + +As you might expect, the ``ForeignKey`` and ``ManyToManyField`` model field +types are special cases: + + * ``ForeignKey`` is represented by ``django.newforms.ModelChoiceField``, + which is a ``ChoiceField`` whose choices are a model ``QuerySet``. + + * ``ManyToManyField`` is represented by + ``django.newforms.ModelMultipleChoiceField``, which is a + ``MultipleChoiceField`` whose choices are a model ``QuerySet``. + +In addition, each generated form field has attributes set as follows: + + * If the model field has ``blank=True``, then ``required`` is set to + ``False`` on the form field. Otherwise, ``required=True``. + + * The form field's ``label`` is set to the ``verbose_name`` of the model + field, with the first character capitalized. + + * The form field's ``help_text`` is set to the ``help_text`` of the model + field. + + * If the model field has ``choices`` set, then the form field's ``widget`` + will be set to ``Select``, with choices coming from the model field's + ``choices``. + +Finally, note that you can override the form field used for a given model +field. See "Overriding the default field types" below. + +A full example +~~~~~~~~~~~~~~ + +Consider this set of models:: + + from django.db import models + + TITLE_CHOICES = ( + ('MR', 'Mr.'), + ('MRS', 'Mrs.'), + ('MS', 'Ms.'), + ) + + class Author(models.Model): + name = models.CharField(maxlength=100) + title = models.CharField(maxlength=3, choices=TITLE_CHOICES) + birth_date = models.DateField(blank=True, null=True) + + def __str__(self): + return self.name + + class Book(models.Model): + name = models.CharField(maxlength=100) + authors = models.ManyToManyField(Author) + +With these models, a call to ``form_for_model(Author)`` would return a ``Form`` +class equivalent to this:: + + class AuthorForm(forms.Form): + name = forms.CharField(max_length=100) + title = forms.CharField(max_length=3, + widget=forms.Select(choices=TITLE_CHOICES)) + birth_date = forms.DateField(required=False) + +A call to ``form_for_model(Book)`` would return a ``Form`` class equivalent to +this:: + + class BookForm(forms.Form): + name = forms.CharField(max_length=100) + authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all()) + +The ``save()`` method +~~~~~~~~~~~~~~~~~~~~~ + +Every form produced by ``form_for_model()`` also has a ``save()`` method. This +method creates and saves a database object from the data bound to the form. For +example:: + + # Create a form instance from POST data. + >>> f = ArticleForm(request.POST) + + # Save a new Article object from the form's data. + >>> new_article = f.save() + +Note that ``save()`` will raise a ``ValueError`` if the data in the form +doesn't validate -- i.e., ``if form.errors``. + +Using an alternate base class +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you want to add custom methods to the form generated by +``form_for_model()``, write a class that extends ``django.newforms.BaseForm`` +and contains your custom methods. Then, use the ``form`` argument to +``form_for_model()`` to tell it to use your custom form as its base class. +For example:: + + # Create the new base class. + >>> class MyBase(BaseForm): + ... def my_method(self): + ... # Do whatever the method does + + # Create the form class with a different base class. + >>> ArticleForm = form_for_model(Article, form=MyBase) + + # Instantiate the form. + >>> f = ArticleForm() + + # Use the base class method. + >>> f.my_method() + +Using a subset of fields on the form +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**New in Django development version** + +In some cases, you may not want all the model fields to appear on the generated +form. There are two ways of telling ``form_for_model()`` to use only a subset +of the model fields: + + 1. Set ``editable=False`` on the model field. As a result, *any* form + created from the model via ``form_for_model()`` will not include that + field. + + 2. Use the ``fields`` argument to ``form_for_model()``. This argument, if + given, should be a list of field names to include in the form. + + For example, if you want a form for the ``Author`` model (defined above) + that includes only the ``name`` and ``title`` fields, you would specify + ``fields`` like this:: + + PartialArticleForm = form_for_model(Author, fields=('name', 'title')) + +.. note:: + + If you specify ``fields`` when creating a form with ``form_for_model()``, + make sure that the fields that are *not* specified can provide default + values, or are allowed to have a value of ``None``. If a field isn't + specified on a form, the object created from the form can't provide + a value for that attribute, which will prevent the new instance from + being saved. + +Overriding the default field types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The default field types, as described in the "Field types" table above, are +sensible defaults; if you have a ``DateField`` in your model, chances are you'd +want that to be represented as a ``DateField`` in your form. But +``form_for_model()`` gives you the flexibility of changing the form field type +for a given model field. You do this by specifying a **formfield callback**. + +A formfield callback is a function that, when provided with a model field, +returns a form field instance. When constructing a form, ``form_for_model()`` +asks the formfield callback to provide form field types. + +By default, ``form_for_model()`` calls the ``formfield()`` method on the model +field:: + + def default_callback(field, **kwargs): + return field.formfield(**kwargs) + +The ``kwargs`` are any keyword arguments that might be passed to the form +field, such as ``required=True`` or ``label='Foo'``. + +For example, if you wanted to use ``MyDateFormField`` for any ``DateField`` +field on the model, you could define the callback:: + + >>> def my_callback(field, **kwargs): + ... if isinstance(field, models.DateField): + ... return MyDateFormField(**kwargs) + ... else: + ... return field.formfield(**kwargs) + + >>> ArticleForm = form_for_model(formfield_callback=my_callback) + +Note that your callback needs to handle *all* possible model field types, not +just the ones that you want to behave differently to the default. That's why +this example has an ``else`` clause that implements the default behavior. + +Finding the model associated with a form +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The model class that was used to construct the form is available +using the ``_model`` property of the generated form:: + + >>> ArticleForm = form_for_model(Article) + >>> ArticleForm._model + <class 'myapp.models.Article'> + +``form_for_instance()`` +----------------------- + +``form_for_instance()`` is like ``form_for_model()``, but it takes a model +instance instead of a model class:: + + # Create an Author. + >>> a = Author(name='Joe Smith', title='MR', birth_date=None) + >>> a.save() + + # Create a form for this particular Author. + >>> AuthorForm = form_for_instance(a) + + # Instantiate the form. + >>> f = AuthorForm() + +When a form created by ``form_for_instance()`` is created, the initial +data values for the form fields are drawn from the instance. However, +this data is not bound to the form. You will need to bind data to the +form before the form can be saved. + +When you call ``save()`` on a form created by ``form_for_instance()``, +the database instance will be updated. As in ``form_for_model()``, ``save()`` +will raise ``ValueError`` if the data doesn't validate. + +``form_for_instance()`` has ``form``, ``fields`` and ``formfield_callback`` +arguments that behave the same way as they do for ``form_for_model()``. + +When should you use ``form_for_model()`` and ``form_for_instance()``? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``form_for_model()`` and ``form_for_instance()`` functions are meant to be +shortcuts for the common case. If you want to create a form whose fields map to +more than one model, or a form that contains fields that *aren't* on a model, +you shouldn't use these shortcuts. Creating a ``Form`` class the "long" way +isn't that difficult, after all. + More coming soon ================ @@ -870,6 +1643,3 @@ what's possible. If you're really itching to learn and use this library, please be patient. We're working hard on finishing both the code and documentation. - -Widgets -======= diff --git a/docs/overview.txt b/docs/overview.txt index 35af75bf05..7b3559663a 100644 --- a/docs/overview.txt +++ b/docs/overview.txt @@ -297,5 +297,5 @@ The next obvious steps are for you to `download Django`_, read `the tutorial`_ and join `the community`_. Thanks for your interest! .. _download Django: http://www.djangoproject.com/download/ -.. _the tutorial: http://www.djangoproject.com/documentation/tutorial1/ +.. _the tutorial: http://www.djangoproject.com/documentation/tutorial01/ .. _the community: http://www.djangoproject.com/community/ diff --git a/docs/redirects.txt b/docs/redirects.txt index 5f84f28097..4df60d473f 100644 --- a/docs/redirects.txt +++ b/docs/redirects.txt @@ -66,6 +66,6 @@ Redirects are represented by a standard `Django model`_, which lives in `django/contrib/redirects/models.py`_. You can access redirect objects via the `Django database API`_. -.. _Django model: ../model_api/ +.. _Django model: ../model-api/ .. _django/contrib/redirects/models.py: http://code.djangoproject.com/browser/django/trunk/django/contrib/redirects/models.py -.. _Django database API: ../db_api/ +.. _Django database API: ../db-api/ diff --git a/docs/release_notes_0.96.txt b/docs/release_notes_0.96.txt index ca5f5e045c..f62780c6b2 100644 --- a/docs/release_notes_0.96.txt +++ b/docs/release_notes_0.96.txt @@ -62,7 +62,7 @@ Database constraint names changed The format of the constraint names Django generates for foreign key references have changed slightly. These names are generally only used when it is not possible to put the reference directly on the affected -column, so they is not always visible. +column, so they are not always visible. The effect of this change is that running ``manage.py reset`` and similar commands against an existing database may generate SQL with @@ -261,4 +261,4 @@ all their hard work: that went into 0.96 -- but everyone who's contributed to Django is listed in AUTHORS_. -.. _AUTHORS: http://code.djangoproject.com/browser/django/trunk/AUTHORS
\ No newline at end of file +.. _AUTHORS: http://code.djangoproject.com/browser/django/trunk/AUTHORS diff --git a/docs/request_response.txt b/docs/request_response.txt index 2b79903d13..0b985d563b 100644 --- a/docs/request_response.txt +++ b/docs/request_response.txt @@ -93,6 +93,7 @@ All attributes except ``session`` should be considered read-only. * ``CONTENT_TYPE`` * ``HTTP_ACCEPT_ENCODING`` * ``HTTP_ACCEPT_LANGUAGE`` + * ``HTTP_HOST`` -- The HTTP Host header sent by the client. * ``HTTP_REFERER`` -- The referring page, if any. * ``HTTP_USER_AGENT`` -- The client's user-agent string. * ``QUERY_STRING`` -- The query string, as a single (unparsed) string. @@ -416,6 +417,10 @@ types of HTTP responses. Like ``HttpResponse``, these subclasses live in The constructor doesn't take any arguments. Use this to designate that a page hasn't been modified since the user's last request. +``HttpResponseBadRequest`` + **New in Django development version.** + Acts just like ``HttpResponse`` but uses a 400 status code. + ``HttpResponseNotFound`` Acts just like ``HttpResponse`` but uses a 404 status code. @@ -479,8 +484,8 @@ In order to use the ``Http404`` exception to its fullest, you should create a template that is displayed when a 404 error is raised. This template should be called ``404.html`` and located in the top level of your template tree. -Customing error views ---------------------- +Customizing error views +----------------------- The 404 (page not found) view ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/serialization.txt b/docs/serialization.txt index 48ab46f0f9..01afa2708c 100644 --- a/docs/serialization.txt +++ b/docs/serialization.txt @@ -27,7 +27,7 @@ data to (see `Serialization formats`_) and a QuerySet_ to serialize. (Actually, the second argument can be any iterator that yields Django objects, but it'll almost always be a QuerySet). -.. _QuerySet: ../db_api/#retrieving-objects +.. _QuerySet: ../db-api/#retrieving-objects You can also use a serializer object directly:: @@ -44,6 +44,25 @@ This is useful if you want to serialize data directly to a file-like object .. _HTTPResponse: ../request_response/#httpresponse-objects +Subset of fields +~~~~~~~~~~~~~~~~ + +If you only want a subset of fields to be serialized, you can +specify a `fields` argument to the serializer:: + + from django.core import serializers + data = serializers.serialize('xml', SomeModel.objects.all(), fields=('name','size')) + +In this example, only the `name` and `size` attributes of each model will +be serialized. + +.. note:: + + Depending on your model, you may find that it is not possible to deserialize + a model that only serializes a subset of its fields. If a serialized object + doesn't specify all the fields that are required by a model, the deserializer + will not be able to save deserialized instances. + Deserializing data ------------------ @@ -92,10 +111,14 @@ Django "ships" with a few included serializers: ``python`` Translates to and from "simple" Python objects (lists, dicts, strings, etc.). Not really all that useful on its own, but used as a base for other serializers. + + ``yaml`` Serializes to YAML (Yet Another Markup Lanuage). This + serializer is only available if PyYAML_ is installed. ========== ============================================================== .. _json: http://json.org/ .. _simplejson: http://undefined.org/python/#simplejson +.. _PyYAML: http://www.pyyaml.org/ Notes for specific serialization formats ---------------------------------------- @@ -109,7 +132,7 @@ serializer, you must pass ``ensure_ascii=False`` as a parameter to the For example:: - json_serializer = serializers.get_serializer("json") + json_serializer = serializers.get_serializer("json")() json_serializer.serialize(queryset, ensure_ascii=False, stream=response) Writing custom serializers diff --git a/docs/sessions.txt b/docs/sessions.txt index 660718b4e2..c7124ba703 100644 --- a/docs/sessions.txt +++ b/docs/sessions.txt @@ -107,7 +107,7 @@ posts a comment. It doesn't let a user post a comment more than once:: This simplistic view logs in a "member" of the site:: def login(request): - m = members.get_object(username__exact=request.POST['username']) + m = Member.objects.get(username=request.POST['username']) if m.password == request.POST['password']: request.session['member_id'] = m.id return HttpResponse("You're logged in.") @@ -158,7 +158,7 @@ is defined in ``django/contrib/sessions/models.py``. Because it's a normal model, you can access sessions using the normal Django database API:: >>> from django.contrib.sessions.models import Session - >>> s = Session.objects.get_object(pk='2b1189a188b44ad18c35e113ac6ceead') + >>> s = Session.objects.get(pk='2b1189a188b44ad18c35e113ac6ceead') >>> s.expire_date datetime.datetime(2005, 8, 20, 13, 35, 12) diff --git a/docs/settings.txt b/docs/settings.txt index 63b5cceef9..12e6dab4bc 100644 --- a/docs/settings.txt +++ b/docs/settings.txt @@ -59,7 +59,7 @@ Use the ``--settings`` command-line argument to specify the settings manually:: django-admin.py runserver --settings=mysite.settings -.. _django-admin.py: ../django_admin/ +.. _django-admin.py: ../django-admin/ On the server (mod_python) -------------------------- @@ -102,7 +102,7 @@ between the current settings file and Django's default settings. For more, see the `diffsettings documentation`_. -.. _diffsettings documentation: ../django_admin/#diffsettings +.. _diffsettings documentation: ../django-admin/#diffsettings Using settings in Python code ============================= @@ -264,6 +264,11 @@ MySQL will connect via a Unix socket to the specified socket. For example:: If you're using MySQL and this value *doesn't* start with a forward slash, then this value is assumed to be the host. +If you're using PostgreSQL, an empty string means to use a Unix domain socket +for the connection, rather than a network connection to localhost. If you +explictly need to use a TCP/IP connection on the local machine with +PostgreSQL, specify ``localhost`` here. + DATABASE_NAME ------------- @@ -395,8 +400,10 @@ EMAIL_HOST_PASSWORD Default: ``''`` (Empty string) -Username to use for the SMTP server defined in ``EMAIL_HOST``. If empty, -Django won't attempt authentication. +Password to use for the SMTP server defined in ``EMAIL_HOST``. This setting is +used in conjunction with ``EMAIL_HOST_USER`` when authenticating to the SMTP +server. If either of these settings is empty, Django won't attempt +authenticaion. See also ``EMAIL_HOST_USER``. @@ -426,6 +433,15 @@ Subject-line prefix for e-mail messages sent with ``django.core.mail.mail_admins or ``django.core.mail.mail_managers``. You'll probably want to include the trailing space. +EMAIL_USE_TLS +------------- + +**New in Django development version** + +Default: ``False`` + +Whether to use a TLS (secure) connection when talking to the SMTP server. + FIXTURE_DIRS ------------- @@ -462,7 +478,7 @@ A tuple of strings designating all applications that are enabled in this Django installation. Each string should be a full Python path to a Python package that contains a Django application, as created by `django-admin.py startapp`_. -.. _django-admin.py startapp: ../django_admin/#startapp-appname +.. _django-admin.py startapp: ../django-admin/#startapp-appname INTERNAL_IPS ------------ @@ -498,44 +514,17 @@ in standard language format. For example, U.S. English is ``"en-us"``. See the LANGUAGES --------- -Default: A tuple of all available languages. Currently, this is:: +Default: A tuple of all available languages. This list is continually growing +and including a copy here would inevitably become rapidly out of date. You can +see the current list of translated languages by looking in +``django/conf/global_settings.py`` (or view the `online source`_). - LANGUAGES = ( - ('ar', _('Arabic')), - ('bn', _('Bengali')), - ('cs', _('Czech')), - ('cy', _('Welsh')), - ('da', _('Danish')), - ('de', _('German')), - ('el', _('Greek')), - ('en', _('English')), - ('es', _('Spanish')), - ('es_AR', _('Argentinean Spanish')), - ('fr', _('French')), - ('gl', _('Galician')), - ('hu', _('Hungarian')), - ('he', _('Hebrew')), - ('is', _('Icelandic')), - ('it', _('Italian')), - ('ja', _('Japanese')), - ('nl', _('Dutch')), - ('no', _('Norwegian')), - ('pt-br', _('Brazilian')), - ('ro', _('Romanian')), - ('ru', _('Russian')), - ('sk', _('Slovak')), - ('sl', _('Slovenian')), - ('sr', _('Serbian')), - ('sv', _('Swedish')), - ('ta', _('Tamil')), - ('uk', _('Ukrainian')), - ('zh-cn', _('Simplified Chinese')), - ('zh-tw', _('Traditional Chinese')), - ) +.. _online source: http://code.djangoproject.com/browser/django/trunk/django/conf/global_settings.py -A tuple of two-tuples in the format (language code, language name). This -specifies which languages are available for language selection. See the -`internationalization docs`_ for details. +The list is a tuple of two-tuples in the format (language code, language +name) -- for example, ``('ja', 'Japanese')``. This specifies which languages +are available for language selection. See the `internationalization docs`_ for +details. Generally, the default value should suffice. Only set this setting if you want to restrict language selection to a subset of the Django-provided languages. @@ -562,6 +551,37 @@ strings for translation, but the translation won't happen at runtime -- so you'll have to remember to wrap the languages in the *real* ``gettext()`` in any code that uses ``LANGUAGES`` at runtime. +LOGIN_REDIRECT_URL +------------------ + +**New in Django development version** + +Default: ``'/accounts/profile/'`` + +The URL where requests are redirected after login when the +``contrib.auth.login`` view gets no ``next`` parameter. + +This is used by the `@login_required`_ decorator, for example. + +LOGIN_URL +--------- + +**New in Django development version** + +Default: ``'/accounts/login/'`` + +The URL where requests are redirected for login, specially when using the +`@login_required`_ decorator. + +LOGOUT_URL +---------- + +**New in Django development version** + +Default: ``'/accounts/logout/'`` + +LOGIN_URL counterpart. + MANAGERS -------- @@ -756,7 +776,8 @@ Default:: ("django.core.context_processors.auth", "django.core.context_processors.debug", - "django.core.context_processors.i18n") + "django.core.context_processors.i18n", + "django.core.context_processors.media") A tuple of callables that are used to populate the context in ``RequestContext``. These callables take a request object as their argument and return a dictionary @@ -805,26 +826,57 @@ misspelled) variables. See `How invalid variables are handled`_. .. _How invalid variables are handled: ../templates_python/#how-invalid-variables-are-handled -TEST_RUNNER ------------ +TEST_DATABASE_CHARSET +--------------------- -Default: ``'django.test.simple.run_tests'`` +**New in Django development version** -The name of the method to use for starting the test suite. See -`Testing Django Applications`_. +Default: ``None`` -.. _Testing Django Applications: ../testing/ +The character set encoding used to create the test database. The value of this +string is passed directly through to the database, so its format is +backend-specific. + +Supported for the PostgreSQL_ (``postgresql``, ``postgresql_psycopg2``) and MySQL_ (``mysql``, ``mysql_old``) backends. + +.. _PostgreSQL: http://www.postgresql.org/docs/8.2/static/multibyte.html +.. _MySQL: http://www.mysql.org/doc/refman/5.0/en/charset-database.html + +TEST_DATABASE_COLLATION +------------------------ + +**New in Django development version** + +Default: ``None`` + +The collation order to use when creating the test database. This value is +passed directly to the backend, so its format is backend-specific. + +Only supported for ``mysql`` and ``mysql_old`` backends (see `section 10.3.2`_ +of the MySQL manual for details). + +.. _section 10.3.2: http://www.mysql.org/doc/refman/5.0/en/charset-database.html TEST_DATABASE_NAME ------------------ Default: ``None`` -The name of database to use when running the test suite. If a value of +The name of database to use when running the test suite. If a value of ``None`` is specified, the test database will use the name ``'test_' + settings.DATABASE_NAME``. See `Testing Django Applications`_. .. _Testing Django Applications: ../testing/ +TEST_RUNNER +----------- + +Default: ``'django.test.simple.run_tests'`` + +The name of the method to use for starting the test suite. See +`Testing Django Applications`_. + +.. _Testing Django Applications: ../testing/ + TIME_FORMAT ----------- @@ -874,7 +926,7 @@ Default: ``Django/<version> (http://www.djangoproject.com/)`` The string to use as the ``User-Agent`` header when checking to see if URLs exist (see the ``verify_exists`` option on URLField_). -.. _URLField: ../model_api/#urlfield +.. _URLField: ../model-api/#urlfield USE_ETAGS --------- @@ -1012,6 +1064,8 @@ Also, it's an error to call ``configure()`` more than once, or to call It boils down to this: Use exactly one of either ``configure()`` or ``DJANGO_SETTINGS_MODULE``. Not both, and not neither. +.. _@login_required: ../authentication/#the-login-required-decorator + Error reporting via e-mail ========================== @@ -1038,7 +1092,7 @@ You can tell Django to stop reporting particular 404s by tweaking the tuple of strings. For example:: IGNORABLE_404_ENDS = ('.php', '.cgi') - IGNORABLE_404_STARTS = ('/phpmyadmin/') + IGNORABLE_404_STARTS = ('/phpmyadmin/',) In this example, a 404 to any URL ending with ``.php`` or ``.cgi`` will *not* be reported. Neither will any URL starting with ``/phpmyadmin/``. diff --git a/docs/sitemaps.txt b/docs/sitemaps.txt index dafc009859..550f448de1 100644 --- a/docs/sitemaps.txt +++ b/docs/sitemaps.txt @@ -2,8 +2,6 @@ The sitemap framework ===================== -**New in Django development version**. - Django comes with a high-level sitemap-generating framework that makes creating sitemap_ XML files easy. diff --git a/docs/sites.txt b/docs/sites.txt index 7497d7dd80..12259b04c3 100644 --- a/docs/sites.txt +++ b/docs/sites.txt @@ -276,8 +276,8 @@ you want your admin site to have access to all objects (not just site-specific ones), put ``objects = models.Manager()`` in your model, before you define ``CurrentSiteManager``. -.. _manager: ../model_api/#managers -.. _manager documentation: ../model_api/#managers +.. _manager: ../model-api/#managers +.. _manager documentation: ../model-api/#managers How Django uses the sites framework =================================== diff --git a/docs/syndication_feeds.txt b/docs/syndication_feeds.txt index a64914de3f..2a03e6d5a6 100644 --- a/docs/syndication_feeds.txt +++ b/docs/syndication_feeds.txt @@ -114,6 +114,9 @@ Note: `object-relational mapper`_, ``items()`` doesn't have to return model instances. Although you get a few bits of functionality "for free" by using Django models, ``items()`` can return any type of object you want. + * If you're creating an Atom feed, rather than an RSS feed, set the + ``subtitle`` attribute instead of the ``description`` attribute. See + `Publishing Atom and RSS feeds in tandem`_, later, for an example. One thing's left to do. In an RSS feed, each ``<item>`` has a ``<title>``, ``<link>`` and ``<description>``. We need to tell the framework what data to @@ -143,7 +146,10 @@ put into those elements. exist, it tries calling a method ``item_link()`` in the ``Feed`` class, passing it a single parameter, ``item``, which is the object itself. Both ``get_absolute_url()`` and ``item_link()`` should return the item's - URL as a normal Python string. + URL as a normal Python string. As with ``get_absolute_url()``, the + result of ``item_link()`` will be included directly in the URL, so you + are responsible for doing all necessary URL quoting and conversion to + ASCII inside the method itself. * For the LatestEntries example above, we could have very simple feed templates: @@ -156,7 +162,7 @@ put into those elements. {{ obj.description }} .. _chicagocrime.org: http://www.chicagocrime.org/ -.. _object-relational mapper: ../db_api/ +.. _object-relational mapper: ../db-api/ .. _Django templates: ../templates/ A complex example @@ -298,7 +304,7 @@ Publishing Atom and RSS feeds in tandem --------------------------------------- Some developers like to make available both Atom *and* RSS versions of their -feeds. That's easy to do with Django: Just create a subclass of your ``feed`` +feeds. That's easy to do with Django: Just create a subclass of your ``Feed`` class and set the ``feed_type`` to something different. Then update your URLconf to add the extra versions. @@ -318,6 +324,20 @@ Here's a full example:: class AtomSiteNewsFeed(RssSiteNewsFeed): feed_type = Atom1Feed + subtitle = RssSiteNewsFeed.description + +.. Note:: + In this example, the RSS feed uses a ``description`` while the Atom feed + uses a ``subtitle``. That's because Atom feeds don't provide for a + feed-level "description," but they *do* provide for a "subtitle." + + If you provide a ``description`` in your ``Feed`` class, Django will *not* + automatically put that into the ``subtitle`` element, because a subtitle + and description are not necessarily the same thing. Instead, you should + define a ``subtitle`` attribute. + + In the above example, we simply set the Atom feed's ``subtitle`` to the + RSS feed's ``description``, because it's quite short already. And the accompanying URLconf:: @@ -629,15 +649,15 @@ This example illustrates all possible attributes and methods for a ``Feed`` clas def item_enclosure_mime_type(self, item): """ Takes an item, as returned by items(), and returns the item's - enclosure mime type. + enclosure MIME type. """ def item_enclosure_mime_type(self): """ - Returns the enclosure length, in bytes, for every item in the feed. + Returns the enclosure MIME type for every item in the feed. """ - item_enclosure_mime_type = "audio/mpeg" # Hard-coded enclosure mime-type. + item_enclosure_mime_type = "audio/mpeg" # Hard-coded enclosure MIME type. # ITEM PUBDATE -- It's optional to use one of these three. This is a # hook that specifies how to get the pubdate for a given item. diff --git a/docs/templates.txt b/docs/templates.txt index db748ae432..cb8e238f43 100644 --- a/docs/templates.txt +++ b/docs/templates.txt @@ -91,9 +91,12 @@ Filters can be "chained." The output of one filter is applied to the next. ``{{ text|escape|linebreaks }}`` is a common idiom for escaping text contents, then converting line breaks to ``<p>`` tags. -Some filters take arguments. A filter argument looks like this: -``{{ bio|truncatewords:"30" }}``. This will display the first 30 words of the -``bio`` variable. Filter arguments always are in double quotes. +Some filters take arguments. A filter argument looks like this: ``{{ +bio|truncatewords:30 }}``. This will display the first 30 words of the ``bio`` +variable. + +Filter arguments that contain spaces must be quoted; for example, to join a list +with commas and spaced you'd use ``{{ list|join:", " }}``. The `Built-in filter reference`_ below describes all the built-in filters. @@ -112,7 +115,7 @@ know how to write Python code. Comments ======== -To comment-out part of a template, use the comment syntax: ``{# #}``. +To comment-out part of a line in a template, use the comment syntax: ``{# #}``. For example, this template would render as ``'hello'``:: @@ -122,6 +125,12 @@ A comment can contain any template code, invalid or not. For example:: {# {% if foo %}bar{% else %} #} +This syntax can only be used for single-line comments (no newlines are +permitted between the ``{#`` and ``#}`` delimiters). If you need to comment +out a multiline portion of the template, see the ``comment`` tag, below__. + +__ comment_ + Template inheritance ==================== @@ -438,7 +447,7 @@ for ~~~ Loop over each item in an array. For example, to display a list of athletes -given ``athlete_list``:: +provided in ``athlete_list``:: <ul> {% for athlete in athlete_list %} @@ -446,7 +455,25 @@ given ``athlete_list``:: {% endfor %} </ul> -You can also loop over a list in reverse by using ``{% for obj in list reversed %}``. +You can loop over a list in reverse by using ``{% for obj in list reversed %}``. + +**New in Django development version** +If you need to loop over a list of lists, you can unpack the values +in eachs sub-list into a set of known names. For example, if your context contains +a list of (x,y) coordinates called ``points``, you could use the following +to output the list of points:: + + {% for x, y in points %} + There is a point at {{ x }},{{ y }} + {% endfor %} + +This can also be useful if you need to access the items in a dictionary. +For example, if your context contained a dictionary ``data``, the following +would display the keys and values of the dictionary:: + + {% for key, value in data.items %} + {{ key }}: {{ value }} + {% endfor %} The for loop sets a number of variables available within the loop: @@ -702,11 +729,11 @@ Example:: Note that you can backslash-escape a format string if you want to use the "raw" value. In this example, "f" is backslash-escaped, because otherwise "f" is a format string that displays the time. The "o" doesn't need to be -escaped, because it's not a format character.:: +escaped, because it's not a format character:: It is the {% now "jS o\f F" %} -(Displays "It is the 4th of September" %} +This would display as "It is the 4th of September". regroup ~~~~~~~ @@ -737,6 +764,7 @@ The following snippet of template code would accomplish this dubious task:: <li>{{ item }}</li> {% endfor %} </ul> + </li> {% endfor %} </ul> @@ -756,7 +784,7 @@ i.e.:: spaceless ~~~~~~~~~ -Normalizes whitespace between HTML tags to a single space. This includes tab +Removes whitespace between HTML tags. This includes tab characters and newlines. Example usage:: @@ -769,9 +797,9 @@ Example usage:: This example would return this HTML:: - <p> <a href="foo/">Foo</a> </p> + <p><a href="foo/">Foo</a></p> -Only space between *tags* is normalized -- not space between tags and text. In +Only space between *tags* is removed -- not space between tags and text. In this example, the space around ``Hello`` won't be stripped:: {% spaceless %} @@ -842,10 +870,11 @@ The first argument is a path to a view function in the format should be comma-separated values that will be used as positional and keyword arguments in the URL. All arguments required by the URLconf should be present. -For example, suppose you have a view, ``app_name.client``, whose URLconf takes -a client ID. The URLconf line might look like this:: +For example, suppose you have a view, ``app_views.client``, whose URLconf +takes a client ID (here, ``client()`` is a method inside the views file +``app_views.py``). The URLconf line might look like this:: - ('^client/(\d+)/$', 'app_name.client') + ('^client/(\d+)/$', 'app_views.client') If this app's URLconf is included into the project's URLconf under a path such as this:: @@ -854,7 +883,7 @@ such as this:: ...then, in a template, you can create a link to this view like this:: - {% url app_name.client client.id %} + {% url app_views.client client.id %} The template tag will output the string ``/clients/client/123/``. @@ -872,6 +901,23 @@ Above, if ``this_value`` is 175 and ``max_value`` is 200, the the image in the above example will be 88 pixels wide (because 175/200 = .875; .875 * 100 = 87.5 which is rounded up to 88). +with +~~~~ + +**New in Django development version** + +Caches a complex variable under a simpler name. This is useful when accessing +an "expensive" method (e.g., one that hits the database) multiple times. + +For example:: + + {% with business.employees.count as total %} + {{ total }} employee{{ total|pluralize }} + {% endwith %} + +The populated variable (in the example above, ``total``) is only available +between the ``{% with %}`` and ``{% endwith %}`` tags. + Built-in filter reference ------------------------- @@ -970,7 +1016,7 @@ place -- but only if there's a decimal part to be displayed. For example: * ``36.15`` gets converted to ``36.2`` * ``36`` gets converted to ``36`` -If used with a numeric integer argument, ``floatformat`` rounds a number to that +If used with a numeric integer argument, ``floatformat`` rounds a number to that many decimal places. For example: * ``36.1234`` with floatformat:3 gets converted to ``36.123`` @@ -983,7 +1029,7 @@ For example: * ``36.1234`` with floatformat:-3 gets converted to ``36.123`` * ``36`` with floatformat:-4 gets converted to ``36`` -Using ``floatformat`` with no argument is equivalent to using ``floatformat`` with +Using ``floatformat`` with no argument is equivalent to using ``floatformat`` with an argument of ``-1``. get_digit @@ -1275,3 +1321,11 @@ A collection of template filters that implement these common markup languages: * Textile * Markdown * ReST (ReStructured Text) + +django.contrib.webdesign +------------------------ + +A collection of template tags that can be useful while designing a website, +such as a generator of Lorem Ipsum text. See the `webdesign documentation`_. + +.. _webdesign documentation: ../webdesign/ diff --git a/docs/templates_python.txt b/docs/templates_python.txt index 5dd8e4fde0..c967df1a49 100644 --- a/docs/templates_python.txt +++ b/docs/templates_python.txt @@ -212,21 +212,24 @@ template tags. If an invalid variable is provided to one of these template tags, the variable will be interpreted as ``None``. Filters are always applied to invalid variables within these template tags. +If ``TEMPLATE_STRING_IF_INVALID`` contains a ``'%s'``, the format marker will +be replaced with the name of the invalid variable. + .. admonition:: For debug purposes only! - While ``TEMPLATE_STRING_IF_INVALID`` can be a useful debugging tool, - it is a bad idea to turn it on as a 'development default'. - - Many templates, including those in the Admin site, rely upon the - silence of the template system when a non-existent variable is + While ``TEMPLATE_STRING_IF_INVALID`` can be a useful debugging tool, + it is a bad idea to turn it on as a 'development default'. + + Many templates, including those in the Admin site, rely upon the + silence of the template system when a non-existent variable is encountered. If you assign a value other than ``''`` to - ``TEMPLATE_STRING_IF_INVALID``, you will experience rendering + ``TEMPLATE_STRING_IF_INVALID``, you will experience rendering problems with these templates and sites. - - Generally, ``TEMPLATE_STRING_IF_INVALID`` should only be enabled - in order to debug a specific template problem, then cleared + + Generally, ``TEMPLATE_STRING_IF_INVALID`` should only be enabled + in order to debug a specific template problem, then cleared once debugging is complete. - + Playing with Context objects ---------------------------- @@ -291,7 +294,8 @@ return a dictionary of items to be merged into the context. By default, ("django.core.context_processors.auth", "django.core.context_processors.debug", - "django.core.context_processors.i18n") + "django.core.context_processors.i18n", + "django.core.context_processors.media") Each processor is applied in order. That means, if one processor adds a variable to the context and a second processor adds a variable with the same @@ -345,7 +349,7 @@ If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every ``request.user.get_and_delete_messages()`` for every request. That method collects the user's messages and deletes them from the database. - Note that messages are set with ``user.add_message()``. See the + Note that messages are set with ``user.message_set.create``. See the `message docs`_ for more. * ``perms`` -- An instance of @@ -387,6 +391,15 @@ See the `internationalization docs`_ for more. .. _LANGUAGE_CODE setting: ../settings/#language-code .. _internationalization docs: ../i18n/ +django.core.context_processors.media +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every +``RequestContext`` will contain a variable ``MEDIA_URL``, providing the +value of the `MEDIA_URL setting`_. + +.. _MEDIA_URL setting: ../settings/#media-url + django.core.context_processors.request ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -680,14 +693,15 @@ how the compilation works and how the rendering works. When Django compiles a template, it splits the raw template text into ''nodes''. Each node is an instance of ``django.template.Node`` and has -a ``render()`` method. A compiled template is, simply, a list of ``Node`` -objects. When you call ``render()`` on a compiled template object, the template -calls ``render()`` on each ``Node`` in its node list, with the given context. -The results are all concatenated together to form the output of the template. +either a ``render()`` or ``iter_render()`` method. A compiled template is, +simply, a list of ``Node`` objects. When you call ``render()`` on a compiled +template object, the template calls ``render()`` on each ``Node`` in its node +list, with the given context. The results are all concatenated together to +form the output of the template. Thus, to define a custom template tag, you specify how the raw template tag is converted into a ``Node`` (the compilation function), and what the node's -``render()`` method does. +``render()`` or ``iter_render()`` method does. Writing the compilation function ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -714,7 +728,7 @@ object:: # split_contents() knows not to split quoted strings. tag_name, format_string = token.split_contents() except ValueError: - raise template.TemplateSyntaxError, "%r tag requires a single argument" % token.contents[0] + raise template.TemplateSyntaxError, "%r tag requires a single argument" % token.contents.split()[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 CurrentTimeNode(format_string[1:-1]) @@ -757,7 +771,8 @@ Writing the renderer ~~~~~~~~~~~~~~~~~~~~ The second step in writing custom tags is to define a ``Node`` subclass that -has a ``render()`` method. +has a ``render()`` method (we will discuss the ``iter_render()`` alternative +in `Improving rendering speed`_, below). Continuing the above example, we need to define ``CurrentTimeNode``:: @@ -843,7 +858,7 @@ Now your tag should begin to look like this:: # split_contents() knows not to split quoted strings. tag_name, date_to_be_formatted, format_string = token.split_contents() except ValueError: - raise template.TemplateSyntaxError, "%r tag requires exactly two arguments" % token.contents[0] + raise template.TemplateSyntaxError, "%r tag requires exactly two arguments" % token.contents.split()[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 FormatTimeNode(date_to_be_formatted, format_string[1:-1]) @@ -861,12 +876,12 @@ current context, available in the ``render`` method:: def __init__(self, date_to_be_formatted, format_string): self.date_to_be_formatted = date_to_be_formatted self.format_string = format_string - + def render(self, context): try: actual_date = resolve_variable(self.date_to_be_formatted, context) return actual_date.strftime(self.format_string) - except VariableDoesNotExist: + except template.VariableDoesNotExist: return '' ``resolve_variable`` will try to resolve ``blog_entry.date_updated`` and then @@ -1020,7 +1035,7 @@ The ``takes_context`` parameter defaults to ``False``. When it's set to *True*, the tag is passed the context object, as in this example. That's the only difference between this case and the previous ``inclusion_tag`` example. -.. _tutorials: ../tutorial1/#creating-models +.. _tutorials: ../tutorial01/#creating-models Setting a variable in the context ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1077,7 +1092,7 @@ class, like so:: # Splitting by None == splitting by spaces. tag_name, arg = token.contents.split(None, 1) except ValueError: - raise template.TemplateSyntaxError, "%r tag requires arguments" % token.contents[0] + raise template.TemplateSyntaxError, "%r tag requires arguments" % token.contents.split()[0] m = re.search(r'(.*?) as (\w+)', arg) if not m: raise template.TemplateSyntaxError, "%r tag had invalid arguments" % tag_name @@ -1162,6 +1177,48 @@ For more examples of complex rendering, see the source code for ``{% if %}``, .. _configuration: +Improving rendering speed +~~~~~~~~~~~~~~~~~~~~~~~~~ + +For most practical purposes, the ``render()`` method on a ``Node`` will be +sufficient and the simplest way to implement a new tag. However, if your +template tag is expected to produce large strings via ``render()``, you can +speed up the rendering process (and reduce memory usage) using iterative +rendering via the ``iter_render()`` method. + +The ``iter_render()`` method should either be an iterator that yields string +chunks, one at a time, or a method that returns a sequence of string chunks. +The template renderer will join the successive chunks together when creating +the final output. The improvement over the ``render()`` method here is that +you do not need to create one large string containing all the output of the +``Node``, instead you can produce the output in smaller chunks. + +By way of example, here's a trivial ``Node`` subclass that simply returns the +contents of a file it is given:: + + class FileNode(Node): + def __init__(self, filename): + self.filename = filename + + def iter_render(self): + for line in file(self.filename): + yield line + +For very large files, the full file contents will never be read entirely into +memory when this tag is used, which is a useful optimisation. + +If you define an ``iter_render()`` method on your ``Node`` subclass, you do +not need to define a ``render()`` method. The reverse is true as well: the +default ``Node.iter_render()`` method will call your ``render()`` method if +necessary. A useful side-effect of this is that you can develop a new tag +using ``render()`` and producing all the output at once, which is easy to +debug. Then you can rewrite the method as an iterator, rename it to +``iter_render()`` and everything will still work. + +It is compulsory, however, to define *either* ``render()`` or ``iter_render()`` +in your subclass. If you omit them both, a ``TypeError`` will be raised when +the code is imported. + Configuring the template system in standalone mode ================================================== @@ -1193,3 +1250,4 @@ is of obvious interest. .. _settings file: ../settings/#using-settings-without-the-django-settings-module-environment-variable .. _settings documentation: ../settings/ + diff --git a/docs/testing.txt b/docs/testing.txt index 31cea791d3..50c4ec3046 100644 --- a/docs/testing.txt +++ b/docs/testing.txt @@ -2,19 +2,29 @@ Testing Django applications =========================== -Automated testing is an extremely useful weapon in the bug-killing arsenal -of the modern developer. When initially writing code, a test suite can be -used to validate that code behaves as expected. When refactoring or -modifying code, tests serve as a guide to ensure that behavior hasn't -changed unexpectedly as a result of the refactor. +Automated testing is an extremely useful bug-killing tool for the modern +Web developer. You can use a collection of tests -- a **test suite** -- to +solve, or avoid, a number of problems: -Testing a web application is a complex task, as there are many -components of a web application that must be validated and tested. To -help you test your application, Django provides a test execution -framework, and range of utilities that can be used to simulate and -inspect various facets of a web application. + * When you're writing new code, you can use tests to validate your code + works as expected. - This testing framework is currently under development, and may change + * When you're refactoring or modifying old code, you can use tests to + ensure your changes haven't affected your application's behavior + unexpectedly. + +Testing a Web application is a complex task, because a Web application is made +of several layers of logic -- from HTTP-level request handling, to form +validation and processing, to template rendering. With Django's test-execution +framework and assorted utilities, you can simulate requests, insert test data, +inspect your application's output and generally verify your code is doing what +it should be doing. + +The best part is, it's really easy. + +.. admonition:: Note + + This testing framework is currently under development. It may change slightly before the next official Django release. (That's *no* excuse not to write tests, though!) @@ -137,7 +147,7 @@ doctests or unit tests are right for you. If you've been using Python for a while, ``doctest`` will probably feel more "pythonic". It's designed to make writing tests as easy as possible, so there's no overhead of writing classes or methods; you simply put tests in -docstrings. This gives the added advantage of given your modules automatic +docstrings. This gives the added advantage of giving your modules automatic documentation -- well-written doctests can kill both the documentation and the testing bird with a single stone. @@ -166,7 +176,8 @@ To assist in testing various features of your application, Django provides tools that can be used to establish tests and test conditions. * `Test Client`_ -* Fixtures_ +* `TestCase`_ +* `E-mail services`_ Test Client ----------- @@ -216,21 +227,21 @@ can be invoked on the ``Client`` instance. ``post(path, data={}, content_type=MULTIPART_CONTENT)`` Make a POST request on the provided ``path``. If you provide a content type - (e.g., ``text/xml`` for an XML payload), the contents of ``data`` will be - sent as-is in the POST request, using the content type in the HTTP + (e.g., ``text/xml`` for an XML payload), the contents of ``data`` will be + sent as-is in the POST request, using the content type in the HTTP ``Content-Type`` header. - - If you do not provide a value for ``content_type``, the values in + + If you do not provide a value for ``content_type``, the values in ``data`` will be transmitted with a content type of ``multipart/form-data``. The key-value pairs in the data dictionary will be encoded as a multipart message and used to create the POST data payload. - - To submit multiple values for a given key (for example, to specify - the selections for a multiple selection list), provide the values as a + + To submit multiple values for a given key (for example, to specify + the selections for a multiple selection list), provide the values as a list or tuple for the required key. For example, a data dictionary of ``{'choices': ('a','b','d')}`` would submit three selected rows for the field named ``choices``. - + Submitting files is a special case. To POST a file, you need only provide the file field name as a key, and a file handle to the file you wish to upload as a value. The Test Client will populate the two POST fields (i.e., @@ -246,29 +257,42 @@ can be invoked on the ``Client`` instance. file name), and `attachment_file` (containing the file data). Note that you need to manually close the file after it has been provided to the POST. -``login(path, username, password)`` - In a production site, it is likely that some views will be protected with - the @login_required decorator provided by ``django.contrib.auth``. Interacting - with a URL that has been login protected is a slightly complex operation, - so the Test Client provides a simple method to automate the login process. A - call to ``login()`` stimulates the series of GET and POST calls required - to log a user into a @login_required protected view. +``login(**credentials)`` + **New in Django development version** - If login is possible, the final return value of ``login()`` is the response - that is generated by issuing a GET request on the protected URL. If login - is not possible, ``login()`` returns False. + On a production site, it is likely that some views will be protected from + anonymous access through the use of the @login_required decorator, or some + other login checking mechanism. The ``login()`` method can be used to + simulate the effect of a user logging into the site. As a result of calling + this method, the Client will have all the cookies and session data required + to pass any login-based tests that may form part of a view. + + In most cases, the ``credentials`` required by this method are the username + and password of the user that wants to log in, provided as keyword + arguments:: + + c = Client() + c.login(username='fred', password='secret') + # Now you can access a login protected view + + If you are using a different authentication backend, this method may + require different credentials. + + ``login()`` returns ``True`` if it the credentials were accepted and login + was successful. Note that since the test suite will be executed using the test database, - which contains no users by default. As a result, logins for your production - site will not work. You will need to create users as part of the test suite - to be able to test logins to your application. + which contains no users by default. As a result, logins that are valid + on your production site will not work under test conditions. You will + need to create users as part of the test suite (either manually, or + using a test fixture). Testing Responses ~~~~~~~~~~~~~~~~~ -The ``get()``, ``post()`` and ``login()`` methods all return a Response -object. This Response object has the following properties that can be used -for testing purposes: +The ``get()`` and ``post()`` methods both return a Response object. This +Response object has the following properties that can be used for testing +purposes: =============== ========================================================== Property Description @@ -276,7 +300,7 @@ for testing purposes: ``status_code`` The HTTP status of the response. See RFC2616_ for a full list of HTTP status codes. - ``content`` The body of the response. The is the final page + ``content`` The body of the response. This is the final page content as rendered by the view, or any error message (such as the URL for a 302 redirect). @@ -357,9 +381,31 @@ The following is a simple unit test using the Test Client:: # Check that the rendered context contains 5 customers self.failUnlessEqual(len(response.context['customers']), 5) -Fixtures +TestCase -------- +Normal python unit tests extend a base class of ``unittest.testCase``. +Django provides an extension of this base class - ``django.test.TestCase`` +- that provides some additional capabilities that can be useful for +testing web sites. + +Moving from a normal unittest TestCase to a Django TestCase is easy - just +change the base class of your test from ``unittest.TestCase`` to +``django.test.TestCase``. All of the standard Python unit test facilities +will continue to be available, but they will be augmented with some useful +extra facilities. + +Default Test Client +~~~~~~~~~~~~~~~~~~~ +**New in Django development version** + +Every test case in a ``django.test.TestCase`` instance has access to an +instance of a Django `Test Client`_. This Client can be accessed as +``self.client``. This client is recreated for each test. + +Fixture loading +~~~~~~~~~~~~~~~ + A test case for a database-backed website isn't much use if there isn't any data in the database. To make it easy to put test data into the database, Django provides a fixtures framework. @@ -370,22 +416,20 @@ comprise the fixture can be distributed over multiple directories, in multiple applications. .. note:: - If you have synchronized a Django project, you have already experienced + If you have synchronized a Django project, you have already experienced the use of one fixture -- the ``initial_data`` fixture. Every time you synchronize the database, Django installs the ``initial_data`` fixture. This provides a mechanism to populate a new database with any initial data (such as a default set of categories). Fixtures with other names - can be installed manually using ``django-admin.py loaddata``. - + can be installed manually using ``django-admin.py loaddata``. -However, for the purposes of unit testing, each test must be able to +However, for the purposes of unit testing, each test must be able to guarantee the contents of the database at the start of each and every -test. To do this, Django provides a TestCase baseclass that can integrate -with fixtures. +test. -Moving from a normal unittest TestCase to a Django TestCase is easy - just -change the base class of your test, and define a list of fixtures -to be used. For example, the test case from `Writing unittests`_ would +To define a fixture for a test, all you need to do is add a class +attribute to your test describing the fixtures you want the test to use. +For example, the test case from `Writing unittests`_ would look like:: from django.test import TestCase @@ -393,23 +437,116 @@ look like:: class AnimalTestCase(TestCase): fixtures = ['mammals.json', 'birds'] - + def setUp(self): # test definitions as before At the start of each test case, before ``setUp()`` is run, Django will -flush the database, returning the database the state it was in directly -after ``syncdb`` was called. Then, all the named fixtures are installed. +flush the database, returning the database the state it was in directly +after ``syncdb`` was called. Then, all the named fixtures are installed. In this example, any JSON fixture called ``mammals``, and any fixture -named ``birds`` will be installed. See the documentation on +named ``birds`` will be installed. See the documentation on `loading fixtures`_ for more details on defining and installing fixtures. -.. _`loading fixtures`: ../django_admin/#loaddata-fixture-fixture +.. _`loading fixtures`: ../django-admin/#loaddata-fixture-fixture -This flush/load procedure is repeated for each test in the test case, so you -can be certain that the outcome of a test will not be affected by +This flush/load procedure is repeated for each test in the test case, so you +can be certain that the outcome of a test will not be affected by another test, or the order of test execution. +Emptying the test outbox +~~~~~~~~~~~~~~~~~~~~~~~~ +**New in Django development version** + +At the start of each test case, in addition to installing fixtures, +Django clears the contents of the test e-mail outbox. + +For more detail on e-mail services during tests, see `E-mail services`_. + +Assertions +~~~~~~~~~~ +**New in Django development version** + +Normal Python unit tests have a wide range of assertions, such as +``assertTrue`` and ``assertEquals`` that can be used to validate behavior. +``django.TestCase`` adds to these, providing some assertions +that can be useful in testing the behavior of web sites. + +``assertContains(response, text, count=1, status_code=200)`` + Assert that a response indicates that a page could be retrieved and + produced the nominated status code, and that ``text`` occurs ``count`` + times in the content of the response. + +``assertFormError(response, form, field, errors)`` + Assert that a field on a form raised the provided list of errors when + rendered on the form. + + ``form`` is the name the form object was given in the template context. + + ``field`` is the name of the field on the form to check. If ``field`` + has a value of ``None``, non-field errors will be checked. + + ``errors`` is an error string, or a list of error strings, that are + expected as a result of form validation. + +``assertTemplateNotUsed(response, template_name)`` + Assert that the template with the given name was *not* used in rendering + the response. + +``assertRedirects(response, expected_path, status_code=302, target_status_code=200)`` + Assert that the response received produced the nominated status code, + redirects the browser to the provided path, and that retrieving the provided + path yields a response with the target status code. + +``assertTemplateUsed(response, template_name)`` + Assert that the template with the given name was used in rendering the + response. + +E-mail services +--------------- + +**New in Django development version** + +If your view makes use of the `Django e-mail services`_, you don't really +want e-mail to be sent every time you run a test using that view. + +When the Django test framework is initialized, it transparently replaces the +normal `SMTPConnection`_ class with a dummy implementation that redirects all +e-mail to a dummy outbox. This outbox, stored as ``django.core.mail.outbox``, +is a simple list of all `EmailMessage`_ instances that have been sent. +For example, during test conditions, it would be possible to run the following +code:: + + from django.core import mail + + # Send message + mail.send_mail('Subject here', 'Here is the message.', 'from@example.com', + ['to@example.com'], fail_silently=False) + + # One message has been sent + self.assertEqual(len(mail.outbox), 1) + # Subject of first message is correct + self.assertEqual(mail.outbox[0].subject, 'Subject here') + +The ``mail.outbox`` object does not exist under normal execution conditions. +The outbox is created during test setup, along with the dummy `SMTPConnection`_. +When the test framework is torn down, the standard `SMTPConnection`_ class +is restored, and the test outbox is destroyed. + +As noted `previously`_, the test outbox is emptied at the start of every +test in a Django TestCase. To empty the outbox manually, assign the empty list +to mail.outbox:: + + from django.core import mail + + # Empty the test outbox + mail.outbox = [] + +.. _`Django e-mail services`: ../email/ +.. _`SMTPConnection`: ../email/#the-emailmessage-and-smtpconnection-classes +.. _`EmailMessage`: ../email/#the-emailmessage-and-smtpconnection-classes +.. _`previously`: #emptying-the-test-outbox + Running tests ============= @@ -434,6 +571,18 @@ database settings will the same as they would be for the project normally. If you wish to use a name other than the default for the test database, you can use the ``TEST_DATABASE_NAME`` setting to provide a name. +**New in Django development version:** For fine-grained control over the +character encoding of your database, use the ``TEST_DATABASE_CHARSET`` setting. +If you're using MySQL, you can also use the ``TEST_DATABASE_COLLATION`` setting +to control the particular collation used by the test database. See the +settings_ documentation for details of these advanced settings. + +.. _settings: ../settings/ + +The test database is created by the user in the ``DATABASE_USER`` setting. +This user needs to have sufficient privileges to create a new database on the +system. + Once the test database has been established, Django will run your tests. If everything goes well, at the end you'll see:: @@ -468,10 +617,11 @@ failed:: FAILED (failures=1) -The return code for the script will indicate the number of tests that failed. +The return code for the script is the total number of failed and erroneous +tests. If all the tests pass, the return code is 0. Regardless of whether the tests pass or fail, the test database is destroyed when -all the tests have been executed. +all the tests have been executed. Using a different testing framework =================================== @@ -482,7 +632,7 @@ it does provide a mechanism to allow you to invoke tests constructed for an alternative framework as if they were normal Django tests. When you run ``./manage.py test``, Django looks at the ``TEST_RUNNER`` -setting to determine what to do. By default, ``TEST_RUNNER`` points to +setting to determine what to do. By default, ``TEST_RUNNER`` points to ``django.test.simple.run_tests``. This method defines the default Django testing behavior. This behavior involves: @@ -512,7 +662,7 @@ arguments: Verbosity determines the amount of notification and debug information that will be printed to the console; `0` is no output, `1` is normal output, and `2` is verbose output. - + This method should return the number of tests that failed. Testing utilities @@ -523,11 +673,12 @@ a number of utility methods in the ``django.test.utils`` module. ``setup_test_environment()`` Performs any global pre-test setup, such as the installing the - instrumentation of the template rendering system. + instrumentation of the template rendering system and setting up + the dummy SMTPConnection. ``teardown_test_environment()`` Performs any global post-test teardown, such as removing the instrumentation - of the template rendering system. + of the template rendering system and restoring normal e-mail services. ``create_test_db(verbosity=1, autoclobber=False)`` Creates a new test database, and run ``syncdb`` against it. diff --git a/docs/tutorial01.txt b/docs/tutorial01.txt index 56c5fa769e..c40b051b19 100644 --- a/docs/tutorial01.txt +++ b/docs/tutorial01.txt @@ -124,7 +124,7 @@ It worked! Full docs for the development server are at `django-admin documentation`_. -.. _django-admin documentation: ../django_admin/ +.. _django-admin documentation: ../django-admin/ Database setup -------------- @@ -133,8 +133,8 @@ Now, edit ``settings.py``. It's a normal Python module with module-level variables representing Django settings. Change these settings to match your database's connection parameters: - * ``DATABASE_ENGINE`` -- Either 'postgresql', 'mysql' or 'sqlite3'. - More coming soon. + * ``DATABASE_ENGINE`` -- Either 'postgresql_psycopg2', 'mysql' or 'sqlite3'. + Other backends are `also available`_. * ``DATABASE_NAME`` -- The name of your database, or the full (absolute) path to the database file if you're using SQLite. * ``DATABASE_USER`` -- Your database username (not used for SQLite). @@ -143,6 +143,8 @@ database's connection parameters: empty string if your database server is on the same physical machine (not used for SQLite). +.. _also available: ../settings/ + .. admonition:: Note If you're using PostgreSQL or MySQL, make sure you've created a database by @@ -319,7 +321,8 @@ Now Django knows ``mysite`` includes the ``polls`` app. Let's run another comman python manage.py sql polls -You should see the following (the CREATE TABLE SQL statements for the polls app):: +You should see something similar to the following (the CREATE TABLE SQL statements +for the polls app):: BEGIN; CREATE TABLE "polls_poll" ( @@ -337,6 +340,8 @@ You should see the following (the CREATE TABLE SQL statements for the polls app) Note the following: + * The exact output will vary depending on the database you are using. + * Table names are automatically generated by combining the name of the app (``polls``) and the lowercase name of the model -- ``poll`` and ``choice``. (You can override this behavior.) @@ -365,8 +370,9 @@ If you're interested, also run the following commands: * ``python manage.py validate polls`` -- Checks for any errors in the construction of your models. - * ``python manage.py sqlinitialdata polls`` -- Outputs any initial data - required for Django's admin framework and your models. + * ``python manage.py sqlcustom polls`` -- Outputs any custom SQL statements + (such as table modifications or constraints) that are defined for the + application. * ``python manage.py sqlclear polls`` -- Outputs the necessary ``DROP TABLE`` statements for this app, according to which tables already exist @@ -376,7 +382,7 @@ If you're interested, also run the following commands: statements for this app. * ``python manage.py sqlall polls`` -- A combination of all the SQL from - the 'sql', 'sqlinitialdata', and 'sqlindexes' commands. + the 'sql', 'sqlcustom', and 'sqlindexes' commands. Looking at the output of those commands can help you understand what's actually happening under the hood. @@ -394,7 +400,7 @@ as you like, and it will only ever create the tables that don't exist. Read the `django-admin.py documentation`_ for full information on what the ``manage.py`` utility can do. -.. _django-admin.py documentation: ../django_admin/ +.. _django-admin.py documentation: ../django-admin/ Playing with the API ==================== @@ -571,5 +577,5 @@ For full details on the database API, see our `Database API reference`_. When you're comfortable with the API, read `part 2 of this tutorial`_ to get Django's automatic admin working. -.. _Database API reference: ../db_api/ -.. _part 2 of this tutorial: ../tutorial2/ +.. _Database API reference: ../db-api/ +.. _part 2 of this tutorial: ../tutorial02/ diff --git a/docs/tutorial02.txt b/docs/tutorial02.txt index 2eabae96f0..99f586b4a1 100644 --- a/docs/tutorial02.txt +++ b/docs/tutorial02.txt @@ -5,7 +5,7 @@ Writing your first Django app, part 2 This tutorial begins where `Tutorial 1`_ left off. We're continuing the Web-poll application and will focus on Django's automatically-generated admin site. -.. _Tutorial 1: ../tutorial1/ +.. _Tutorial 1: ../tutorial01/ .. admonition:: Philosophy @@ -61,8 +61,8 @@ tutorial, remember?) You should see the Django admin index page: :alt: Django admin index page :target: http://media.djangoproject.com/img/doc/tutorial/admin02.png -By default, you should see two types of editable content: groups and users. -These are core features Django ships with by default. +You should see a few other types of editable content, including groups, users +and sites. These are core features Django ships with by default. .. _"I can't log in" questions: ../faq/#the-admin-site @@ -320,7 +320,7 @@ method a ``short_description`` attribute:: Let's add another improvement to the Poll change list page: Filters. Add the -following line to ``Poll.admin``:: +following line to ``Poll.Admin``:: list_filter = ['pub_date'] @@ -434,4 +434,4 @@ When you're comfortable with the admin site, read `part 3 of this tutorial`_ to start working on public poll views. .. _Django admin CSS guide: ../admin_css/ -.. _part 3 of this tutorial: ../tutorial3/ +.. _part 3 of this tutorial: ../tutorial03/ diff --git a/docs/tutorial03.txt b/docs/tutorial03.txt index 17b6ec0c68..41febe021d 100644 --- a/docs/tutorial03.txt +++ b/docs/tutorial03.txt @@ -5,7 +5,7 @@ Writing your first Django app, part 3 This tutorial begins where `Tutorial 2`_ left off. We're continuing the Web-poll application and will focus on creating the public interface -- "views." -.. _Tutorial 2: ../tutorial2/ +.. _Tutorial 2: ../tutorial02/ Philosophy ========== @@ -60,9 +60,10 @@ arguments from the dictionary (an optional third item in the tuple). For more on ``HTTPRequest`` objects, see the `request and response documentation`_. For more details on URLconfs, see the `URLconf documentation`_. -When you ran ``python manage.py startproject mysite`` at the beginning of +When you ran ``python django-admin.py startproject mysite`` at the beginning of Tutorial 1, it created a default URLconf in ``mysite/urls.py``. It also -automatically set your ``ROOT_URLCONF`` setting to point at that file:: +automatically set your ``ROOT_URLCONF`` setting (in ``settings.py``) to point +at that file:: ROOT_URLCONF = 'mysite.urls' @@ -463,4 +464,4 @@ All the poll app cares about is its relative URLs, not its absolute URLs. When you're comfortable with writing views, read `part 4 of this tutorial`_ to learn about simple form processing and generic views. -.. _part 4 of this tutorial: ../tutorial4/ +.. _part 4 of this tutorial: ../tutorial04/ diff --git a/docs/tutorial04.txt b/docs/tutorial04.txt index b1c8c7d4fc..5cc12c445d 100644 --- a/docs/tutorial04.txt +++ b/docs/tutorial04.txt @@ -48,6 +48,7 @@ So let's create a ``vote()`` function in ``mysite/polls/views.py``:: from django.shortcuts import get_object_or_404, render_to_response from django.http import HttpResponseRedirect + from django.core.urlresolvers import reverse from mysite.polls.models import Choice, Poll # ... def vote(request, poll_id): @@ -66,7 +67,7 @@ So let's create a ``vote()`` function in ``mysite/polls/views.py``:: # Always return an HttpResponseRedirect after successfully dealing # with POST data. This prevents data from being posted twice if a # user hits the Back button. - return HttpResponseRedirect('/polls/%s/results/' % p.id) + return HttpResponseRedirect(reverse('mysite.polls.views.results', args=(p.id,))) This code includes a few things we haven't covered yet in this tutorial: @@ -86,13 +87,29 @@ This code includes a few things we haven't covered yet in this tutorial: * After incrementing the choice count, the code returns an ``HttpResponseRedirect`` rather than a normal ``HttpResponse``. ``HttpResponseRedirect`` takes a single argument: the URL to which the - user will be redirected. You should leave off the "http://" and domain - name if you can. That helps your app become portable across domains. + user will be redirected (see the following point for how we construct + the URL in this case). As the Python comment above points out, you should always return an ``HttpResponseRedirect`` after successfully dealing with POST data. This tip isn't specific to Django; it's just good Web development practice. + * We are using the ``reverse()`` function in the ``HttpResponseRedirect`` + constructor in this example. This function helps avoid having to + hardcode a URL in the view function. It is given the name of the view + that we want to pass control to and the variable portion of the URL + pattern that points to that view. In this case, using the URLConf we set + up in Tutorial 3, this ``reverse()`` call will return a string like :: + + '/polls/3/results/' + + ... where the ``3`` is the value of ``p.id``. This redirected URL will + then call the ``'results'`` view to display the final page. Note that + you need to use the full name of the view here (including the prefix). + + For more information about ``reverse()``, see the `URL dispatcher`_ + documentation. + As mentioned in Tutorial 3, ``request`` is a ``HTTPRequest`` object. For more on ``HTTPRequest`` objects, see the `request and response documentation`_. @@ -121,6 +138,7 @@ results page that gets updated each time you vote. If you submit the form without having chosen a choice, you should see the error message. .. _request and response documentation: ../request_response/ +.. _URL dispatcher: ../url_dispatch#reverse Use generic views: Less code is better ====================================== @@ -219,7 +237,7 @@ template. Note that we use ``dict()`` to return an altered dictionary in place. If you'd like to know more about how that works, The Django database API documentation `explains the lazy nature of QuerySet objects`_. -.. _explains the lazy nature of QuerySet objects: ../db_api/#querysets-are-lazy +.. _explains the lazy nature of QuerySet objects: ../db-api/#querysets-are-lazy In previous parts of the tutorial, the templates have been provided with a context that contains the ``poll`` and ``latest_poll_list`` context variables. However, @@ -256,4 +274,8 @@ installments: * Advanced admin features: Permissions * Advanced admin features: Custom JavaScript -.. _Tutorial 3: ../tutorial3/ +In the meantime, you can read through the rest of the `Django documentation`_ +and start writing your own applications. + +.. _Tutorial 3: ../tutorial03/ +.. _Django documentation: http://www.djangoproject.com/documentation/ diff --git a/docs/url_dispatch.txt b/docs/url_dispatch.txt index 85c87de680..402b1200b5 100644 --- a/docs/url_dispatch.txt +++ b/docs/url_dispatch.txt @@ -185,10 +185,26 @@ The first argument to ``patterns()`` is a string ``prefix``. See The remaining arguments should be tuples in this format:: - (regular expression, Python callback function [, optional dictionary]) + (regular expression, Python callback function [, optional dictionary [, optional name]]) -...where ``optional dictionary`` is optional. (See -_`Passing extra options to view functions` below.) +...where ``optional dictionary`` and ``optional name`` are optional. (See +`Passing extra options to view functions`_ below.) + +url +--- + +**New in Django development version** + +You can use the ``url()`` function, instead of a tuple, as an argument to +``patterns()``. This is convenient if you want to specify a name without the +optional extra arguments dictionary. For example:: + + urlpatterns = patterns('', + url(r'/index/$', index_view, name="main-view"), + ... + ) + +See `Naming URL patterns`_ for why the ``name`` parameter is useful. handler404 ---------- @@ -479,3 +495,94 @@ The style you use is up to you. Note that if you use this technique -- passing objects rather than strings -- the view prefix (as explained in "The view prefix" above) will have no effect. + +Naming URL patterns +=================== + +**New in Django development version** + +It's fairly common to use the same view function in multiple URL patterns in +your URLconf. For example, these two URL patterns both point to the ``archive`` +view:: + + urlpatterns = patterns('', + (r'/archive/(\d{4})/$', archive), + (r'/archive-summary/(\d{4})/$', archive, {'summary': True}), + ) + +This is completely valid, but it leads to problems when you try to do reverse +URL matching (through the ``permalink()`` decorator or the ``{% url %}`` +template tag). Continuing this example, if you wanted to retrieve the URL for +the ``archive`` view, Django's reverse URL matcher would get confused, because +*two* URLpatterns point at that view. + +To solve this problem, Django supports **named URL patterns**. That is, you can +give a name to a URL pattern in order to distinguish it from other patterns +using the same view and parameters. Then, you can use this name in reverse URL +matching. + +Here's the above example, rewritten to used named URL patterns:: + + urlpatterns = patterns('', + url(r'/archive/(\d{4})/$', archive, name="full-archive"), + url(r'/archive-summary/(\d{4})/$', archive, {'summary': True}, "arch-summary"), + ) + +With these names in place (``full-archive`` and ``arch-summary``), you can +target each pattern individually by using its name:: + + {% url arch-summary 1945 %} + {% url full-archive 2007 %} + +Even though both URL patterns refer to the ``archive`` view here, using the +``name`` parameter to ``url()`` allows you to tell them apart in templates. + +The string used for the URL name can contain any characters you like. You are +not restricted to valid Python names. + +.. note:: + + When you name your URL patterns, make sure you use names that are unlikely + to clash with any other application's choice of names. If you call your URL + pattern ``comment``, and another application does the same thing, there's + no guarantee which URL will be inserted into your template when you use + this name. + + Putting a prefix on your URL names, perhaps derived from the application + name, will decrease the chances of collision. We recommend something like + ``myapp-comment`` instead of ``comment``. + +Utility methods +=============== + +reverse() +--------- + +If you need to use something similar to the ``{% url %}`` template tag in your +code, Django provides the ``django.core.urlresolvers.reverse()``. The +``reverse()`` function has the following signature:: + + reverse(viewname, urlconf=None, args=None, kwargs=None) + +``viewname`` is either the function name (either a function reference, or the +string version of the name, if you used that form in ``urlpatterns``) or the +`URL pattern name`_. Normally, you won't need to worry about the +``urlconf`` parameter and will only pass in the positional and keyword +arguments to use in the URL matching. For example:: + + from django.core.urlresolvers import reverse + + def myview(request): + return HttpResponseRedirect(reverse('arch-summary', args=[1945])) + +.. _URL pattern name: `Naming URL patterns`_ + +permalink() +----------- + +The ``permalink()`` decorator is useful for writing short methods that return +a full URL path. For example, a model's ``get_absolute_url()`` method. Refer +to the `model API documentation`_ for more information about ``permalink()``. + +.. _model API documentation: ../model-api/#the-permalink-decorator + diff --git a/docs/webdesign.txt b/docs/webdesign.txt new file mode 100644 index 0000000000..8e6eae89dd --- /dev/null +++ b/docs/webdesign.txt @@ -0,0 +1,53 @@ +======================== +django.contrib.webdesign +======================== + +The ``django.contrib.webdesign`` package, part of the `"django.contrib" add-ons`_, +provides various Django helpers that are particularly useful to Web *designers* +(as opposed to developers). + +At present, the package contains only a single template tag. If you have ideas +for Web-designer-friendly functionality in Django, please `suggest them`_. + +.. _"django.contrib" add-ons: ../add_ons/ +.. _suggest them: ../contributing/ + +Template tags +============= + +To use these template tags, add ``'django.contrib.webdesign'`` to your +``INSTALLED_APPS`` setting. Once you've done that, use +``{% load webdesign %}`` in a template to give your template access to the tags. + + +lorem +===== + +Displays random "lorem ipsum" Latin text. This is useful for providing sample +data in templates. + +Usage:: + + {% lorem [count] [method] [random] %} + +The ``{% lorem %}`` tag can be used with zero, one, two or three arguments. +The arguments are: + + =========== ============================================================= + Argument Description + =========== ============================================================= + ``count`` A number (or variable) containing the number of paragraphs or + words to generate (default is 1). + ``method`` Either ``w`` for words, ``p`` for HTML paragraphs or ``b`` + for plain-text paragraph blocks (default is ``b``). + ``random`` The word ``random``, which if given, does not use the common + paragraph ("Lorem ipsum dolor sit amet...") when generating + text. + =========== ============================================================= + +Examples: + + * ``{% lorem %}`` will output the common "lorem ipsum" paragraph. + * ``{% lorem 3 p %}`` will output the common "lorem ipsum" paragraph + and two random paragraphs each wrapped in HTML ``<p>`` tags. + * ``{% lorem 2 w random %}`` will output two random Latin words. |
