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

Raphaël Hertzog hertzog at moszumanska.debian.org
Mon Mar 23 20:13:57 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 7a41006b464c23d415485ebd4284c1957e5e47e2
Author: Raphaël Hertzog <hertzog at debian.org>
Date:   Mon Mar 23 20:39:53 2015 +0100

    Imported Upstream version 1.7.7
---
 AUTHORS                                           |  1 +
 Django.egg-info/PKG-INFO                          |  2 +-
 Django.egg-info/SOURCES.txt                       |  3 +
 PKG-INFO                                          |  2 +-
 django/__init__.py                                |  2 +-
 django/core/management/commands/makemigrations.py | 19 ++++--
 django/db/migrations/operations/models.py         |  4 ++
 django/utils/html.py                              |  6 +-
 django/utils/http.py                              | 10 ++-
 docs/howto/custom-template-tags.txt               |  2 +-
 docs/howto/deployment/wsgi/modwsgi.txt            |  8 +++
 docs/intro/tutorial05.txt                         |  8 +--
 docs/ref/applications.txt                         |  2 +-
 docs/ref/contrib/admin/actions.txt                |  2 +-
 docs/ref/contrib/gis/gdal.txt                     | 13 ++--
 docs/ref/contrib/staticfiles.txt                  |  6 ++
 docs/ref/databases.txt                            |  2 +-
 docs/ref/files/uploads.txt                        |  4 +-
 docs/ref/models/fields.txt                        | 16 ++++-
 docs/ref/models/querysets.txt                     |  5 ++
 docs/ref/schema-editor.txt                        |  3 -
 docs/ref/templates/api.txt                        |  5 ++
 docs/releases/1.4.20.txt                          | 26 ++++++++
 docs/releases/1.6.11.txt                          | 43 +++++++++++++
 docs/releases/1.7.7.txt                           | 54 ++++++++++++++++
 docs/releases/1.7.txt                             | 18 +++++-
 docs/releases/index.txt                           |  3 +
 docs/topics/auth/default.txt                      |  5 ++
 docs/topics/db/sql.txt                            |  2 +-
 docs/topics/forms/modelforms.txt                  | 77 ++++++++++++-----------
 docs/topics/migrations.txt                        | 69 +++++---------------
 tests/migrations/test_commands.py                 | 45 +++++++++++++
 tests/migrations/test_operations.py               | 35 +++++++++++
 tests/utils_tests/test_html.py                    |  3 +
 tests/utils_tests/test_http.py                    |  4 +-
 35 files changed, 387 insertions(+), 122 deletions(-)

diff --git a/AUTHORS b/AUTHORS
index 37fd21c..cf5935c 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -62,6 +62,7 @@ answer newbie questions, and generally made Django that much better:
     Roberto Aguilar <roberto at baremetal.io>
     ajs <adi at sieker.info>
     Akis Kesoglou <akiskesoglou at gmail.com>
+    Aksel Ethem <aksel.ethem at gmail.com>
     alang at bright-green.com
     A S Alam <aalam at users.sf.net>
     Andi Albrecht <albrecht.andi at gmail.com>
diff --git a/Django.egg-info/PKG-INFO b/Django.egg-info/PKG-INFO
index 21d6b3f..fdd042d 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.6
+Version: 1.7.7
 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 f67cbb5..c5813cd 100644
--- a/Django.egg-info/SOURCES.txt
+++ b/Django.egg-info/SOURCES.txt
@@ -3986,6 +3986,7 @@ docs/releases/1.4.17.txt
 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.3.txt
 docs/releases/1.4.4.txt
 docs/releases/1.4.5.txt
@@ -4009,6 +4010,7 @@ docs/releases/1.5.9.txt
 docs/releases/1.5.txt
 docs/releases/1.6.1.txt
 docs/releases/1.6.10.txt
+docs/releases/1.6.11.txt
 docs/releases/1.6.2.txt
 docs/releases/1.6.3.txt
 docs/releases/1.6.4.txt
@@ -4024,6 +4026,7 @@ docs/releases/1.7.3.txt
 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.txt
 docs/releases/index.txt
 docs/releases/security.txt
diff --git a/PKG-INFO b/PKG-INFO
index 21d6b3f..fdd042d 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: Django
-Version: 1.7.6
+Version: 1.7.7
 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 77b09d9..e398988 100644
--- a/django/__init__.py
+++ b/django/__init__.py
@@ -1,4 +1,4 @@
-VERSION = (1, 7, 6, 'final', 0)
+VERSION = (1, 7, 7, 'final', 0)
 
 
 def get_version(*args, **kwargs):
diff --git a/django/core/management/commands/makemigrations.py b/django/core/management/commands/makemigrations.py
index 7ca8911..0d479a4 100644
--- a/django/core/management/commands/makemigrations.py
+++ b/django/core/management/commands/makemigrations.py
@@ -219,7 +219,18 @@ class Command(BaseCommand):
                 })
                 new_migration = subclass("%04i_merge" % (biggest_number + 1), app_label)
                 writer = MigrationWriter(new_migration)
-                with open(writer.path, "wb") as fh:
-                    fh.write(writer.as_string())
-                if self.verbosity > 0:
-                    self.stdout.write("\nCreated new merge migration %s" % writer.path)
+
+                if not self.dry_run:
+                    # Write the merge migrations file to the disk
+                    with open(writer.path, "wb") as fh:
+                        fh.write(writer.as_string())
+                    if self.verbosity > 0:
+                        self.stdout.write("\nCreated new merge migration %s" % writer.path)
+                elif self.verbosity == 3:
+                    # Alternatively, makemigrations --merge --dry-run --verbosity 3
+                    # will output the merge migrations to stdout rather than saving
+                    # the file to the disk.
+                    self.stdout.write(self.style.MIGRATE_HEADING(
+                        "Full merge migrations file '%s':" % writer.filename) + "\n"
+                    )
+                    self.stdout.write("%s\n" % writer.as_string())
diff --git a/django/db/migrations/operations/models.py b/django/db/migrations/operations/models.py
index 3d92b68..190d117 100644
--- a/django/db/migrations/operations/models.py
+++ b/django/db/migrations/operations/models.py
@@ -122,6 +122,10 @@ class RenameModel(Operation):
         del state.models[app_label, self.old_name.lower()]
         # Repoint the FKs and M2Ms pointing to us
         for related_object in (related_objects + related_m2m_objects):
+            if related_object.field.rel.to is not model:
+                # The model being renamed does not participate in this relation
+                # directly. Rather, a superclass does.
+                continue
             # Use the new related key for self referential related objects.
             if related_object.model == model:
                 related_key = (app_label, self.new_name.lower())
diff --git a/django/utils/html.py b/django/utils/html.py
index b6b4e1c..813d6b0 100644
--- a/django/utils/html.py
+++ b/django/utils/html.py
@@ -173,8 +173,10 @@ def strip_tags(value):
     # is redundant, but helps to reduce number of executions of _strip_once.
     while '<' in value and '>' in value:
         new_value = _strip_once(value)
-        if new_value == value:
-            # _strip_once was not able to detect more tags
+        if len(new_value) >= len(value):
+            # _strip_once was not able to detect more tags or length increased
+            # due to http://bugs.python.org/issue20288
+            # (affects Python 2 < 2.7.7 and Python 3 < 3.3.5)
             break
         value = new_value
     return value
diff --git a/django/utils/http.py b/django/utils/http.py
index 6aa5cd3..ef88f65 100644
--- a/django/utils/http.py
+++ b/django/utils/http.py
@@ -5,7 +5,7 @@ import calendar
 import datetime
 import re
 import sys
-
+import unicodedata
 from binascii import Error as BinasciiError
 from email.utils import formatdate
 
@@ -270,9 +270,10 @@ def is_safe_url(url, host=None):
 
     Always returns ``False`` on an empty url.
     """
+    if url is not None:
+        url = url.strip()
     if not url:
         return False
-    url = url.strip()
     # Chrome treats \ completely as /
     url = url.replace('\\', '/')
     # Chrome considers any URL with more than two slashes to be absolute, but
@@ -286,5 +287,10 @@ def is_safe_url(url, host=None):
     # allow this syntax.
     if not url_info.netloc and url_info.scheme:
         return False
+    # Forbid URLs that start with control characters. Some browsers (like
+    # Chrome) ignore quite a few control characters at the start of a
+    # URL and might consider the URL as scheme relative.
+    if unicodedata.category(url[0])[0] == 'C':
+        return False
     return ((not url_info.netloc or url_info.netloc == host) and
             (not url_info.scheme or url_info.scheme in ['http', 'https']))
diff --git a/docs/howto/custom-template-tags.txt b/docs/howto/custom-template-tags.txt
index 00bf7b1..77fe7ae 100644
--- a/docs/howto/custom-template-tags.txt
+++ b/docs/howto/custom-template-tags.txt
@@ -584,7 +584,7 @@ it's rendered:
 .. code-block:: html+django
 
     {% for o in some_list %}
-        <tr class="{% cycle 'row1' 'row2' %}>
+        <tr class="{% cycle 'row1' 'row2' %}">
             ...
         </tr>
     {% endfor %}
diff --git a/docs/howto/deployment/wsgi/modwsgi.txt b/docs/howto/deployment/wsgi/modwsgi.txt
index d994ef1..60fe596 100644
--- a/docs/howto/deployment/wsgi/modwsgi.txt
+++ b/docs/howto/deployment/wsgi/modwsgi.txt
@@ -112,6 +112,14 @@ use ``WSGIPythonPath``; instead you should use the ``python-path`` option to
     WSGIDaemonProcess example.com python-path=/path/to/mysite.com:/path/to/venv/lib/python2.7/site-packages
     WSGIProcessGroup example.com
 
+If you want to serve your project in a subdirectory
+(``http://example.com/mysite`` in this example), you can add ``WSGIScriptAlias``
+to the configuration above:
+
+.. code-block:: apache
+
+    WSGIScriptAlias /mysite /path/to/mysite.com/mysite/wsgi.py process-group=example.com
+
 See the official mod_wsgi documentation for `details on setting up daemon
 mode`_.
 
diff --git a/docs/intro/tutorial05.txt b/docs/intro/tutorial05.txt
index 545a84a..5b62a7f 100644
--- a/docs/intro/tutorial05.txt
+++ b/docs/intro/tutorial05.txt
@@ -177,7 +177,7 @@ Put the following in the ``tests.py`` file in the ``polls`` application:
         def test_was_published_recently_with_future_question(self):
             """
             was_published_recently() should return False for questions whose
-            pub_date is in the future
+            pub_date is in the future.
             """
             time = timezone.now() + datetime.timedelta(days=30)
             future_question = Question(pub_date=time)
@@ -282,7 +282,7 @@ more comprehensively:
     def test_was_published_recently_with_old_question(self):
         """
         was_published_recently() should return False for questions whose
-        pub_date is older than 1 day
+        pub_date is older than 1 day.
         """
         time = timezone.now() - datetime.timedelta(days=30)
         old_question = Question(pub_date=time)
@@ -291,7 +291,7 @@ more comprehensively:
     def test_was_published_recently_with_recent_question(self):
         """
         was_published_recently() should return True for questions whose
-        pub_date is within the last day
+        pub_date is within the last day.
         """
         time = timezone.now() - datetime.timedelta(hours=1)
         recent_question = Question(pub_date=time)
@@ -483,7 +483,7 @@ class:
         def test_index_view_with_a_past_question(self):
             """
             Questions with a pub_date in the past should be displayed on the
-            index page
+            index page.
             """
             create_question(question_text="Past question.", days=-30)
             response = self.client.get(reverse('polls:index'))
diff --git a/docs/ref/applications.txt b/docs/ref/applications.txt
index ab52e8b..1b790ee 100644
--- a/docs/ref/applications.txt
+++ b/docs/ref/applications.txt
@@ -243,7 +243,7 @@ Methods
         In the usual initialization process, the ``ready`` method is only called
         once by Django. But in some corner cases, particularly in tests which
         are fiddling with installed applications, ``ready`` might be called more
-        than once. In that case, either write idempotents methods, or put a flag
+        than once. In that case, either write idempotent methods, or put a flag
         on your ``AppConfig`` classes to prevent re-running code which should
         be executed exactly one time.
 
diff --git a/docs/ref/contrib/admin/actions.txt b/docs/ref/contrib/admin/actions.txt
index 5757e2e..b3d9f0e 100644
--- a/docs/ref/contrib/admin/actions.txt
+++ b/docs/ref/contrib/admin/actions.txt
@@ -70,7 +70,7 @@ Writing action functions
 ------------------------
 
 First, we'll need to write a function that gets called when the action is
-trigged from the admin. Action functions are just regular functions that take
+triggered from the admin. Action functions are just regular functions that take
 three arguments:
 
 * The current :class:`ModelAdmin`
diff --git a/docs/ref/contrib/gis/gdal.txt b/docs/ref/contrib/gis/gdal.txt
index 009cc0b..852f431 100644
--- a/docs/ref/contrib/gis/gdal.txt
+++ b/docs/ref/contrib/gis/gdal.txt
@@ -8,7 +8,7 @@ GDAL API
    :synopsis: GeoDjango's high-level interface to the GDAL library.
 
 `GDAL`__ stands for **Geospatial Data Abstraction Library**,
-and is a veritable "swiss army knife" of GIS data functionality.  A subset
+and is a veritable "Swiss army knife" of GIS data functionality.  A subset
 of GDAL is the `OGR`__ Simple Features Library, which specializes
 in reading and writing vector geographic data in a variety of standard
 formats.
@@ -61,10 +61,10 @@ points, polygons, etc.), as well as the names and types of any
 additional fields (:class:`Field`) of data that may be associated with
 each feature in that layer.
 
-.. class:: DataSource(ds_input)
+.. class:: DataSource(ds_input, [encoding='utf-8'])
 
-   The constructor for ``DataSource`` just a single parameter: the path of
-   the file you want to read.  However, OGR
+   The constructor for ``DataSource`` only requires one parameter: the path of
+   the file you want to read. However, OGR
    also supports a variety of more complex data sources, including
    databases, that may be accessed by passing a special name string instead
    of a path.  For more information, see the `OGR Vector Formats`__
@@ -72,6 +72,11 @@ each feature in that layer.
    instance gives the OGR name of the underlying data source that it is
    using.
 
+   The optional ``encoding`` parameter allows you to
+   specify a non-standard encoding of the strings in the source. This is
+   typically useful when you obtain ``DjangoUnicodeDecodeError`` exceptions
+   while reading field values.
+
    Once you've created your ``DataSource``, you can find out how many
    layers of data it contains by accessing the :attr:`layer_count` property,
    or (equivalently) by using the ``len()`` function.  For information on
diff --git a/docs/ref/contrib/staticfiles.txt b/docs/ref/contrib/staticfiles.txt
index 739e974..6c17515 100644
--- a/docs/ref/contrib/staticfiles.txt
+++ b/docs/ref/contrib/staticfiles.txt
@@ -298,6 +298,12 @@ hashed names for all processed files in a file called ``staticfiles.json``.
 This happens once when you run the :djadmin:`collectstatic` management
 command.
 
+Due to the requirement of running :djadmin:`collectstatic`, this storage
+typically shouldn't be used when running tests as ``collectstatic`` isn't run
+as part of the normal test setup. During testing, ensure that the
+:setting:`STATICFILES_STORAGE` setting is set to something else like
+``'django.contrib.staticfiles.storage.StaticFilesStorage'`` (the default).
+
 .. method:: storage.ManifestStaticFilesStorage.file_hash(name, content=None)
 
 The method that is used when creating the hashed name of a file.
diff --git a/docs/ref/databases.txt b/docs/ref/databases.txt
index 29526a3..470774c 100644
--- a/docs/ref/databases.txt
+++ b/docs/ref/databases.txt
@@ -637,7 +637,7 @@ If you're getting this error, you can solve it by:
   transactions are short-lived.
 
 * Increase the default timeout value by setting the ``timeout`` database
-  option option::
+  option::
 
       'OPTIONS': {
           # ...
diff --git a/docs/ref/files/uploads.txt b/docs/ref/files/uploads.txt
index 1b9103b..96e3dd0 100644
--- a/docs/ref/files/uploads.txt
+++ b/docs/ref/files/uploads.txt
@@ -106,8 +106,8 @@ Subclasses of ``UploadedFile`` include:
     A file uploaded into memory (i.e. stream-to-memory). This class is used
     by the :class:`~django.core.files.uploadhandler.MemoryFileUploadHandler`.
 
-Built-in upload handers
-=======================
+Built-in upload handlers
+========================
 
 .. module:: django.core.files.uploadhandler
    :synopsis: Django's handlers for file uploads.
diff --git a/docs/ref/models/fields.txt b/docs/ref/models/fields.txt
index 73256ac..9510025 100644
--- a/docs/ref/models/fields.txt
+++ b/docs/ref/models/fields.txt
@@ -1380,7 +1380,10 @@ that control how the relationship functions.
 
     If you don't specify an explicit ``through`` model, there is still an
     implicit ``through`` model class you can use to directly access the table
-    created to hold the association. It has three fields:
+    created to hold the association. It has three fields to link the models.
+
+    If the source and target models differ, the following fields are
+    generated:
 
     * ``id``: the primary key of the relation.
     * ``<containing_model>_id``: the ``id`` of the model that declares the
@@ -1388,6 +1391,15 @@ that control how the relationship functions.
     * ``<other_model>_id``: the ``id`` of the model that the
       ``ManyToManyField`` points to.
 
+    If the ``ManyToManyField`` points from and to the same model, the following 
+    fields are generated:
+
+    * ``id``: the primary key of the relation.
+    * ``from_<model>_id``: the ``id`` of the instance which points at the
+      model (i.e. the source instance).
+    * ``to_<model>_id``: the ``id`` of the instance to which the relationship
+      points (i.e. the target model instance).
+
     This class can be used to query associated records for a given model
     instance like a normal model.
 
@@ -1577,7 +1589,7 @@ Field API reference
 
     All of Django's built-in fields, such as :class:`CharField`, are particular
     implementations of ``Field``. If you need a custom field, you can either
-    subclass any of the built-in fields or write a ``Field``` from scratch. In
+    subclass any of the built-in fields or write a ``Field`` from scratch. In
     either case, see :doc:`/howto/custom-model-fields`.
 
     .. attribute:: description
diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt
index 6124024..4946f77 100644
--- a/docs/ref/models/querysets.txt
+++ b/docs/ref/models/querysets.txt
@@ -348,6 +348,11 @@ You can tell if a query is ordered or not by checking the
 :attr:`.QuerySet.ordered` attribute, which will be ``True`` if the
 ``QuerySet`` has been ordered in any way.
 
+Each ``order_by()`` call will clear any previous ordering. For example, this
+query will be ordered by ``pub_date`` and not ``headline``::
+
+    Entry.objects.order_by('headline').order_by('pub_date')
+
 .. warning::
 
     Ordering is not a free operation. Each field you add to the ordering
diff --git a/docs/ref/schema-editor.txt b/docs/ref/schema-editor.txt
index 94456d0..0d181ef 100644
--- a/docs/ref/schema-editor.txt
+++ b/docs/ref/schema-editor.txt
@@ -163,6 +163,3 @@ connection
 A connection object to the database. A useful attribute of the connection is
 ``alias`` which can be used to determine the name of the database being
 accessed.
-
-This is useful when doing data migrations for :ref:`migrations with multiple
-databases <data-migrations-and-multiple-databases>`.
diff --git a/docs/ref/templates/api.txt b/docs/ref/templates/api.txt
index 9e5964c..a76d325 100644
--- a/docs/ref/templates/api.txt
+++ b/docs/ref/templates/api.txt
@@ -322,6 +322,11 @@ dictionary syntax::
     >>> c['newvariable']
     'hello'
 
+.. method:: Context.get(key, otherwise=None)
+
+    Returns the value for ``key`` if ``key`` is in the context, else returns
+    ``otherwise``.
+
 .. method:: Context.pop()
 .. method:: Context.push()
 .. exception:: ContextPopException
diff --git a/docs/releases/1.4.20.txt b/docs/releases/1.4.20.txt
new file mode 100644
index 0000000..f2ca5ac
--- /dev/null
+++ b/docs/releases/1.4.20.txt
@@ -0,0 +1,26 @@
+===========================
+Django 1.4.20 release notes
+===========================
+
+*March 18, 2015*
+
+Django 1.4.20 fixes one security issue in 1.4.19.
+
+Mitigated possible XSS attack via user-supplied redirect URLs
+=============================================================
+
+Django relies on user input in some cases (e.g.
+:func:`django.contrib.auth.views.login` and :doc:`i18n </topics/i18n/index>`)
+to redirect the user to an "on success" URL. The security checks for these
+redirects (namely ``django.utils.http.is_safe_url()``) accepted URLs with
+leading control characters and so considered URLs like ``\x08javascript:...``
+safe. This issue doesn't affect Django currently, since we only put this URL
+into the ``Location`` response header and browsers seem to ignore JavaScript
+there. Browsers we tested also treat URLs prefixed with control characters such
+as ``%08//example.com`` as relative paths so redirection to an unsafe target
+isn't a problem either.
+
+However, if a developer relies on ``is_safe_url()`` to
+provide safe redirect targets and puts such a URL into a link, they could
+suffer from an XSS attack as some browsers such as Google Chrome ignore control
+characters at the start of a URL in an anchor ``href``.
diff --git a/docs/releases/1.6.11.txt b/docs/releases/1.6.11.txt
new file mode 100644
index 0000000..f1063fc
--- /dev/null
+++ b/docs/releases/1.6.11.txt
@@ -0,0 +1,43 @@
+===========================
+Django 1.6.11 release notes
+===========================
+
+*March 18, 2015*
+
+Django 1.6.11 fixes two security issues in 1.6.10.
+
+Denial-of-service possibility with ``strip_tags()``
+===================================================
+
+Last year :func:`~django.utils.html.strip_tags`  was changed to work
+iteratively. The problem is that the size of the input it's processing can
+increase on each iteration which results in an infinite loop in
+``strip_tags()``. This issue only affects versions of Python that haven't
+received  `a bugfix in HTMLParser <http://bugs.python.org/issue20288>`_; namely
+Python < 2.7.7 and 3.3.5. Some operating system vendors have also backported
+the fix for the Python bug into their packages of earlier versions.
+
+To remedy this issue, ``strip_tags()`` will now return the original input if
+it detects the length of the string it's processing increases. Remember that
+absolutely NO guarantee is provided about the results of ``strip_tags()`` being
+HTML safe. So NEVER mark safe the result of a ``strip_tags()`` call without
+escaping it first, for example with :func:`~django.utils.html.escape`.
+
+Mitigated possible XSS attack via user-supplied redirect URLs
+=============================================================
+
+Django relies on user input in some cases (e.g.
+:func:`django.contrib.auth.views.login` and :doc:`i18n </topics/i18n/index>`)
+to redirect the user to an "on success" URL. The security checks for these
+redirects (namely ``django.utils.http.is_safe_url()``) accepted URLs with
+leading control characters and so considered URLs like ``\x08javascript:...``
+safe. This issue doesn't affect Django currently, since we only put this URL
+into the ``Location`` response header and browsers seem to ignore JavaScript
+there. Browsers we tested also treat URLs prefixed with control characters such
+as ``%08//example.com`` as relative paths so redirection to an unsafe target
+isn't a problem either.
+
+However, if a developer relies on ``is_safe_url()`` to
+provide safe redirect targets and puts such a URL into a link, they could
+suffer from an XSS attack as some browsers such as Google Chrome ignore control
+characters at the start of a URL in an anchor ``href``.
diff --git a/docs/releases/1.7.7.txt b/docs/releases/1.7.7.txt
new file mode 100644
index 0000000..c458368
--- /dev/null
+++ b/docs/releases/1.7.7.txt
@@ -0,0 +1,54 @@
+==========================
+Django 1.7.7 release notes
+==========================
+
+*March 18, 2015*
+
+Django 1.7.7 fixes several bugs and security issues in 1.7.6.
+
+Denial-of-service possibility with ``strip_tags()``
+===================================================
+
+Last year :func:`~django.utils.html.strip_tags`  was changed to work
+iteratively. The problem is that the size of the input it's processing can
+increase on each iteration which results in an infinite loop in
+``strip_tags()``. This issue only affects versions of Python that haven't
+received  `a bugfix in HTMLParser <http://bugs.python.org/issue20288>`_; namely
+Python < 2.7.7 and 3.3.5. Some operating system vendors have also backported
+the fix for the Python bug into their packages of earlier versions.
+
+To remedy this issue, ``strip_tags()`` will now return the original input if
+it detects the length of the string it's processing increases. Remember that
+absolutely NO guarantee is provided about the results of ``strip_tags()`` being
+HTML safe. So NEVER mark safe the result of a ``strip_tags()`` call without
+escaping it first, for example with :func:`~django.utils.html.escape`.
+
+Mitigated possible XSS attack via user-supplied redirect URLs
+=============================================================
+
+Django relies on user input in some cases (e.g.
+:func:`django.contrib.auth.views.login` and :doc:`i18n </topics/i18n/index>`)
+to redirect the user to an "on success" URL. The security checks for these
+redirects (namely ``django.utils.http.is_safe_url()``) accepted URLs with
+leading control characters and so considered URLs like ``\x08javascript:...``
+safe. This issue doesn't affect Django currently, since we only put this URL
+into the ``Location`` response header and browsers seem to ignore JavaScript
+there. Browsers we tested also treat URLs prefixed with control characters such
+as ``%08//example.com`` as relative paths so redirection to an unsafe target
+isn't a problem either.
+
+However, if a developer relies on ``is_safe_url()`` to
+provide safe redirect targets and puts such a URL into a link, they could
+suffer from an XSS attack as some browsers such as Google Chrome ignore control
+characters at the start of a URL in an anchor ``href``.
+
+Bugfixes
+========
+
+* Fixed renaming of classes in migrations where renaming a subclass would
+  cause incorrect state to be recorded for objects that referenced the
+  superclass (:ticket:`24354`).
+
+* Stopped writing migration files in dry run mode when merging migration
+  conflicts. When ``makemigrations --merge`` is called with ``verbosity=3`` the
+  migration file is written to ``stdout`` (:ticket: `24427`).
diff --git a/docs/releases/1.7.txt b/docs/releases/1.7.txt
index 34e9a09..e2723ca 100644
--- a/docs/releases/1.7.txt
+++ b/docs/releases/1.7.txt
@@ -1518,6 +1518,22 @@ As :class:`~collections.OrderedDict` was added to the standard library in
 Python 2.7, :class:`~django.utils.datastructures.SortedDict` is no longer
 needed and has been deprecated.
 
+The two additional, deprecated methods provided by ``SortedDict`` (``insert()``
+and ``value_for_index()``) have been removed. If you relied on these methods to
+alter structures like form fields, you should now treat these ``OrderedDict``\s
+as immutable objects and override them to change their content.
+
+For example, you might want to override ``MyFormClass.base_fields`` (although
+this attribute isn't considered a public API) to change the ordering of fields
+for all ``MyFormClass`` instances; or similarly, you could override
+``self.fields`` from inside ``MyFormClass.__init__()``, to change the fields
+for a particular form instance. For example (from Django itself)::
+
+    PasswordChangeForm.base_fields = OrderedDict(
+        (k, PasswordChangeForm.base_fields[k])
+        for k in ['old_password', 'new_password1', 'new_password2']
+    )
+
 Custom SQL location for models package
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -1554,7 +1570,7 @@ Reorganization of ``django.contrib.contenttypes``
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 Since ``django.contrib.contenttypes.generic`` defined both admin and model
-related objects an import of this module could trigger unexpected side effects.
+related objects, an import of this module could trigger unexpected side effects.
 As a consequence, its contents were split into :mod:`~django.contrib.contenttypes`
 submodules and the ``django.contrib.contenttypes.generic`` module is deprecated:
 
diff --git a/docs/releases/index.txt b/docs/releases/index.txt
index e1cf808..7545c55 100644
--- a/docs/releases/index.txt
+++ b/docs/releases/index.txt
@@ -25,6 +25,7 @@ versions of the documentation contain the release notes for any later releases.
 .. toctree::
    :maxdepth: 1
 
+   1.7.7
    1.7.6
    1.7.5
    1.7.4
@@ -38,6 +39,7 @@ versions of the documentation contain the release notes for any later releases.
 .. toctree::
    :maxdepth: 1
 
+   1.6.11
    1.6.10
    1.6.9
    1.6.8
@@ -74,6 +76,7 @@ versions of the documentation contain the release notes for any later releases.
 .. toctree::
    :maxdepth: 1
 
+   1.4.20
    1.4.19
    1.4.18
    1.4.17
diff --git a/docs/topics/auth/default.txt b/docs/topics/auth/default.txt
index 89af55f..d3a5b72 100644
--- a/docs/topics/auth/default.txt
+++ b/docs/topics/auth/default.txt
@@ -1402,6 +1402,11 @@ have the power to create superusers, which can then, in turn, change other
 users. So Django requires add *and* change permissions as a slight security
 measure.
 
+Be thoughtful about how you allow users to manage permissions. If you give a
+non-superuser the ability to edit users, this is ultimately the same as giving
+them superuser status because they will be able to elevate permissions of
+users including themselves!
+
 Changing Passwords
 ------------------
 
diff --git a/docs/topics/db/sql.txt b/docs/topics/db/sql.txt
index c57ccbc..6ca7097 100644
--- a/docs/topics/db/sql.txt
+++ b/docs/topics/db/sql.txt
@@ -56,7 +56,7 @@ options that make it very powerful.
 
 .. admonition:: Model table names
 
-    Where'd the name of the ``Person`` table come from in that example?
+    Where did the name of the ``Person`` table come from in that example?
 
     By default, Django figures out a database table name by joining the
     model's "app label" -- the name you used in ``manage.py startapp`` -- to
diff --git a/docs/topics/forms/modelforms.txt b/docs/topics/forms/modelforms.txt
index 223f740..97e640c 100644
--- a/docs/topics/forms/modelforms.txt
+++ b/docs/topics/forms/modelforms.txt
@@ -49,67 +49,72 @@ Each model field has a corresponding default form field. For example, a
 ``ManyToManyField`` is represented as a ``MultipleChoiceField``. Here is the
 full list of conversions:
 
-===============================  ========================================
-Model field                      Form field
-===============================  ========================================
-``AutoField``                    Not represented in the form
+.. currentmodule:: django.db.models
 
-``BigIntegerField``              ``IntegerField`` with ``min_value`` set
-                                 to -9223372036854775808 and ``max_value``
-                                 set to 9223372036854775807.
+=================================== ==================================================
+Model field                         Form field
+=================================== ==================================================
+:class:`AutoField`                  Not represented in the form
 
-``BooleanField``                 ``BooleanField``
+:class:`BigIntegerField`            :class:`~django.forms.IntegerField` with
+                                    ``min_value`` set to -9223372036854775808
+                                    and ``max_value`` set to 9223372036854775807.
 
-``CharField``                    ``CharField`` with ``max_length`` set to
-                                 the model field's ``max_length``
+:class:`BooleanField`               :class:`~django.forms.BooleanField`
 
-``CommaSeparatedIntegerField``   ``CharField``
+:class:`CharField`                  :class:`~django.forms.CharField` with
+                                    ``max_length`` set to the model field's
+                                    ``max_length``
 
-``DateField``                    ``DateField``
+:class:`CommaSeparatedIntegerField` :class:`~django.forms.CharField`
 
-``DateTimeField``                ``DateTimeField``
+:class:`DateField`                  :class:`~django.forms.DateField`
 
-``DecimalField``                 ``DecimalField``
+:class:`DateTimeField`              :class:`~django.forms.DateTimeField`
 
-``EmailField``                   ``EmailField``
+:class:`DecimalField`               :class:`~django.forms.DecimalField`
 
-``FileField``                    ``FileField``
+:class:`EmailField`                 :class:`~django.forms.EmailField`
 
-``FilePathField``                ``FilePathField``
+:class:`FileField`                  :class:`~django.forms.FileField`
 
-``FloatField``                   ``FloatField``
+:class:`FilePathField`              :class:`~django.forms.FilePathField`
 
-``ForeignKey``                   ``ModelChoiceField`` (see below)
+:class:`FloatField`                 :class:`~django.forms.FloatField`
 
-``ImageField``                   ``ImageField``
+:class:`ForeignKey`                 :class:`~django.forms.ModelChoiceField`
+                                    (see below)
 
-``IntegerField``                 ``IntegerField``
+``ImageField``                      :class:`~django.forms.ImageField`
 
-``IPAddressField``               ``IPAddressField``
+:class:`IntegerField`               :class:`~django.forms.IntegerField`
 
-``GenericIPAddressField``        ``GenericIPAddressField``
+``IPAddressField``                  ``IPAddressField``
 
-``ManyToManyField``              ``ModelMultipleChoiceField`` (see
-                                 below)
+:class:`GenericIPAddressField`      :class:`~django.forms.GenericIPAddressField`
 
-``NullBooleanField``             ``CharField``
+:class:`ManyToManyField`            :class:`~django.forms.ModelMultipleChoiceField`
+                                    (see below)
 
-``PositiveIntegerField``         ``IntegerField``
+:class:`NullBooleanField`           :class:`~django.forms.CharField`
 
-``PositiveSmallIntegerField``    ``IntegerField``
+:class:`PositiveIntegerField`       :class:`~django.forms.IntegerField`
 
-``SlugField``                    ``SlugField``
+:class:`PositiveSmallIntegerField`  :class:`~django.forms.IntegerField`
 
-``SmallIntegerField``            ``IntegerField``
+:class:`SlugField`                  :class:`~django.forms.SlugField`
 
-``TextField``                    ``CharField`` with
-                                 ``widget=forms.Textarea``
+:class:`SmallIntegerField`          :class:`~django.forms.IntegerField`
 
-``TimeField``                    ``TimeField``
+:class:`TextField`                  :class:`~django.forms.CharField` with
+                                    ``widget=forms.Textarea``
 
-``URLField``                     ``URLField``
-===============================  ========================================
+:class:`TimeField`                  :class:`~django.forms.TimeField`
 
+:class:`URLField`                   :class:`~django.forms.URLField`
+=================================== ==================================================
+
+.. currentmodule:: django.forms
 
 As you might expect, the ``ForeignKey`` and ``ManyToManyField`` model field
 types are special cases:
@@ -693,7 +698,7 @@ and values from an attached model instance. For example::
     >>> article.headline
     'My headline'
     >>> form = ArticleForm(initial={'headline': 'Initial headline'), instance=article)
-    >>> form['pub_date'].value()
+    >>> form['headline'].value()
     'Initial headline'
 
 .. _modelforms-factory:
diff --git a/docs/topics/migrations.txt b/docs/topics/migrations.txt
index aa40590..2353899 100755
--- a/docs/topics/migrations.txt
+++ b/docs/topics/migrations.txt
@@ -435,68 +435,31 @@ You can pass a second callable to
 want executed when migrating backwards. If this callable is omitted, migrating
 backwards will raise an exception.
 
-.. _data-migrations-and-multiple-databases:
+Accessing models from other apps
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Data migrations and multiple databases
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+When writing a ``RunPython`` function that uses models from apps other than the
+one in which the migration is located, the migration's ``dependencies``
+attribute should include the latest migration of each app that is involved,
+otherwise you may get an error similar to: ``LookupError: No installed app
+with label 'myappname'`` when you try to retrieve the model in the ``RunPython``
+function using ``apps.get_model()``.
 
-When using multiple databases, you may need to figure out whether or not to
-run a migration against a particular database. For example, you may want to
-**only** run a migration on a particular database.
-
-In order to do that you can check the database connection's alias inside a
-``RunPython`` operation by looking at the ``schema_editor.connection.alias``
-attribute::
-
-    from django.db import migrations
-
-    def forwards(apps, schema_editor):
-        if not schema_editor.connection.alias == 'default':
-            return
-        # Your migration code goes here
-
-    class Migration(migrations.Migration):
-
-        dependencies = [
-            # Dependencies to other migrations
-        ]
-
-        operations = [
-            migrations.RunPython(forwards),
-        ]
-
-You can also use your database router's ``allow_migrate()`` method, but keep in
-mind that the imported router needs to stay around as long as it is referenced
-inside a migration:
-
-.. snippet::
-    :filename: myapp/dbrouters.py
-
-    class MyRouter(object):
-
-        def allow_migrate(self, db, model):
-            return db == 'default'
-
-Then, to leverage this in your migrations, do the following::
-
-    from django.db import migrations
-
-    from myappname.dbrouters import MyRouter
-
-    def forwards(apps, schema_editor):
-        MyModel = apps.get_model("myappname", "MyModel")
-        if not MyRouter().allow_migrate(schema_editor.connection.alias, MyModel):
-            return
-        # Your migration code goes here
+In the following example, we have a migration in ``app1`` which needs to use
+models in ``app2``. We aren't concerned with the details of ``move_m1`` other
+than the fact it will need to access models from both apps. Therefore we've
+added a dependency that specifies the last migration of ``app2``::
 
     class Migration(migrations.Migration):
 
         dependencies = [
-            # Dependencies to other migrations
+            ('app1', '0001_initial'),
+            # added dependency to enable using models from app2 in move_m1
+            ('app2', '0004_foobar'),
         ]
 
         operations = [
-            migrations.RunPython(forwards),
+            migrations.RunPython(move_m1),
         ]
 
 More advanced migrations
diff --git a/tests/migrations/test_commands.py b/tests/migrations/test_commands.py
index ef6f71a..d12cfe9 100644
--- a/tests/migrations/test_commands.py
+++ b/tests/migrations/test_commands.py
@@ -400,6 +400,51 @@ class MakeMigrationsTests(MigrationTestBase):
         self.assertIn("Created new merge migration", stdout.getvalue())
 
     @override_system_checks([])
+    @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_conflict"})
+    def test_makemigration_merge_dry_run(self):
+        """
+        Makes sure that makemigrations respects --dry-run option when fixing
+        migration conflicts (#24427).
+        """
+        out = six.StringIO()
+        call_command("makemigrations", "migrations", dry_run=True, merge=True, interactive=False, stdout=out)
+        merge_file = os.path.join(self.test_dir, '0003_merge.py')
+        self.assertFalse(os.path.exists(merge_file))
+        output = force_text(out.getvalue())
+        self.assertIn("Merging migrations", output)
+        self.assertIn("Branch 0002_second", output)
+        self.assertIn("Branch 0002_conflicting_second", output)
+        self.assertNotIn("Created new merge migration", output)
+
+    @override_system_checks([])
+    @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_conflict"})
+    def test_makemigration_merge_dry_run_verbosity_3(self):
+        """
+        Makes sure that `makemigrations --merge --dry-run` writes the merge
+        migration file to stdout with `verbosity == 3` (#24427).
+        """
+        out = six.StringIO()
+        call_command("makemigrations", "migrations", dry_run=True, merge=True, interactive=False,
+                     stdout=out, verbosity=3)
+        merge_file = os.path.join(self.test_dir, '0003_merge.py')
+        self.assertFalse(os.path.exists(merge_file))
+        output = force_text(out.getvalue())
+        self.assertIn("Merging migrations", output)
+        self.assertIn("Branch 0002_second", output)
+        self.assertIn("Branch 0002_conflicting_second", output)
+        self.assertNotIn("Created new merge migration", output)
+
+        # Additional output caused by verbosity 3
+        # The complete merge migration file that would be written
+        self.assertIn("# -*- coding: utf-8 -*-", output)
+        self.assertIn("class Migration(migrations.Migration):", output)
+        self.assertIn("dependencies = [", output)
+        self.assertIn("('migrations', '0002_second')", output)
+        self.assertIn("('migrations', '0002_conflicting_second')", output)
+        self.assertIn("operations = [", output)
+        self.assertIn("]", output)
+
+    @override_system_checks([])
     @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_no_default"})
     def test_makemigrations_dry_run(self):
         """
diff --git a/tests/migrations/test_operations.py b/tests/migrations/test_operations.py
index 06a22d0..3cc2256 100644
--- a/tests/migrations/test_operations.py
+++ b/tests/migrations/test_operations.py
@@ -482,6 +482,41 @@ class OperationTests(OperationTestBase):
             self.assertFKExists("test_rmwsrf_rider", ["friend_id"], ("test_rmwsrf_rider", "id"))
             self.assertFKNotExists("test_rmwsrf_rider", ["friend_id"], ("test_rmwsrf_horserider", "id"))
 
+    def test_rename_model_with_superclass_fk(self):
+        """
+        Tests the RenameModel operation on a model which has a superclass that
+        has a foreign key.
+        """
+        project_state = self.set_up_test_model("test_rmwsc", related_model=True, mti_model=True)
+        # Test the state alteration
+        operation = migrations.RenameModel("ShetlandPony", "LittleHorse")
+        self.assertEqual(operation.describe(), "Rename model ShetlandPony to LittleHorse")
+        new_state = project_state.clone()
+        operation.state_forwards("test_rmwsc", new_state)
+        self.assertNotIn(("test_rmwsc", "shetlandpony"), new_state.models)
+        self.assertIn(("test_rmwsc", "littlehorse"), new_state.models)
+        # RenameModel shouldn't repoint the superclass's relations, only local ones
... 53 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