[Python-modules-commits] [python-django] 01/03: Imported Upstream version 1.7.9

Raphaël Hertzog hertzog at moszumanska.debian.org
Wed Jul 8 23:39:46 UTC 2015


This is an automated email from the git hooks/post-receive script.

hertzog pushed a commit to branch debian/sid
in repository python-django.

commit d16a450f271fa5fe3ef10b43f47307ed95b793bb
Author: Raphaël Hertzog <hertzog at debian.org>
Date:   Thu Jul 9 01:33:03 2015 +0200

    Imported Upstream version 1.7.9
---
 Django.egg-info/PKG-INFO                         |   2 +-
 Django.egg-info/SOURCES.txt                      |   3 +
 PKG-INFO                                         |   2 +-
 django/__init__.py                               |   2 +-
 django/apps/registry.py                          |   2 +-
 django/contrib/sessions/backends/cache.py        |   6 +-
 django/contrib/sessions/backends/cached_db.py    |   4 +-
 django/contrib/sessions/backends/db.py           |   5 +-
 django/contrib/sessions/backends/file.py         |   5 +-
 django/contrib/sessions/tests.py                 |  20 ++++
 django/core/validators.py                        |  27 +++--
 django/db/backends/mysql/schema.py               |  19 ++++
 django/db/backends/postgresql_psycopg2/schema.py |   9 +-
 django/db/backends/schema.py                     |  81 ++++++++-----
 django/db/backends/sqlite3/introspection.py      |   5 +-
 django/db/models/sql/compiler.py                 |   3 +-
 django/test/testcases.py                         |  14 ++-
 docs/howto/deployment/wsgi/apache-auth.txt       |   2 +-
 docs/internals/deprecation.txt                   |   2 +-
 docs/internals/release-process.txt               |  12 +-
 docs/intro/tutorial01.txt                        |   2 +-
 docs/intro/tutorial02.txt                        |  10 +-
 docs/ref/contrib/admin/index.txt                 |   4 +-
 docs/ref/contrib/gis/geoquerysets.txt            |   4 +-
 docs/ref/contrib/syndication.txt                 |   2 +-
 docs/ref/django-admin.txt                        |   6 +-
 docs/ref/models/fields.txt                       |   9 ++
 docs/ref/models/querysets.txt                    |  24 ++++
 docs/ref/request-response.txt                    |  13 ++-
 docs/ref/settings.txt                            |   5 +-
 docs/ref/templates/api.txt                       |  12 +-
 docs/ref/templates/builtins.txt                  |  22 ++--
 docs/releases/1.4.21.txt                         |  54 +++++++++
 docs/releases/1.6.txt                            |   3 +-
 docs/releases/1.7.7.txt                          |   2 +-
 docs/releases/1.7.8.txt                          |  15 +++
 docs/releases/1.7.9.txt                          |  65 +++++++++++
 docs/releases/index.txt                          |   3 +
 docs/topics/auth/customizing.txt                 |  19 ++--
 docs/topics/auth/default.txt                     |  17 ++-
 docs/topics/auth/passwords.txt                   |   8 ++
 docs/topics/cache.txt                            |   4 +-
 docs/topics/class-based-views/intro.txt          |   7 +-
 docs/topics/db/models.txt                        |   3 -
 docs/topics/db/queries.txt                       |  39 +++++--
 docs/topics/files.txt                            |  17 +++
 docs/topics/forms/formsets.txt                   |   4 +-
 docs/topics/forms/index.txt                      |  24 ++--
 docs/topics/forms/modelforms.txt                 |   9 +-
 docs/topics/http/middleware.txt                  |   1 +
 docs/topics/i18n/timezones.txt                   |   4 +-
 docs/topics/i18n/translation.txt                 | 139 +++++++++++++++++++++--
 docs/topics/install.txt                          |   2 +-
 docs/topics/logging.txt                          | 105 ++++++++++++-----
 docs/topics/testing/tools.txt                    |  24 ++--
 tests/apps/tests.py                              |   2 +-
 tests/migrations/test_operations.py              |  13 ++-
 tests/queries/models.py                          |  15 +++
 tests/queries/tests.py                           |  62 +++++++---
 tests/schema/models.py                           |   8 ++
 tests/schema/tests.py                            |  85 ++++++++++++--
 tests/test_utils/tests.py                        |   6 +
 tests/validators/tests.py                        |  15 ++-
 63 files changed, 873 insertions(+), 239 deletions(-)

diff --git a/Django.egg-info/PKG-INFO b/Django.egg-info/PKG-INFO
index fdd042d..cbffe51 100644
--- a/Django.egg-info/PKG-INFO
+++ b/Django.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: Django
-Version: 1.7.7
+Version: 1.7.9
 Summary: A high-level Python Web framework that encourages rapid development and clean, pragmatic design.
 Home-page: http://www.djangoproject.com/
 Author: Django Software Foundation
diff --git a/Django.egg-info/SOURCES.txt b/Django.egg-info/SOURCES.txt
index c5813cd..34213ff 100644
--- a/Django.egg-info/SOURCES.txt
+++ b/Django.egg-info/SOURCES.txt
@@ -3987,6 +3987,7 @@ docs/releases/1.4.18.txt
 docs/releases/1.4.19.txt
 docs/releases/1.4.2.txt
 docs/releases/1.4.20.txt
+docs/releases/1.4.21.txt
 docs/releases/1.4.3.txt
 docs/releases/1.4.4.txt
 docs/releases/1.4.5.txt
@@ -4027,6 +4028,8 @@ docs/releases/1.7.4.txt
 docs/releases/1.7.5.txt
 docs/releases/1.7.6.txt
 docs/releases/1.7.7.txt
+docs/releases/1.7.8.txt
+docs/releases/1.7.9.txt
 docs/releases/1.7.txt
 docs/releases/index.txt
 docs/releases/security.txt
diff --git a/PKG-INFO b/PKG-INFO
index fdd042d..cbffe51 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: Django
-Version: 1.7.7
+Version: 1.7.9
 Summary: A high-level Python Web framework that encourages rapid development and clean, pragmatic design.
 Home-page: http://www.djangoproject.com/
 Author: Django Software Foundation
diff --git a/django/__init__.py b/django/__init__.py
index e398988..8733754 100644
--- a/django/__init__.py
+++ b/django/__init__.py
@@ -1,4 +1,4 @@
-VERSION = (1, 7, 7, 'final', 0)
+VERSION = (1, 7, 9, 'final', 0)
 
 
 def get_version(*args, **kwargs):
diff --git a/django/apps/registry.py b/django/apps/registry.py
index fe53d96..b26354b 100644
--- a/django/apps/registry.py
+++ b/django/apps/registry.py
@@ -213,7 +213,7 @@ class Apps(object):
                 warnings.warn(
                     "Model '%s.%s' was already registered. "
                     "Reloading models is not advised as it can lead to inconsistencies, "
-                    "most notably with related models." % (model_name, app_label),
+                    "most notably with related models." % (app_label, model_name),
                     RuntimeWarning, stacklevel=2)
             else:
                 raise RuntimeError(
diff --git a/django/contrib/sessions/backends/cache.py b/django/contrib/sessions/backends/cache.py
index b1058b3..faeb106 100644
--- a/django/contrib/sessions/backends/cache.py
+++ b/django/contrib/sessions/backends/cache.py
@@ -27,7 +27,7 @@ class SessionStore(SessionBase):
             session_data = None
         if session_data is not None:
             return session_data
-        self.create()
+        self._session_key = None
         return {}
 
     def create(self):
@@ -49,6 +49,8 @@ class SessionStore(SessionBase):
             "It is likely that the cache is unavailable.")
 
     def save(self, must_create=False):
+        if self.session_key is None:
+            return self.create()
         if must_create:
             func = self._cache.add
         else:
@@ -60,7 +62,7 @@ class SessionStore(SessionBase):
             raise CreateError
 
     def exists(self, session_key):
-        return (KEY_PREFIX + session_key) in self._cache
+        return session_key and (KEY_PREFIX + session_key) in self._cache
 
     def delete(self, session_key=None):
         if session_key is None:
diff --git a/django/contrib/sessions/backends/cached_db.py b/django/contrib/sessions/backends/cached_db.py
index f5c14b0..5cc6f79 100644
--- a/django/contrib/sessions/backends/cached_db.py
+++ b/django/contrib/sessions/backends/cached_db.py
@@ -51,12 +51,12 @@ class SessionStore(DBStore):
                     logger = logging.getLogger('django.security.%s' %
                             e.__class__.__name__)
                     logger.warning(force_text(e))
-                self.create()
+                self._session_key = None
                 data = {}
         return data
 
     def exists(self, session_key):
-        if (KEY_PREFIX + session_key) in self._cache:
+        if session_key and (KEY_PREFIX + session_key) in self._cache:
             return True
         return super(SessionStore, self).exists(session_key)
 
diff --git a/django/contrib/sessions/backends/db.py b/django/contrib/sessions/backends/db.py
index a087061..3e6cdf9 100644
--- a/django/contrib/sessions/backends/db.py
+++ b/django/contrib/sessions/backends/db.py
@@ -26,7 +26,7 @@ class SessionStore(SessionBase):
                 logger = logging.getLogger('django.security.%s' %
                         e.__class__.__name__)
                 logger.warning(force_text(e))
-            self.create()
+            self._session_key = None
             return {}
 
     def exists(self, session_key):
@@ -43,7 +43,6 @@ class SessionStore(SessionBase):
                 # Key wasn't unique. Try again.
                 continue
             self.modified = True
-            self._session_cache = {}
             return
 
     def save(self, must_create=False):
@@ -53,6 +52,8 @@ class SessionStore(SessionBase):
         create a *new* entry (as opposed to possibly updating an existing
         entry).
         """
+        if self.session_key is None:
+            return self.create()
         obj = Session(
             session_key=self._get_or_create_session_key(),
             session_data=self.encode(self._get_session(no_load=must_create)),
diff --git a/django/contrib/sessions/backends/file.py b/django/contrib/sessions/backends/file.py
index 6569daf..f886bcd 100644
--- a/django/contrib/sessions/backends/file.py
+++ b/django/contrib/sessions/backends/file.py
@@ -96,7 +96,7 @@ class SessionStore(SessionBase):
                     self.delete()
                     self.create()
         except (IOError, SuspiciousOperation):
-            self.create()
+            self._session_key = None
         return session_data
 
     def create(self):
@@ -107,10 +107,11 @@ class SessionStore(SessionBase):
             except CreateError:
                 continue
             self.modified = True
-            self._session_cache = {}
             return
 
     def save(self, must_create=False):
+        if self.session_key is None:
+            return self.create()
         # Get the session data now, before we start messing
         # with the file it is stored within.
         session_data = self._get_session(no_load=must_create)
diff --git a/django/contrib/sessions/tests.py b/django/contrib/sessions/tests.py
index 8d63aaa..6e042c7 100644
--- a/django/contrib/sessions/tests.py
+++ b/django/contrib/sessions/tests.py
@@ -171,6 +171,11 @@ class SessionTestsMixin(object):
         self.assertNotEqual(self.session.session_key, prev_key)
         self.assertEqual(list(self.session.items()), prev_data)
 
+    def test_save_doesnt_clear_data(self):
+        self.session['a'] = 'b'
+        self.session.save()
+        self.assertEqual(self.session['a'], 'b')
+
     def test_invalid_key(self):
         # Submitting an invalid session key (either by guessing, or if the db has
         # removed the key) results in a new key being generated.
@@ -306,6 +311,21 @@ class SessionTestsMixin(object):
                 self.session.delete(old_session_key)
                 self.session.delete(new_session_key)
 
+    def test_session_load_does_not_create_record(self):
+        """
+        Loading an unknown session key does not create a session record.
+
+        Creating session records on load is a DOS vulnerability.
+        """
+        if self.backend is CookieSession:
+            raise unittest.SkipTest("Cookie backend doesn't have an external store to create records in.")
+        session = self.backend('someunknownkey')
+        session.load()
+
+        self.assertFalse(session.exists(session.session_key))
+        # provided unknown key was cycled, not reused
+        self.assertNotEqual(session.session_key, 'someunknownkey')
+
 
 class DatabaseSessionTests(SessionTestsMixin, TestCase):
 
diff --git a/django/core/validators.py b/django/core/validators.py
index 1e599ec..462e310 100644
--- a/django/core/validators.py
+++ b/django/core/validators.py
@@ -73,7 +73,7 @@ class URLValidator(RegexValidator):
         r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|'  # ...or ipv4
         r'\[?[A-F0-9]*:[A-F0-9:]+\]?)'  # ...or ipv6
         r'(?::\d+)?'  # optional port
-        r'(?:/?|[/?]\S+)$', re.IGNORECASE)
+        r'(?:/?|[/?]\S+)\Z', re.IGNORECASE)
     message = _('Enter a valid URL.')
     schemes = ['http', 'https', 'ftp', 'ftps']
 
@@ -107,12 +107,15 @@ class URLValidator(RegexValidator):
         else:
             url = value
 
+integer_validator = RegexValidator(
+    re.compile('^-?\d+\Z'),
+    message=_('Enter a valid integer.'),
+    code='invalid',
+)
+
 
 def validate_integer(value):
-    try:
-        int(value)
-    except (ValueError, TypeError):
-        raise ValidationError(_('Enter a valid integer.'), code='invalid')
+    return integer_validator(value)
 
 
 @deconstructible
@@ -120,15 +123,15 @@ class EmailValidator(object):
     message = _('Enter a valid email address.')
     code = 'invalid'
     user_regex = re.compile(
-        r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*$"  # dot-atom
-        r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"$)',  # quoted-string
+        r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*\Z"  # dot-atom
+        r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"\Z)',  # quoted-string
         re.IGNORECASE)
     domain_regex = re.compile(
-        r'(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}|[A-Z0-9-]{2,}(?<!-))$',
+        r'(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}|[A-Z0-9-]{2,}(?<!-))\Z',
         re.IGNORECASE)
     literal_regex = re.compile(
         # literal form, ipv4 or ipv6 address (SMTP 4.1.3)
-        r'\[([A-f0-9:\.]+)\]$',
+        r'\[([A-f0-9:\.]+)\]\Z',
         re.IGNORECASE)
     domain_whitelist = ['localhost']
 
@@ -181,10 +184,10 @@ class EmailValidator(object):
 
 validate_email = EmailValidator()
 
-slug_re = re.compile(r'^[-a-zA-Z0-9_]+$')
+slug_re = re.compile(r'^[-a-zA-Z0-9_]+\Z')
 validate_slug = RegexValidator(slug_re, _("Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."), 'invalid')
 
-ipv4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$')
+ipv4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z')
 validate_ipv4_address = RegexValidator(ipv4_re, _('Enter a valid IPv4 address.'), 'invalid')
 
 
@@ -225,7 +228,7 @@ def ip_address_validators(protocol, unpack_ipv4):
         raise ValueError("The protocol '%s' is unknown. Supported: %s"
                          % (protocol, list(ip_address_validator_map)))
 
-comma_separated_int_list_re = re.compile('^[\d,]+$')
+comma_separated_int_list_re = re.compile('^[\d,]+\Z')
 validate_comma_separated_integer_list = RegexValidator(comma_separated_int_list_re, _('Enter only digits separated by commas.'), 'invalid')
 
 
diff --git a/django/db/backends/mysql/schema.py b/django/db/backends/mysql/schema.py
index bce1a15..15286a6 100644
--- a/django/db/backends/mysql/schema.py
+++ b/django/db/backends/mysql/schema.py
@@ -48,3 +48,22 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
                 'table': self.quote_name(model._meta.db_table),
                 'column': self.quote_name(field.column),
             }, [effective_default])
+
+    def _set_field_new_type_null_status(self, field, new_type):
+        """
+        Keep the null property of the old field. If it has changed, it will be
+        handled separately.
+        """
+        if field.null:
+            new_type += " NULL"
+        else:
+            new_type += " NOT NULL"
+        return new_type
+
+    def _alter_column_type_sql(self, table, old_field, new_field, new_type):
+        new_type = self._set_field_new_type_null_status(old_field, new_type)
+        return super(DatabaseSchemaEditor, self)._alter_column_type_sql(table, old_field, new_field, new_type)
+
+    def _rename_field_sql(self, table, old_field, new_field, new_type):
+        new_type = self._set_field_new_type_null_status(old_field, new_type)
+        return super(DatabaseSchemaEditor, self)._rename_field_sql(table, old_field, new_field, new_type)
diff --git a/django/db/backends/postgresql_psycopg2/schema.py b/django/db/backends/postgresql_psycopg2/schema.py
index 7b479c2..6caf38d 100644
--- a/django/db/backends/postgresql_psycopg2/schema.py
+++ b/django/db/backends/postgresql_psycopg2/schema.py
@@ -34,11 +34,12 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
                         model, [field], suffix='_like', sql=self.sql_create_text_index))
         return output
 
-    def _alter_column_type_sql(self, table, column, type):
+    def _alter_column_type_sql(self, table, old_field, new_field, new_type):
         """
         Makes ALTER TYPE with SERIAL make sense.
         """
-        if type.lower() == "serial":
+        if new_type.lower() == "serial":
+            column = new_field.column
             sequence_name = "%s_%s_seq" % (table, column)
             return (
                 (
@@ -82,4 +83,6 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
                 ],
             )
         else:
-            return super(DatabaseSchemaEditor, self)._alter_column_type_sql(table, column, type)
+            return super(DatabaseSchemaEditor, self)._alter_column_type_sql(
+                table, old_field, new_field, new_type
+            )
diff --git a/django/db/backends/schema.py b/django/db/backends/schema.py
index 4a5637c..0d9ebf7 100644
--- a/django/db/backends/schema.py
+++ b/django/db/backends/schema.py
@@ -13,6 +13,14 @@ from django.utils import six
 logger = getLogger('django.db.backends.schema')
 
 
+def _related_objects(old_field, new_field):
+    # Returns (old_relation, new_relation) tuples.
+    return zip(
+        old_field.model._meta.get_all_related_objects(),
+        new_field.model._meta.get_all_related_objects()
+    )
+
+
 class BaseDatabaseSchemaEditor(object):
     """
     This class (and its subclasses) are responsible for emitting schema-changing
@@ -438,12 +446,17 @@ class BaseDatabaseSchemaEditor(object):
         old_type = old_db_params['type']
         new_db_params = new_field.db_parameters(connection=self.connection)
         new_type = new_db_params['type']
-        if (old_type is None and old_field.rel is None) or (new_type is None and new_field.rel is None):
-            raise ValueError("Cannot alter field %s into %s - they do not properly define db_type (are you using PostGIS 1.5 or badly-written custom fields?)" % (
-                old_field,
-                new_field,
-            ))
-        elif old_type is None and new_type is None and (old_field.rel.through and new_field.rel.through and old_field.rel.through._meta.auto_created and new_field.rel.through._meta.auto_created):
+        if ((old_type is None and old_field.rel is None) or
+                (new_type is None and new_field.rel is None)):
+            raise ValueError(
+                "Cannot alter field %s into %s - they do not properly define "
+                "db_type (are you using PostGIS 1.5 or badly-written custom "
+                "fields?)" % (old_field, new_field)
+            )
+        elif old_type is None and new_type is None and (
+                old_field.rel.through and new_field.rel.through and
+                old_field.rel.through._meta.auto_created and
+                new_field.rel.through._meta.auto_created):
             return self._alter_many_to_many(model, old_field, new_field, strict)
         elif old_type is None and new_type is None and (old_field.rel.through and new_field.rel.through and not old_field.rel.through._meta.auto_created and not new_field.rel.through._meta.auto_created):
             # Both sides have through models; this is a no-op.
@@ -487,10 +500,12 @@ class BaseDatabaseSchemaEditor(object):
         # Drop incoming FK constraints if we're a primary key and things are going
         # to change.
         if old_field.primary_key and new_field.primary_key and old_type != new_type:
-            for rel in new_field.model._meta.get_all_related_objects():
-                rel_fk_names = self._constraint_names(rel.model, [rel.field.column], foreign_key=True)
+            for _old_rel, new_rel in _related_objects(old_field, new_field):
+                rel_fk_names = self._constraint_names(
+                    new_rel.model, [new_rel.field.column], foreign_key=True
+                )
                 for fk_name in rel_fk_names:
-                    self.execute(self._delete_constraint_sql(self.sql_delete_fk, rel.model, fk_name))
+                    self.execute(self._delete_constraint_sql(self.sql_delete_fk, new_rel.model, fk_name))
         # Removed an index? (no strict check, as multiple indexes are possible)
         if (old_field.db_index and not new_field.db_index and
                 not old_field.unique and not
@@ -512,19 +527,16 @@ class BaseDatabaseSchemaEditor(object):
                 self.execute(self._delete_constraint_sql(self.sql_delete_check, model, constraint_name))
         # Have they renamed the column?
         if old_field.column != new_field.column:
-            self.execute(self.sql_rename_column % {
-                "table": self.quote_name(model._meta.db_table),
-                "old_column": self.quote_name(old_field.column),
-                "new_column": self.quote_name(new_field.column),
-                "type": new_type,
-            })
+            self.execute(self._rename_field_sql(model._meta.db_table, old_field, new_field, new_type))
         # Next, start accumulating actions to do
         actions = []
         null_actions = []
         post_actions = []
         # Type change?
         if old_type != new_type:
-            fragment, other_actions = self._alter_column_type_sql(model._meta.db_table, new_field.column, new_type)
+            fragment, other_actions = self._alter_column_type_sql(
+                model._meta.db_table, old_field, new_field, new_type
+            )
             actions.append(fragment)
             post_actions.extend(other_actions)
         # When changing a column NULL constraint to NOT NULL with a given
@@ -637,7 +649,7 @@ class BaseDatabaseSchemaEditor(object):
         # referring to us.
         rels_to_update = []
         if old_field.primary_key and new_field.primary_key and old_type != new_type:
-            rels_to_update.extend(new_field.model._meta.get_all_related_objects())
+            rels_to_update.extend(_related_objects(old_field, new_field))
         # Changed to become primary key?
         # Note that we don't detect unsetting of a PK, as we assume another field
         # will always come along and replace it.
@@ -660,20 +672,23 @@ class BaseDatabaseSchemaEditor(object):
                 }
             )
             # Update all referencing columns
-            rels_to_update.extend(new_field.model._meta.get_all_related_objects())
+            rels_to_update.extend(_related_objects(old_field, new_field))
         # Handle our type alters on the other end of rels from the PK stuff above
-        for rel in rels_to_update:
-            rel_db_params = rel.field.db_parameters(connection=self.connection)
+        for old_rel, new_rel in rels_to_update:
+            rel_db_params = new_rel.field.db_parameters(connection=self.connection)
             rel_type = rel_db_params['type']
+            fragment, other_actions = self._alter_column_type_sql(
+                new_rel.model._meta.db_table, old_rel.field, new_rel.field, rel_type
+            )
             self.execute(
                 self.sql_alter_column % {
-                    "table": self.quote_name(rel.model._meta.db_table),
-                    "changes": self.sql_alter_column_type % {
-                        "column": self.quote_name(rel.field.column),
-                        "type": rel_type,
-                    }
-                }
+                    "table": self.quote_name(new_rel.model._meta.db_table),
+                    "changes": fragment[0],
+                },
+                fragment[1],
             )
+            for sql, params in other_actions:
+                self.execute(sql, params)
         # Does it have a foreign key?
         if (new_field.rel and
                 (fks_dropped or not old_field.rel or not old_field.db_constraint) and
@@ -707,7 +722,7 @@ class BaseDatabaseSchemaEditor(object):
         if self.connection.features.connection_persists_old_columns:
             self.connection.close()
 
-    def _alter_column_type_sql(self, table, column, type):
+    def _alter_column_type_sql(self, table, old_field, new_field, new_type):
         """
         Hook to specialize column type alteration for different backends,
         for cases when a creation type is different to an alteration type
@@ -720,8 +735,8 @@ class BaseDatabaseSchemaEditor(object):
         return (
             (
                 self.sql_alter_column_type % {
-                    "column": self.quote_name(column),
-                    "type": type,
+                    "column": self.quote_name(new_field.column),
+                    "type": new_type,
                 },
                 [],
             ),
@@ -821,6 +836,14 @@ class BaseDatabaseSchemaEditor(object):
             output.append(self._create_index_sql(model, fields, suffix="_idx"))
         return output
 
+    def _rename_field_sql(self, table, old_field, new_field, new_type):
+        return self.sql_rename_column % {
+            "table": self.quote_name(table),
+            "old_column": self.quote_name(old_field.column),
+            "new_column": self.quote_name(new_field.column),
+            "type": new_type,
+        }
+
     def _create_fk_sql(self, model, field, suffix):
         from_table = model._meta.db_table
         from_column = field.column
diff --git a/django/db/backends/sqlite3/introspection.py b/django/db/backends/sqlite3/introspection.py
index f029715..529ef55 100644
--- a/django/db/backends/sqlite3/introspection.py
+++ b/django/db/backends/sqlite3/introspection.py
@@ -201,7 +201,10 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
         constraints = {}
         # Get the index info
         cursor.execute("PRAGMA index_list(%s)" % self.connection.ops.quote_name(table_name))
-        for number, index, unique in cursor.fetchall():
+        for row in cursor.fetchall():
+            # Sqlite3 3.8.9+ has 5 columns, however older versions only give 3
+            # columns. Discard last 2 columns if there.
+            number, index, unique = row[:3]
             # Get the index info for that index
             cursor.execute('PRAGMA index_info(%s)' % self.connection.ops.quote_name(index))
             for index_rank, column_rank, column in cursor.fetchall():
diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py
index 90ac90f..e938253 100644
--- a/django/db/models/sql/compiler.py
+++ b/django/db/models/sql/compiler.py
@@ -56,7 +56,8 @@ class SQLCompiler(object):
         if name in self.quote_cache:
             return self.quote_cache[name]
         if ((name in self.query.alias_map and name not in self.query.table_map) or
-                name in self.query.extra_select or name in self.query.external_aliases):
+                name in self.query.extra_select or (
+                    name in self.query.external_aliases and name not in self.query.table_map)):
             self.quote_cache[name] = name
             return name
         r = self.connection.ops.quote_name(name)
diff --git a/django/test/testcases.py b/django/test/testcases.py
index 61b206d..fff0506 100644
--- a/django/test/testcases.py
+++ b/django/test/testcases.py
@@ -558,8 +558,7 @@ class SimpleTestCase(unittest.TestCase):
             msg_prefix + "Template '%s' was used unexpectedly in rendering"
             " the response" % template_name)
 
-    def assertRaisesMessage(self, expected_exception, expected_message,
-                           callable_obj=None, *args, **kwargs):
+    def assertRaisesMessage(self, expected_exception, expected_message, *args, **kwargs):
         """
         Asserts that the message in a raised exception matches the passed
         value.
@@ -567,12 +566,17 @@ class SimpleTestCase(unittest.TestCase):
         Args:
             expected_exception: Exception class expected to be raised.
             expected_message: expected error message string value.
-            callable_obj: Function to be called.
-            args: Extra args.
+            args: Function to be called and extra positional args.
             kwargs: Extra kwargs.
         """
+        # callable_obj was a documented kwarg in older version of Django, but
+        # had to be removed due to a bad fix for http://bugs.python.org/issue24134
+        # inadvertently making its way into Python 2.7.10.
+        callable_obj = kwargs.pop('callable_obj', None)
+        if callable_obj:
+            args = (callable_obj,) + args
         return six.assertRaisesRegex(self, expected_exception,
-                re.escape(expected_message), callable_obj, *args, **kwargs)
+                re.escape(expected_message), *args, **kwargs)
 
     def assertFieldOutput(self, fieldclass, valid, invalid, field_args=None,
             field_kwargs=None, empty_value=''):
diff --git a/docs/howto/deployment/wsgi/apache-auth.txt b/docs/howto/deployment/wsgi/apache-auth.txt
index 9af3f23..428e24c 100644
--- a/docs/howto/deployment/wsgi/apache-auth.txt
+++ b/docs/howto/deployment/wsgi/apache-auth.txt
@@ -32,7 +32,7 @@ Authentication with mod_wsgi
 
     The use of ``WSGIApplicationGroup %{GLOBAL}`` in the configurations below
     presumes that your Apache instance is running only one Django application.
-    If you are running more than Django application, please refer to the
+    If you are running more than one Django application, please refer to the
     `Defining Application Groups`_ section of the mod_wsgi docs for more
     information about this setting.
 
diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt
index 252db52..40f003b 100644
--- a/docs/internals/deprecation.txt
+++ b/docs/internals/deprecation.txt
@@ -111,7 +111,7 @@ details on these changes.
 * ``django.db.backends.DatabaseValidation.validate_field`` will be removed in
   favor of the ``check_field`` method.
 
-* The ``check`` management command will be removed.
+* The ``validate`` management command will be removed.
 
 * ``django.utils.module_loading.import_by_path`` will be removed in favor of
   ``django.utils.module_loading.import_string``.
diff --git a/docs/internals/release-process.txt b/docs/internals/release-process.txt
index 180c3dc..bce7319 100644
--- a/docs/internals/release-process.txt
+++ b/docs/internals/release-process.txt
@@ -77,7 +77,8 @@ Supported versions
 ==================
 
 At any moment in time, Django's developer team will support a set of releases to
-varying levels:
+varying levels. See `the download page`_ for the current state of support for
+each version.
 
 * The current development master will get new features and bug fixes
   requiring major refactoring.
@@ -132,13 +133,10 @@ to be "Long-term support" (LTS) releases. LTS releases will get security and
 data loss fixes applied for a guaranteed period of time, typically 3+ years,
 regardless of the pace of releases afterwards.
 
-The follow releases have been designated for long-term support:
+See `the download page`_ for the releases that have been designated for
+long-term support.
 
-* Django 1.8, supported for at least 3 years after its release (scheduled for
-  April 2015).
-* Django 1.4, supported for 6 months after the release of Django 1.8. As
-  Django 1.8 is scheduled to be released around April 2015, support for 1.4
-  will end around October 2015.
+.. _the download page: https://www.djangoproject.com/download/
 
 .. _release-process:
 
diff --git a/docs/intro/tutorial01.txt b/docs/intro/tutorial01.txt
index 6f4a307..882586d 100644
--- a/docs/intro/tutorial01.txt
+++ b/docs/intro/tutorial01.txt
@@ -195,7 +195,7 @@ come with Django:
 
 These applications are included by default as a convenience for the common case.
 
-Some of these applications makes use of at least one database table, though,
+Some of these applications make use of at least one database table, though,
 so we need to create the tables in the database before we can use them. To do
 that, run the following command:
 
diff --git a/docs/intro/tutorial02.txt b/docs/intro/tutorial02.txt
index d66b8d6..69908bf 100644
--- a/docs/intro/tutorial02.txt
+++ b/docs/intro/tutorial02.txt
@@ -127,7 +127,7 @@ the admin index page:
    :alt: Django admin index page, now with polls displayed
 
 Click "Questions". Now you're at the "change list" page for questions. This page
-displays all the question in the database and lets you choose one to change it.
+displays all the questions in the database and lets you choose one to change it.
 There's the "What's up?" question we created in the first tutorial:
 
 .. image:: _images/admin04t.png
@@ -482,10 +482,10 @@ system.
 Customizing your *project's* templates
 --------------------------------------
 
-Create a ``templates`` directory in your project directory. Templates can
-live anywhere on your filesystem that Django can access. (Django runs as
-whatever user your server runs.) However, keeping your templates within the
-project is a good convention to follow.
+Create a ``templates`` directory in your project directory (the one that
+contains ``manage.py``). Templates can live anywhere on your filesystem that
+Django can access. (Django runs as whatever user your server runs.) However,
+keeping your templates within the project is a good convention to follow.
 
 Open your settings file (:file:`mysite/settings.py`, remember) and add a
 :setting:`TEMPLATE_DIRS` setting:
diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt
index d1585b9..68efb0d 100644
--- a/docs/ref/contrib/admin/index.txt
+++ b/docs/ref/contrib/admin/index.txt
@@ -1267,6 +1267,8 @@ templates used by the :class:`ModelAdmin` views:
         class ArticleAdmin(admin.ModelAdmin):
             def save_formset(self, request, form, formset, change):
                 instances = formset.save(commit=False)
+                for obj in formset.deleted_objects:
+                    obj.delete()
                 for instance in instances:
                     instance.user = request.user
                     instance.save()
@@ -1276,7 +1278,7 @@ templates used by the :class:`ModelAdmin` views:
 
 .. method:: ModelAdmin.get_ordering(request)
 
-    The ``get_ordering`` method takes a``request`` as parameter and
+    The ``get_ordering`` method takes a ``request`` as parameter and
     is expected to return a ``list`` or ``tuple`` for ordering similar
     to the :attr:`ordering` attribute. For example::
 
diff --git a/docs/ref/contrib/gis/geoquerysets.txt b/docs/ref/contrib/gis/geoquerysets.txt
index dd2dfe8..6d4b793 100644
--- a/docs/ref/contrib/gis/geoquerysets.txt
+++ b/docs/ref/contrib/gis/geoquerysets.txt
@@ -286,7 +286,7 @@ Example::
 
     # A tuple lookup parameter is used to specify the geometry and
     # the intersection pattern (the pattern here is for 'contains').
-    Zipcode.objects.filter(poly__relate(geom, 'T*T***FF*'))
+    Zipcode.objects.filter(poly__relate=(geom, 'T*T***FF*'))
 
 PostGIS SQL equivalent::
 
@@ -308,7 +308,7 @@ strings are case-insensitive.
 
 Example::
 
-    Zipcode.objects.filter(poly__relate(geom, 'anyinteract'))
+    Zipcode.objects.filter(poly__relate=(geom, 'anyinteract'))
 
 Oracle SQL equivalent::
 
diff --git a/docs/ref/contrib/syndication.txt b/docs/ref/contrib/syndication.txt
index 65b4582..5e3066d 100644
--- a/docs/ref/contrib/syndication.txt
+++ b/docs/ref/contrib/syndication.txt
@@ -226,7 +226,7 @@ method along with the request object.
 
 Here's the code for these beat-specific feeds::
 
-    from django.contrib.syndication.views import FeedDoesNotExist
+    from django.contrib.syndication.views import Feed
     from django.shortcuts import get_object_or_404
 
     class BeatFeed(Feed):
diff --git a/docs/ref/django-admin.txt b/docs/ref/django-admin.txt
index ee0b7b9..d7ae9a9 100644
--- a/docs/ref/django-admin.txt
+++ b/docs/ref/django-admin.txt
@@ -891,9 +891,9 @@ reduction.
     ``pyinotify`` support was added.
 
 When you start the server, and each time you change Python code while the
-server is running, the server will check your entire Django project for errors (see
-the :djadmin:`check` command). If any errors are found, they will be printed
-to standard output, but it won't stop the server.
+server is running, the system check framework will check your entire Django
+project for some common errors (see the :djadmin:`check` command). If any
+errors are found, they will be printed to standard output.
 
 You can run as many servers as you want, as long as they're on separate ports.
 Just execute ``django-admin.py runserver`` more than once.
diff --git a/docs/ref/models/fields.txt b/docs/ref/models/fields.txt
index 9510025..4b33c9c 100644
--- a/docs/ref/models/fields.txt
+++ b/docs/ref/models/fields.txt
@@ -501,6 +501,15 @@ message key.
     ``True`` will cause the field to have ``editable=False`` and ``blank=True``
     set.
 
+.. note::
+    The ``auto_now`` and ``auto_now_add`` options will always use the date in
+    the :ref:`default timezone <default-current-time-zone>` at the moment of
+    creation or update. If you need something different, you may want to
+    consider simply using your own callable default or overriding ``save()``
+    instead of using ``auto_now`` or ``auto_now_add``; or using a
+    ``DateTimeField`` instead of a ``DateField`` and deciding how to handle the
+    conversion from datetime to date at display time.
+
 ``DateTimeField``
 -----------------
 
diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt
index 4946f77..07138da 100644
--- a/docs/ref/models/querysets.txt
+++ b/docs/ref/models/querysets.txt
@@ -1346,6 +1346,30 @@ one, doing so will result in an error.
     reader, is slightly faster and consumes a little less memory in the Python
     process.
 
+    For example, both of these models use the same underlying database table::
+
+        class CommonlyUsedModel(models.Model):
+            f1 = models.CharField(max_length=10)
+
+            class Meta:
+                managed = False
+                db_table = 'app_largetable'
+
+        class ManagedModel(models.Model):
+            f1 = models.CharField(max_length=10)
+            f2 = models.CharField(max_length=10)
+
+            class Meta:
+                db_table = 'app_largetable'
+
+        # Two equivalent QuerySets:
+        CommonlyUsedModel.objects.all()
+        ManagedModel.objects.all().defer('f2')
+
+    If many fields need to be duplicated in the unmanaged model, it may be best
+    to create an abstract model with the shared fields and then have the
+    unmanaged and managed models inherit from the abstract model.
+
 .. note::
 
     When calling :meth:`~django.db.models.Model.save()` for instances with
diff --git a/docs/ref/request-response.txt b/docs/ref/request-response.txt
index d67aae6..0384448 100644
--- a/docs/ref/request-response.txt
+++ b/docs/ref/request-response.txt
@@ -51,7 +51,7 @@ All attributes should be considered read-only, unless stated otherwise below.
 .. attribute:: HttpRequest.path
 
     A string representing the full path to the requested page, not including
-    the domain.
+    the scheme or domain.
 
     Example: ``"/music/bands/the_beatles/"``
 
@@ -147,8 +147,9 @@ All attributes should be considered read-only, unless stated otherwise below.
     Available headers depend on the client and server, but here are some
     examples:
 
-    * ``CONTENT_LENGTH`` -- the length of the request body (as a string).
-    * ``CONTENT_TYPE`` -- the MIME type of the request body.
+    * ``CONTENT_LENGTH`` -- The length of the request body (as a string).
+    * ``CONTENT_TYPE`` -- The MIME type of the request body.
+    * ``HTTP_ACCEPT`` -- Acceptable content types for the response.
     * ``HTTP_ACCEPT_ENCODING`` -- Acceptable encodings for the response.
     * ``HTTP_ACCEPT_LANGUAGE`` -- Acceptable languages for the response.
     * ``HTTP_HOST`` -- The HTTP Host header sent by the client.
@@ -330,7 +331,7 @@ Methods
     Methods implementing a file-like interface for reading from an
     HttpRequest instance. This makes it possible to consume an incoming
     request in a streaming fashion. A common use-case would be to process a
-    big XML payload with iterative parser without constructing a whole
+    big XML payload with an iterative parser without constructing a whole
     XML tree in memory.
 
     Given this standard interface, an HttpRequest instance can be
@@ -465,7 +466,7 @@ In addition, ``QueryDict`` has the following methods:
     Returns the data with the requested key, as a Python list. Returns an
     empty list if the key doesn't exist and no default value was provided.
     It's guaranteed to return a list of some sort unless the default value
-    was no list.
+    provided is not a list.
 
 .. method:: QueryDict.setlist(key, list_)
 
@@ -706,7 +707,7 @@ Methods
       header. It is not part of the :rfc:`2109` standard for cookies,
       and it isn't honored consistently by all browsers. However,
       when it is honored, it can be a useful way to mitigate the
-      risk of client side script accessing the protected cookie
+      risk of a client-side script from accessing the protected cookie
       data.
 
     .. _HTTPOnly: https://www.owasp.org/index.php/HTTPOnly
diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt
index 171e442..17d0830 100644
--- a/docs/ref/settings.txt
+++ b/docs/ref/settings.txt
@@ -1541,8 +1541,9 @@ It serves two purposes:
 
 * If the locale middleware isn't in use, it decides which translation is served
   to all users.
-* If the locale middleware is active, it provides the fallback translation when
-  no translation exist for a given literal to the user's preferred language.
+* If the locale middleware is active, it provides a fallback language in case
+  the user's preferred language can't be determined or is not supported by the
+  Web site.
 
 See :ref:`how-django-discovers-language-preference` for more details.
 
diff --git a/docs/ref/templates/api.txt b/docs/ref/templates/api.txt
index a76d325..69f7fca 100644
--- a/docs/ref/templates/api.txt
+++ b/docs/ref/templates/api.txt
@@ -317,7 +317,9 @@ dictionary syntax::
     'bar'
     >>> del c['foo']
     >>> c['foo']
-    ''
+    Traceback (most recent call last):
+    ...
+    KeyError: 'foo'
     >>> c['newvariable'] = 'hello'
     >>> c['newvariable']
     'hello'
@@ -362,8 +364,8 @@ is called.
     >>> c = Context()
     >>> c['foo'] = 'first level'
     >>> with c.push():
-    >>>     c['foo'] = 'second level'
-    >>>     c['foo']
+    ...     c['foo'] = 'second level'
+    ...     c['foo']
     'second level'
     >>> c['foo']
     'first level'
@@ -374,12 +376,12 @@ used to build the new context level.
     >>> c = Context()
     >>> c['foo'] = 'first level'
     >>> with c.push(foo='second level'):
-    >>>     c['foo']
+    ...     c['foo']
     'second level'
     >>> c['foo']
     'first level'
 
-.. method:: update(other_dict)
+.. method:: Context.update(other_dict)
 
 In addition to ``push()`` and ``pop()``, the ``Context``
 object also defines an ``update()`` method. This works like ``push()``
diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt
index 823e958..c5cc794 100644
--- a/docs/ref/templates/builtins.txt
+++ b/docs/ref/templates/builtins.txt
@@ -710,9 +710,11 @@ the variable ``template_name``::
     your context.
 
 An included template is rendered within the context of the template that
-includes it. This example produces the output ``"Hello, John"``:
+includes it. This example produces the output ``"Hello, John!"``:
+
+* Context: variable ``person`` is set to ``"John"`` and variable ``greeting``
+  is set to ``"Hello"``.
 
-* Context: variable ``person`` is set to ``"john"``.
 * Template::
 
     {% include "name_snippet.html" %}
@@ -2382,7 +2384,7 @@ rel="nofollow">www.djangoproject.com</a>"``.
 In addition to web links, ``urlize`` also converts email addresses into
 ``mailto:`` links. If ``value`` is
 ``"Send questions to foo at example.com"``, the output will be
-``"Send questions to <a href="mailto:foo at example.com">foo at example</a>"``.
+``"Send questions to <a href="mailto:foo at example.com">foo at example.com</a>"``.
 
 The ``urlize`` filter also takes an optional parameter ``autoescape``. If
 ``autoescape`` is ``True``, the link text and URLs will be escaped using
... 1450 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-django.git



More information about the Python-modules-commits mailing list