Anonymous avatar Anonymous committed 6b87af6

boulder-oracle-sprint: Merged to [5462]

Comments (0)

Files changed (23)

     Michal Chruszcz <troll@pld-linux.org>
     Ian Clelland <clelland@gmail.com>
     crankycoder@gmail.com
+    Pete Crosier <pete.crosier@gmail.com>
     Matt Croydon <http://www.postneo.com/>
     flavio.curella@gmail.com
     Jure Cuhalev <gandalf@owca.info>
     junzhang.jn@gmail.com
     Antti Kaihola <http://akaihola.blogspot.com/>
     Ben Dean Kawamura <ben.dean.kawamura@gmail.com>
+    ian.g.kelly@gmail.com
     Garth Kidd <http://www.deadlybloodyserious.com/>
     kilian <kilian.cavalotti@lip6.fr>
     Sune Kirkeby <http://ibofobi.dk/>
     mitakummaa@gmail.com
     mmarshall
     Eric Moritz <http://eric.themoritzfamily.com/>
+    mrmachine <real.human@mrmachine.net>
     Robin Munn <http://www.geekforgod.com/>
     Robert Myers <myer0052@gmail.com>
     Nebojša Dorđević
     wangchun <yaohua2000@gmail.com>
     Dan Watson <http://theidioteque.net/>
     Chris Wesseling <Chris.Wesseling@cwi.nl>
+    James Wheare <django@sparemint.com>
     charly.wilhelm@gmail.com
     Rachel Willmer <http://www.willmer.com/kb/>
     Gary Wilson <gary.wilson@gmail.com>

django/__init__.py

 VERSION = (0, 97, 'pre')
+
+def get_version():
+    "Returns the version as a human-format string."
+    v = '.'.join([str(i) for i in VERSION[:-1]])
+    if VERSION[-1]:
+        v += '-' + VERSION[-1]
+    return v

django/conf/global_settings.py

 
 # The User-Agent string to use when checking for URL validity through the
 # isExistingURL validator.
-URL_VALIDATOR_USER_AGENT = "Django/0.96pre (http://www.djangoproject.com)"
+from django import get_version
+URL_VALIDATOR_USER_AGENT = "Django/%s (http://www.djangoproject.com)" % get_version()
 
 ##############
 # MIDDLEWARE #
Add a comment to this file

django/conf/locale/nl/LC_MESSAGES/django.mo

Binary file modified.

django/conf/locale/nl/LC_MESSAGES/django.po

 msgstr[1] "dagen"
 
 #: utils/timesince.py:16
+# In the timesince context it is stilistically wrong to use the plural for hour in Dutch.
 msgid "hour"
 msgid_plural "hours"
 msgstr[0] "uur"
-msgstr[1] "uren"
+msgstr[1] "uur"
 
 #: utils/timesince.py:17
 msgid "minute"

django/core/management.py

 
 import django
 from django.core.exceptions import ImproperlyConfigured
-import os, re, shutil, sys, textwrap
 from optparse import OptionParser
 from django.utils import termcolors
+import os, re, shutil, sys, textwrap
 
 # For Python 2.3
 if not hasattr(__builtins__, 'set'):
     from sets import Set as set
 
+# For backwards compatibility: get_version() used to be in this module.
+get_version = django.get_version
+
 MODULE_TEMPLATE = '''    {%% if perms.%(app)s.%(addperm)s or perms.%(app)s.%(changeperm)s %%}
     <tr>
         <th>{%% if perms.%(app)s.%(changeperm)s %%}<a href="%(app)s/%(mod)s/">{%% endif %%}%(name)s{%% if perms.%(app)s.%(changeperm)s %%}</a>{%% endif %%}</th>
 # field as the field to which it points.
 get_rel_data_type = lambda f: (f.get_internal_type() in ('AutoField', 'PositiveIntegerField', 'PositiveSmallIntegerField')) and 'IntegerField' or f.get_internal_type()
 
-def get_version():
-    "Returns the version as a human-format string."
-    from django import VERSION
-    v = '.'.join([str(i) for i in VERSION[:-1]])
-    if VERSION[-1]:
-        v += '-' + VERSION[-1]
-    return v
-
 def get_sql_create(app):
     "Returns a list of the CREATE TABLE SQL statements for the given app."
     from django.db import get_creation_module, models

django/db/backends/postgresql/base.py

     from django.db import models
     output = []
     for model in model_list:
+        # Use `coalesce` to set the sequence for each model to the max pk value if there are records,
+        # or 1 if there are none. Set the `is_called` property (the third argument to `setval`) to true
+        # if there are records (as the max pk value is already in use), otherwise set it to false.
         for f in model._meta.fields:
             if isinstance(f, models.AutoField):
-                output.append("%s setval('%s', (%s max(%s) %s %s));" % \
+                output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
                     (style.SQL_KEYWORD('SELECT'),
                     style.SQL_FIELD(quote_name('%s_%s_seq' % (model._meta.db_table, f.column))),
-                    style.SQL_KEYWORD('SELECT'),
                     style.SQL_FIELD(quote_name(f.column)),
+                    style.SQL_FIELD(quote_name(f.column)),
+                    style.SQL_KEYWORD('IS NOT'),
                     style.SQL_KEYWORD('FROM'),
                     style.SQL_TABLE(quote_name(model._meta.db_table))))
                 break # Only one AutoField is allowed per model, so don't bother continuing.
         for f in model._meta.many_to_many:
-            output.append("%s setval('%s', (%s max(%s) %s %s));" % \
+            output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
                 (style.SQL_KEYWORD('SELECT'),
                 style.SQL_FIELD(quote_name('%s_id_seq' % f.m2m_db_table())),
-                style.SQL_KEYWORD('SELECT'),
                 style.SQL_FIELD(quote_name('id')),
+                style.SQL_FIELD(quote_name('id')),
+                style.SQL_KEYWORD('IS NOT'),
                 style.SQL_KEYWORD('FROM'),
                 style.SQL_TABLE(f.m2m_db_table())))
     return output

django/db/backends/postgresql_psycopg2/base.py

     from django.db import models
     output = []
     for model in model_list:
+        # Use `coalesce` to set the sequence for each model to the max pk value if there are records,
+        # or 1 if there are none. Set the `is_called` property (the third argument to `setval`) to true
+        # if there are records (as the max pk value is already in use), otherwise set it to false.
         for f in model._meta.fields:
             if isinstance(f, models.AutoField):
-                output.append("%s setval('%s', (%s max(%s) %s %s));" % \
+                output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
                     (style.SQL_KEYWORD('SELECT'),
                     style.SQL_FIELD(quote_name('%s_%s_seq' % (model._meta.db_table, f.column))),
-                    style.SQL_KEYWORD('SELECT'),
                     style.SQL_FIELD(quote_name(f.column)),
+                    style.SQL_FIELD(quote_name(f.column)),
+                    style.SQL_KEYWORD('IS NOT'),
                     style.SQL_KEYWORD('FROM'),
                     style.SQL_TABLE(quote_name(model._meta.db_table))))
                 break # Only one AutoField is allowed per model, so don't bother continuing.
         for f in model._meta.many_to_many:
-            output.append("%s setval('%s', (%s max(%s) %s %s));" % \
+            output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
                 (style.SQL_KEYWORD('SELECT'),
                 style.SQL_FIELD(quote_name('%s_id_seq' % f.m2m_db_table())),
-                style.SQL_KEYWORD('SELECT'),
                 style.SQL_FIELD(quote_name('id')),
+                style.SQL_FIELD(quote_name('id')),
+                style.SQL_KEYWORD('IS NOT'),
                 style.SQL_KEYWORD('FROM'),
                 style.SQL_TABLE(f.m2m_db_table())))
     return output

django/db/backends/util.py

     return str(s)[0].lower() == 't'
 
 def typecast_decimal(s):
-    if s is None:
+    if s is None or s == '':
         return None
     return decimal.Decimal(s)
 

django/template/defaulttags.py

 from django.template import get_library, Library, InvalidTemplateLibrary
 from django.conf import settings
 import sys
+import re
+
+if not hasattr(__builtins__, 'reversed'):
+    # For Python 2.3.
+    # From http://www.python.org/doc/current/tut/node11.html
+    def reversed(data):
+        for index in xrange(len(data)-1, -1, -1):
+            yield data[index]
+
 
 register = Library()
 
         return ''
 
 class ForNode(Node):
-    def __init__(self, loopvar, sequence, reversed, nodelist_loop):
-        self.loopvar, self.sequence = loopvar, sequence
+    def __init__(self, loopvars, sequence, reversed, nodelist_loop):
+        self.loopvars, self.sequence = loopvars, sequence
         self.reversed = reversed
         self.nodelist_loop = nodelist_loop
 
         else:
             reversed = ''
         return "<For Node: for %s in %s, tail_len: %d%s>" % \
-            (self.loopvar, self.sequence, len(self.nodelist_loop), reversed)
+            (', '.join( self.loopvars ), self.sequence, len(self.nodelist_loop), reversed)
 
     def __iter__(self):
         for node in self.nodelist_loop:
             values = list(values)
         len_values = len(values)
         if self.reversed:
-            # From http://www.python.org/doc/current/tut/node11.html
-            def reverse(data):
-                for index in range(len(data)-1, -1, -1):
-                    yield data[index]
-            values = reverse(values)
+            values = reversed(values)
+        unpack = len(self.loopvars) > 1
         for i, item in enumerate(values):
             context['forloop'] = {
                 # shortcuts for current loop iteration number
                 'last': (i == len_values - 1),
                 'parentloop': parentloop,
             }
-            context[self.loopvar] = item
+            if unpack:
+                # If there are multiple loop variables, unpack the item into them.
+                context.update(dict(zip(self.loopvars, item)))
+            else:
+                context[self.loopvars[0]] = item
             for node in self.nodelist_loop:
                 nodelist.append(node.render(context))
+            if unpack:
+                # The loop variables were pushed on to the context so pop them
+                # off again. This is necessary because the tag lets the length
+                # of loopvars differ to the length of each set of items and we
+                # don't want to leave any vars from the previous loop on the
+                # context.
+                context.pop()
         context.pop()
         return nodelist.render(context)
 
     nodelist = parser.parse(('endfilter',))
     parser.delete_first_token()
     return FilterNode(filter_expr, nodelist)
-filter = register.tag("filter", do_filter)
+do_filter = register.tag("filter", do_filter)
 
 #@register.tag
 def firstof(parser, token):
         {% endfor %}
         </ul>
 
-    You can also loop over a list in reverse by using
+    You can loop over a list in reverse by using
     ``{% for obj in list reversed %}``.
+    
+    You can also unpack multiple values from a two-dimensional array::
+    
+        {% for key,value in dict.items %}
+            {{ key }}: {{ value }}
+        {% endfor %}
 
     The for loop sets a number of variables available within the loop:
 
 
     """
     bits = token.contents.split()
-    if len(bits) == 5 and bits[4] != 'reversed':
-        raise TemplateSyntaxError, "'for' statements with five words should end in 'reversed': %s" % token.contents
-    if len(bits) not in (4, 5):
-        raise TemplateSyntaxError, "'for' statements should have either four or five words: %s" % token.contents
-    if bits[2] != 'in':
-        raise TemplateSyntaxError, "'for' statement must contain 'in' as the second word: %s" % token.contents
-    loopvar = bits[1]
-    sequence = parser.compile_filter(bits[3])
-    reversed = (len(bits) == 5)
+    if len(bits) < 4:
+        raise TemplateSyntaxError, "'for' statements should have at least four words: %s" % token.contents
+
+    reversed = bits[-1] == 'reversed'
+    in_index = reversed and -3 or -2
+    if bits[in_index] != 'in':
+        raise TemplateSyntaxError, "'for' statements should use the format 'for x in y': %s" % token.contents
+
+    loopvars = re.sub(r' *, *', ',', ' '.join(bits[1:in_index])).split(',')
+    for var in loopvars:
+        if not var or ' ' in var:
+            raise TemplateSyntaxError, "'for' tag received an invalid argument: %s" % token.contents
+
+    sequence = parser.compile_filter(bits[in_index+1])
     nodelist_loop = parser.parse(('endfor',))
     parser.delete_first_token()
-    return ForNode(loopvar, sequence, reversed, nodelist_loop)
+    return ForNode(loopvars, sequence, reversed, nodelist_loop)
 do_for = register.tag("for", do_for)
 
 def do_ifequal(parser, token, negate):

django/views/debug.py

 from django.template import Template, Context, TemplateDoesNotExist
 from django.utils.html import escape
 from django.http import HttpResponseServerError, HttpResponseNotFound
-import os, re
+import os, re, sys
 
 HIDDEN_SETTINGS = re.compile('SECRET|PASSWORD|PROFANITIES_LIST')
 
         'request': request,
         'request_protocol': request.is_secure() and "https" or "http",
         'settings': get_safe_settings(),
+        'sys_executable' : sys.executable,
+        'sys_version_info' : '%d.%d.%d' % sys.version_info[0:3],
         'template_info': template_info,
         'template_does_not_exist': template_does_not_exist,
         'loader_debug_info': loader_debug_info,
       <th>Exception Location:</th>
       <td>{{ lastframe.filename|escape }} in {{ lastframe.function|escape }}, line {{ lastframe.lineno }}</td>
     </tr>
+    <tr>
+      <th>Python Executable:</th>
+      <td>{{ sys_executable|escape }}</td>
+    </tr>
+    <tr>
+      <th>Python Version:</th>
+      <td>{{ sys_version_info }}</td>
+    </tr>
   </table>
 </div>
 {% if template_does_not_exist %}
 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
 
 
 .. _Tutorial 2: ../tutorial02/
 
+Requires the auth_ and contenttypes_ contrib packages to be installed.
+
 auth
 ====
 
 
 .. _flatpages documentation: ../flatpages/
 
+Requires the sites_ contrib package to be installed as well.
+
 localflavor
 ===========
 

docs/authentication.txt

 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``.
 
 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
 -------------------------------------
 
 `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')
     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')
 
 
     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``
       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>

docs/man/django-admin.1

+.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.
+

docs/model-api.txt

 
 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``
 ~~~~~~~~~~~~~~~~
 
         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
 
 .. _Python DB-API: http://www.python.org/peps/pep-0249.html
 .. _Other lookup options: ../db-api/#extra-params-select-where-tables
+.. _transaction handling: ../transactions/
 
 Overriding default model methods
 --------------------------------

docs/modpython.txt

 ``<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::
 

docs/newforms.txt

 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.
+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()
 ----------------------------------
 
 Let's put this all together and use the ``ContactForm`` example in a Django
-view and template. This example view displays the contact form by default and
-validates/processes it if accessed via a POST request::
+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()
         return render_to_response('contact.html', {'form': form})
 
-Simple template output
-~~~~~~~~~~~~~~~~~~~~~~
+Simple template example
+~~~~~~~~~~~~~~~~~~~~~~~
 
-The template, ``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 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::
 
 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 listed in the order in which
+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
 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.
 
 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 kick of 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 submittor, 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 thei 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
 ===========================
 

docs/templates.txt

 ``{{ 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.
 
 ~~~
 
 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 %}
     {% 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:
 

scripts/rpm-install.sh

 # Make sure we match foo.pyo and foo.pyc along with foo.py (but only once each)
 sed -e "/\.py[co]$/d" -e "s/\.py$/.py*/" DIRS FILES >INSTALLED_FILES
 
+mkdir -p ${RPM_BUILD_ROOT}/%{_mandir}/man1/
+cp docs/man/* ${RPM_BUILD_ROOT}/%{_mandir}/man1/
+cat << EOF >> INSTALLED_FILES
+%doc %{_mandir}/man1/*"
+EOF

tests/regressiontests/serializers_regress/tests.py

 
     obj = ComplexModel(field1='first',field2='second',field3='third')
     obj.save()
-    
+
     # Serialize then deserialize the test database
     serialized_data = serializers.serialize(format, [obj], indent=2, fields=('field1','field3'))
     result = serializers.deserialize(format, serialized_data).next()
-    
+
     # Check that the deserialized object contains data in only the serialized fields.
     self.assertEqual(result.object.field1, 'first')
     self.assertEqual(result.object.field2, '')
 
     obj = ComplexModel(field1='first',field2='second',field3='third')
     obj.save()
-    
+
     # Serialize the test database to a stream
-    stream = StringIO()    
+    stream = StringIO()
     serializers.serialize(format, [obj], indent=2, stream=stream)
-    
+
     # Serialize normally for a comparison
     string_data = serializers.serialize(format, [obj], indent=2)
 
     # Check that the two are the same
-    self.assertEqual(string_data, stream.buffer())
+    self.assertEqual(string_data, stream.getvalue())
     stream.close()
-    
+
 for format in serializers.get_serializer_formats():
     setattr(SerializerTests, 'test_'+format+'_serializer', curry(serializerTest, format))
     setattr(SerializerTests, 'test_'+format+'_serializer_fields', curry(fieldsTest, format))
-    setattr(SerializerTests, 'test_'+format+'_serializer_stream', curry(fieldsTest, format))
+    if format != 'python':
+        setattr(SerializerTests, 'test_'+format+'_serializer_stream', curry(streamTest, format))

tests/regressiontests/templates/tests.py

             'for-tag-vars02': ("{% for val in values %}{{ forloop.counter0 }}{% endfor %}", {"values": [6, 6, 6]}, "012"),
             'for-tag-vars03': ("{% for val in values %}{{ forloop.revcounter }}{% endfor %}", {"values": [6, 6, 6]}, "321"),
             'for-tag-vars04': ("{% for val in values %}{{ forloop.revcounter0 }}{% endfor %}", {"values": [6, 6, 6]}, "210"),
+            'for-tag-unpack01': ("{% for key,value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"),
+            'for-tag-unpack03': ("{% for key, value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"),
+            'for-tag-unpack04': ("{% for key , value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"),
+            'for-tag-unpack05': ("{% for key ,value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"),
+            'for-tag-unpack06': ("{% for key value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, template.TemplateSyntaxError),
+            'for-tag-unpack07': ("{% for key,,value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, template.TemplateSyntaxError),
+            'for-tag-unpack08': ("{% for key,value, in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, template.TemplateSyntaxError),
+            # Ensure that a single loopvar doesn't truncate the list in val.
+            'for-tag-unpack09': ("{% for val in items %}{{ val.0 }}:{{ val.1 }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"),
+            # Otherwise, silently truncate if the length of loopvars differs to the length of each set of items.
+            'for-tag-unpack10': ("{% for x,y in items %}{{ x }}:{{ y }}/{% endfor %}", {"items": (('one', 1, 'carrot'), ('two', 2, 'orange'))}, "one:1/two:2/"),
+            'for-tag-unpack11': ("{% for x,y,z in items %}{{ x }}:{{ y }},{{ z }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, ("one:1,/two:2,/", "one:1,INVALID/two:2,INVALID/")),
+            'for-tag-unpack12': ("{% for x,y,z in items %}{{ x }}:{{ y }},{{ z }}/{% endfor %}", {"items": (('one', 1, 'carrot'), ('two', 2))}, ("one:1,carrot/two:2,/", "one:1,carrot/two:2,INVALID/")),
+            'for-tag-unpack13': ("{% for x,y,z in items %}{{ x }}:{{ y }},{{ z }}/{% endfor %}", {"items": (('one', 1, 'carrot'), ('two', 2, 'cheese'))}, ("one:1,carrot/two:2,cheese/", "one:1,carrot/two:2,cheese/")),
 
             ### IF TAG ################################################################
             'if-tag01': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": True}, "yes"),
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.