[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