[Python-modules-commits] [python-django] 01/07: Import python-django_1.8.9.orig.tar.gz
Raphaël Hertzog
hertzog at moszumanska.debian.org
Tue Feb 2 09:07:21 UTC 2016
This is an automated email from the git hooks/post-receive script.
hertzog pushed a commit to branch debian/jessie-backports
in repository python-django.
commit 005755b3e573831af927ce66797168fa370332db
Author: Raphaël Hertzog <hertzog at debian.org>
Date: Tue Feb 2 09:51:24 2016 +0100
Import python-django_1.8.9.orig.tar.gz
---
AUTHORS | 2 +
Django.egg-info/PKG-INFO | 2 +-
Django.egg-info/SOURCES.txt | 1 +
PKG-INFO | 2 +-
django/__init__.py | 2 +-
django/contrib/admin/helpers.py | 2 +-
django/contrib/admin/sites.py | 8 +-
.../static/admin/js/admin/DateTimeShortcuts.js | 4 +-
django/contrib/admin/static/admin/js/core.js | 5 +-
django/contrib/admin/utils.py | 2 +-
django/contrib/auth/hashers.py | 2 +-
django/contrib/gis/templates/gis/openlayers.html | 5 +-
django/db/backends/postgresql_psycopg2/schema.py | 4 +-
django/db/models/lookups.py | 8 ++
django/db/models/sql/where.py | 16 ++-
django/dispatch/dispatcher.py | 6 +-
django/utils/functional.py | 20 ++++
django/utils/translation/trans_real.py | 3 +
docs/howto/deployment/wsgi/modwsgi.txt | 7 +-
docs/intro/reusable-apps.txt | 1 +
docs/ref/csrf.txt | 2 +-
docs/ref/databases.txt | 2 +-
docs/releases/1.8.9.txt | 39 ++++++++
docs/releases/index.txt | 1 +
docs/topics/i18n/translation.txt | 24 ++---
docs/topics/security.txt | 3 +-
setup.cfg | 2 +-
tests/admin_scripts/tests.py | 1 +
tests/admin_views/admin.py | 23 +++--
tests/admin_views/models.py | 7 +-
tests/admin_views/tests.py | 82 +++++++++++++---
tests/expressions_case/tests.py | 13 ++-
.../templates/forms_tests/article_form.html | 2 +-
tests/gis_tests/distapp/tests.py | 2 +-
tests/gis_tests/geogapp/tests.py | 10 +-
tests/gis_tests/test_geoforms.py | 5 +-
tests/i18n/tests.py | 4 +
tests/migrations/test_writer.py | 2 +
tests/schema/tests.py | 108 +++++++++++++--------
tests/templates/form_view.html | 2 +-
tests/templates/login.html | 2 +-
tests/utils_tests/test_dateformat.py | 3 +
tests/utils_tests/test_lazyobject.py | 85 ++++++++++++++--
43 files changed, 403 insertions(+), 123 deletions(-)
diff --git a/AUTHORS b/AUTHORS
index 06d9882..e871235 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -611,6 +611,7 @@ answer newbie questions, and generally made Django that much better:
schwank at gmail.com
Scot Hacker <shacker at birdhouse.org>
Scott Barr <scott at divisionbyzero.com.au>
+ Scott Pashley <github at scottpashley.co.uk>
scott at staplefish.com
Sean Brant
Sebastian Hillig <sebastian.hillig at gmail.com>
@@ -720,6 +721,7 @@ answer newbie questions, and generally made Django that much better:
Yasushi Masuda <whosaysni at gmail.com>
ye7cakf02 at sneakemail.com
ymasuda at ethercube.com
+ Yoong Kang Lim <yoongkang.lim at gmail.com>
Zachary Voase <zacharyvoase at gmail.com>
Zach Thompson <zthompson47 at gmail.com>
Zain Memon
diff --git a/Django.egg-info/PKG-INFO b/Django.egg-info/PKG-INFO
index a62d086..42f9052 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.8.8
+Version: 1.8.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 52865cb..4b68a10 100644
--- a/Django.egg-info/SOURCES.txt
+++ b/Django.egg-info/SOURCES.txt
@@ -3409,6 +3409,7 @@ docs/releases/1.8.5.txt
docs/releases/1.8.6.txt
docs/releases/1.8.7.txt
docs/releases/1.8.8.txt
+docs/releases/1.8.9.txt
docs/releases/1.8.txt
docs/releases/index.txt
docs/releases/security.txt
diff --git a/PKG-INFO b/PKG-INFO
index a62d086..42f9052 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: Django
-Version: 1.8.8
+Version: 1.8.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 aa515b5..80244c4 100644
--- a/django/__init__.py
+++ b/django/__init__.py
@@ -1,6 +1,6 @@
from django.utils.version import get_version
-VERSION = (1, 8, 8, 'final', 0)
+VERSION = (1, 8, 9, 'final', 0)
__version__ = get_version(VERSION)
diff --git a/django/contrib/admin/helpers.py b/django/contrib/admin/helpers.py
index 1b6a0ff..36886bf 100644
--- a/django/contrib/admin/helpers.py
+++ b/django/contrib/admin/helpers.py
@@ -203,7 +203,7 @@ class AdminReadonlyField(object):
else:
result_repr = linebreaksbr(result_repr)
else:
- if isinstance(f.rel, ManyToManyRel) and value is not None:
+ if isinstance(getattr(f, 'rel', None), ManyToManyRel) and value is not None:
result_repr = ", ".join(map(six.text_type, value.all()))
else:
result_repr = display_for_field(value, f)
diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py
index af40880..e08b932 100644
--- a/django/contrib/admin/sites.py
+++ b/django/contrib/admin/sites.py
@@ -355,7 +355,13 @@ class AdminSite(object):
from django.contrib.auth.views import logout
defaults = {
'current_app': self.name,
- 'extra_context': dict(self.each_context(request), **(extra_context or {})),
+ 'extra_context': dict(
+ self.each_context(request),
+ # Since the user isn't logged out at this point, the value of
+ # has_permission must be overridden.
+ has_permission=False,
+ **(extra_context or {})
+ ),
}
if self.logout_template is not None:
defaults['template_name'] = self.logout_template
diff --git a/django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js b/django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js
index faec5a4..8d50046 100644
--- a/django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js
+++ b/django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js
@@ -292,8 +292,8 @@ var DateTimeShortcuts = {
if (inp.value) {
var format = get_format('DATE_INPUT_FORMATS')[0];
var selected = inp.value.strptime(format);
- var year = selected.getFullYear();
- var month = selected.getMonth() + 1;
+ var year = selected.getUTCFullYear();
+ var month = selected.getUTCMonth() + 1;
var re = /\d{4}/
if (re.test(year.toString()) && month >= 1 && month <= 12) {
DateTimeShortcuts.calendars[num].drawDate(month, year, selected);
diff --git a/django/contrib/admin/static/admin/js/core.js b/django/contrib/admin/static/admin/js/core.js
index 2c096aa..7526bd3 100644
--- a/django/contrib/admin/static/admin/js/core.js
+++ b/django/contrib/admin/static/admin/js/core.js
@@ -225,7 +225,10 @@ String.prototype.strptime = function(format) {
}
++i;
};
- return new Date(year, month, day);
+ // Create Date object from UTC since the parsed value is supposed to be in
+ // UTC, not local time. Also, the calendar uses UTC functions for date
+ // extraction.
+ return new Date(Date.UTC(year, month, day));
}
// ----------------------------------------------------------------------------
diff --git a/django/contrib/admin/utils.py b/django/contrib/admin/utils.py
index 8ddba50..1ea73d6 100644
--- a/django/contrib/admin/utils.py
+++ b/django/contrib/admin/utils.py
@@ -376,7 +376,7 @@ def display_for_field(value, field):
from django.contrib.admin.templatetags.admin_list import _boolean_icon
from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE
- if field.flatchoices:
+ if getattr(field, 'flatchoices', None):
return dict(field.flatchoices).get(value, EMPTY_CHANGELIST_VALUE)
# NullBooleanField needs special-case null-handling, so it comes
# before the general null test.
diff --git a/django/contrib/auth/hashers.py b/django/contrib/auth/hashers.py
index f7f143b..a8583f7 100644
--- a/django/contrib/auth/hashers.py
+++ b/django/contrib/auth/hashers.py
@@ -349,7 +349,7 @@ class BCryptPasswordHasher(BCryptSHA256PasswordHasher):
This hasher does not first hash the password which means it is subject to
the 72 character bcrypt password truncation, most use cases should prefer
- the BCryptSha512PasswordHasher.
+ the BCryptSHA256PasswordHasher.
See: https://code.djangoproject.com/ticket/20138
"""
diff --git a/django/contrib/gis/templates/gis/openlayers.html b/django/contrib/gis/templates/gis/openlayers.html
index cbefb3a..0356a9d 100644
--- a/django/contrib/gis/templates/gis/openlayers.html
+++ b/django/contrib/gis/templates/gis/openlayers.html
@@ -1,4 +1,5 @@
-<style type="text/css">{% block map_css %}{% load i18n static %}{% get_current_language_bidi as LANGUAGE_BIDI %}
+{% load i18n l10n static %}
+<style type="text/css">{% block map_css %}{% get_current_language_bidi as LANGUAGE_BIDI %}
#{{ id }}_map { width: {{ map_width }}px; height: {{ map_height }}px; }
#{{ id }}_map .aligned label { float: inherit; }
#{{ id }}_div_map { position: relative; vertical-align: top; float: {{ LANGUAGE_BIDI|yesno:"right,left" }}; }
@@ -25,7 +26,7 @@
id: '{{ id }}',
map_id: '{{ id }}_map',
map_options: map_options,
- map_srid: {{ map_srid }},
+ map_srid: {{ map_srid|unlocalize }},
name: '{{ name }}'
};
{% endblock %}
diff --git a/django/db/backends/postgresql_psycopg2/schema.py b/django/db/backends/postgresql_psycopg2/schema.py
index e425154..884ac44 100644
--- a/django/db/backends/postgresql_psycopg2/schema.py
+++ b/django/db/backends/postgresql_psycopg2/schema.py
@@ -107,13 +107,13 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
new_db_params, strict,
)
# Added an index? Create any PostgreSQL-specific indexes.
- if ((not old_field.db_index and new_field.db_index) or (not old_field.unique and new_field.unique)):
+ if not old_field.db_index and not old_field.unique and (new_field.db_index or new_field.unique):
like_index_statement = self._create_like_index_sql(model, new_field)
if like_index_statement is not None:
self.execute(like_index_statement)
# Removed an index? Drop any PostgreSQL-specific indexes.
- if ((not new_field.db_index and old_field.db_index) or (not new_field.unique and old_field.unique)):
+ if (old_field.db_index or old_field.unique) and not (new_field.db_index or new_field.unique):
index_to_remove = self._create_index_name(model, [old_field.column], suffix='_like')
index_names = self._constraint_names(model, [old_field.column], index=True)
for index_name in index_names:
diff --git a/django/db/models/lookups.py b/django/db/models/lookups.py
index d0b30ac..8428d38 100644
--- a/django/db/models/lookups.py
+++ b/django/db/models/lookups.py
@@ -92,6 +92,10 @@ class Transform(RegisterLookupMixin):
bilateral_transforms.append((self.__class__, self.init_lookups))
return bilateral_transforms
+ @cached_property
+ def contains_aggregate(self):
+ return self.lhs.contains_aggregate
+
class Lookup(RegisterLookupMixin):
lookup_name = None
@@ -194,6 +198,10 @@ class Lookup(RegisterLookupMixin):
def as_sql(self, compiler, connection):
raise NotImplementedError
+ @cached_property
+ def contains_aggregate(self):
+ return self.lhs.contains_aggregate or getattr(self.rhs, 'contains_aggregate', False)
+
class BuiltinLookup(Lookup):
def process_lhs(self, compiler, connection, lhs=None):
diff --git a/django/db/models/sql/where.py b/django/db/models/sql/where.py
index 2ba6cea..8cad3df 100644
--- a/django/db/models/sql/where.py
+++ b/django/db/models/sql/where.py
@@ -315,9 +315,9 @@ class WhereNode(tree.Node):
@classmethod
def _contains_aggregate(cls, obj):
- if not isinstance(obj, tree.Node):
- return getattr(obj.lhs, 'contains_aggregate', False) or getattr(obj.rhs, 'contains_aggregate', False)
- return any(cls._contains_aggregate(c) for c in obj.children)
+ if isinstance(obj, tree.Node):
+ return any(cls._contains_aggregate(c) for c in obj.children)
+ return obj.contains_aggregate
@cached_property
def contains_aggregate(self):
@@ -336,6 +336,7 @@ class EverythingNode(object):
"""
A node that matches everything.
"""
+ contains_aggregate = False
def as_sql(self, compiler=None, connection=None):
return '', []
@@ -345,11 +346,16 @@ class NothingNode(object):
"""
A node that matches nothing.
"""
+ contains_aggregate = False
+
def as_sql(self, compiler=None, connection=None):
raise EmptyResultSet
class ExtraWhere(object):
+ # The contents are a black box - assume no aggregates are used.
+ contains_aggregate = False
+
def __init__(self, sqls, params):
self.sqls = sqls
self.params = params
@@ -410,6 +416,10 @@ class Constraint(object):
class SubqueryConstraint(object):
+ # Even if aggregates would be used in a subquery, the outer query isn't
+ # interested about those.
+ contains_aggregate = False
+
def __init__(self, alias, columns, targets, query_object):
self.alias = alias
self.columns = columns
diff --git a/django/dispatch/dispatcher.py b/django/dispatch/dispatcher.py
index 5d7f24c..ec59666 100644
--- a/django/dispatch/dispatcher.py
+++ b/django/dispatch/dispatcher.py
@@ -168,13 +168,13 @@ class Signal(object):
Send signal from sender to all connected receivers.
If any receiver raises an error, the error propagates back through send,
- terminating the dispatch loop, so it is quite possible to not have all
- receivers called if a raises an error.
+ terminating the dispatch loop. So it's possible that all receivers
+ won't be called if an error is raised.
Arguments:
sender
- The sender of the signal Either a specific object or None.
+ The sender of the signal. Either a specific object or None.
named
Named arguments which will be passed to receivers.
diff --git a/django/utils/functional.py b/django/utils/functional.py
index a3c0b88..b230273 100644
--- a/django/utils/functional.py
+++ b/django/utils/functional.py
@@ -240,6 +240,8 @@ class LazyObject(object):
_wrapped = None
def __init__(self):
+ # Note: if a subclass overrides __init__(), it will likely need to
+ # override __copy__() and __deepcopy__() as well.
self._wrapped = empty
__getattr__ = new_method_proxy(getattr)
@@ -292,6 +294,15 @@ class LazyObject(object):
def __getstate__(self):
return {}
+ def __copy__(self):
+ if self._wrapped is empty:
+ # If uninitialized, copy the wrapper. Use type(self), not
+ # self.__class__, because the latter is proxied.
+ return type(self)()
+ else:
+ # If initialized, return a copy of the wrapped object.
+ return copy.copy(self._wrapped)
+
def __deepcopy__(self, memo):
if self._wrapped is empty:
# We have to use type(self), not self.__class__, because the
@@ -373,6 +384,15 @@ class SimpleLazyObject(LazyObject):
repr_attr = self._wrapped
return '<%s: %r>' % (type(self).__name__, repr_attr)
+ def __copy__(self):
+ if self._wrapped is empty:
+ # If uninitialized, copy the wrapper. Use SimpleLazyObject, not
+ # self.__class__, because the latter is proxied.
+ return SimpleLazyObject(self._setupfunc)
+ else:
+ # If initialized, return a copy of the wrapped object.
+ return copy.copy(self._wrapped)
+
def __deepcopy__(self, memo):
if self._wrapped is empty:
# We have to use SimpleLazyObject, not self.__class__, because the
diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py
index aa50c02..8aa8f4e 100644
--- a/django/utils/translation/trans_real.py
+++ b/django/utils/translation/trans_real.py
@@ -121,6 +121,9 @@ class DjangoTranslation(gettext_module.GNUTranslations):
# default lang should have at least one translation file available.
raise IOError("No translation files found for default language %s." % settings.LANGUAGE_CODE)
self._add_fallback()
+ if self._catalog is None:
+ # No catalogs found for this language, set an empty catalog.
+ self._catalog = {}
def __repr__(self):
return "<DjangoTranslation lang:%s>" % self.__language
diff --git a/docs/howto/deployment/wsgi/modwsgi.txt b/docs/howto/deployment/wsgi/modwsgi.txt
index 90ca1c0..985926c 100644
--- a/docs/howto/deployment/wsgi/modwsgi.txt
+++ b/docs/howto/deployment/wsgi/modwsgi.txt
@@ -157,10 +157,9 @@ If, however, you have no option but to serve media files on the same Apache
``VirtualHost`` as Django, you can set up Apache to serve some URLs as
static media, and others using the mod_wsgi interface to Django.
-This example sets up Django at the site root, but explicitly serves
-``robots.txt``, ``favicon.ico``, any CSS file, and anything in the
-``/static/`` and ``/media/`` URL space as a static file. All other URLs
-will be served using mod_wsgi:
+This example sets up Django at the site root, but serves ``robots.txt``,
+``favicon.ico``, and anything in the ``/static/`` and ``/media/`` URL space as
+a static file. All other URLs will be served using mod_wsgi:
.. code-block:: apache
diff --git a/docs/intro/reusable-apps.txt b/docs/intro/reusable-apps.txt
index 3c8041e..245a88b 100644
--- a/docs/intro/reusable-apps.txt
+++ b/docs/intro/reusable-apps.txt
@@ -215,6 +215,7 @@ this. For a small app like polls, this process isn't too difficult.
classifiers=[
'Environment :: Web Environment',
'Framework :: Django',
+ 'Framework :: Django :: X.Y', # replace "X.Y" as appropriate
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License', # example license
'Operating System :: OS Independent',
diff --git a/docs/ref/csrf.txt b/docs/ref/csrf.txt
index 85810b9..dbc05b6 100644
--- a/docs/ref/csrf.txt
+++ b/docs/ref/csrf.txt
@@ -40,7 +40,7 @@ To take advantage of CSRF protection in your views, follow these steps:
2. In any template that uses a POST form, use the :ttag:`csrf_token` tag inside
the ``<form>`` element if the form is for an internal URL, e.g.::
- <form action="." method="post">{% csrf_token %}
+ <form action="" method="post">{% csrf_token %}
This should not be done for POST forms that target external URLs, since
that would cause the CSRF token to be leaked, leading to a vulnerability.
diff --git a/docs/ref/databases.txt b/docs/ref/databases.txt
index dd3ea36..ed15390 100644
--- a/docs/ref/databases.txt
+++ b/docs/ref/databases.txt
@@ -448,7 +448,7 @@ storage engine, you have a couple of options.
creating your tables::
'OPTIONS': {
- 'init_command': 'SET storage_engine=INNODB',
+ 'init_command': 'SET default_storage_engine=INNODB',
}
This sets the default storage engine upon connecting to the database.
diff --git a/docs/releases/1.8.9.txt b/docs/releases/1.8.9.txt
new file mode 100644
index 0000000..92f35ec
--- /dev/null
+++ b/docs/releases/1.8.9.txt
@@ -0,0 +1,39 @@
+==========================
+Django 1.8.9 release notes
+==========================
+
+*February 1, 2016*
+
+Django 1.8.9 fixes several bugs in 1.8.8.
+
+Bugfixes
+========
+
+* Fixed a regression that caused the "user-tools" items to display on the
+ admin's logout page (:ticket:`26035`).
+
+* Fixed a crash in the translations system when the current language has no
+ translations (:ticket:`26046`).
+
+* Fixed a regression that caused the incorrect day to be selected when opening
+ the admin calendar widget for timezones from GMT+0100 to GMT+1200
+ (:ticket:`24980`).
+
+* Fixed a regression in 1.8.8 causing incorrect index handling in migrations on
+ PostgreSQL when adding ``db_index=True`` or ``unique=True`` to a
+ ``CharField`` or ``TextField`` that already had the other specified, or when
+ removing one of them from a field that had both, or when adding
+ ``unique=True`` to a field already listed in ``unique_together``
+ (:ticket:`26034`).
+
+* Fixed a crash when using an ``__in`` lookup inside a ``Case`` expression
+ (:ticket:`26071`).
+
+* Fixed a crash when using a reverse ``OneToOneField`` in
+ ``ModelAdmin.readonly_fields`` (:ticket:`26060`).
+
+* Fixed a regression in Django 1.8.5 that broke copying a ``SimpleLazyObject``
+ with ``copy.copy()`` (:ticket:`26122`).
+
+* Fixed the ``contrib.gis`` map widgets when using
+ ``USE_THOUSAND_SEPARATOR=True`` (:ticket:`20415`).
diff --git a/docs/releases/index.txt b/docs/releases/index.txt
index ec4f0cc..9e6257b 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.8.9
1.8.8
1.8.7
1.8.6
diff --git a/docs/topics/i18n/translation.txt b/docs/topics/i18n/translation.txt
index 7f6de9e..db33e65 100644
--- a/docs/topics/i18n/translation.txt
+++ b/docs/topics/i18n/translation.txt
@@ -70,8 +70,6 @@ as a shorter alias, ``_``, to save typing.
global ``_()`` function causes interference. Explicitly importing
``ugettext()`` as ``_()`` avoids this problem.
-.. highlightlang:: python
-
In this example, the text ``"Welcome to my site."`` is marked as a translation
string::
@@ -960,7 +958,7 @@ You hook it up like this::
}
urlpatterns = [
- url(r'^jsi18n/$', javascript_catalog, js_info_dict),
+ url(r'^jsi18n/$', javascript_catalog, js_info_dict, name='javascript-catalog'),
]
Each string in ``packages`` should be in Python dotted-package syntax (the
@@ -980,7 +978,7 @@ changed by altering the ``domain`` argument.
You can make the view dynamic by putting the packages into the URL pattern::
urlpatterns = [
- url(r'^jsi18n/(?P<packages>\S+?)/$', javascript_catalog),
+ url(r'^jsi18n/(?P<packages>\S+?)/$', javascript_catalog, name='javascript-catalog'),
]
With this, you specify the packages as a list of package names delimited by '+'
@@ -1005,7 +1003,7 @@ To use the catalog, just pull in the dynamically generated script like this:
.. code-block:: html+django
- <script type="text/javascript" src="{% url 'django.views.i18n.javascript_catalog' %}"></script>
+ <script type="text/javascript" src="{% url 'javascript-catalog' %}"></script>
This uses reverse URL lookup to find the URL of the JavaScript catalog view.
When the catalog is loaded, your JavaScript code can use the following methods:
@@ -1158,6 +1156,8 @@ Additionally, if there are complex rules around pluralization, the catalog view
will render a conditional expression. This will evaluate to either a ``true``
(should pluralize) or ``false`` (should **not** pluralize) value.
+.. highlightlang:: python
+
Note on performance
-------------------
@@ -1269,8 +1269,8 @@ After defining these URL patterns, Django will automatically add the
language prefix to the URL patterns that were added by the ``i18n_patterns``
function. Example::
- from django.core.urlresolvers import reverse
- from django.utils.translation import activate
+ >>> from django.core.urlresolvers import reverse
+ >>> from django.utils.translation import activate
>>> activate('en')
>>> reverse('sitemap-xml')
@@ -1327,8 +1327,8 @@ After you've created the translations, the
:func:`~django.core.urlresolvers.reverse` function will return the URL in the
active language. Example::
- from django.core.urlresolvers import reverse
- from django.utils.translation import activate
+ >>> from django.core.urlresolvers import reverse
+ >>> from django.utils.translation import activate
>>> activate('en')
>>> reverse('news:category', kwargs={'slug': 'recent'})
@@ -1624,8 +1624,6 @@ translation utilities with a ``gettext`` package if the command ``xgettext
Customizing the ``makemessages`` command
----------------------------------------
-.. highlightlang:: python
-
If you want to pass additional parameters to ``xgettext``, you need to create a
custom :djadmin:`makemessages` command and override its ``xgettext_options``
attribute::
@@ -1664,8 +1662,6 @@ Miscellaneous
The ``set_language`` redirect view
----------------------------------
-.. highlightlang:: python
-
.. currentmodule:: django.views.i18n
.. function:: set_language(request)
@@ -1728,8 +1724,6 @@ redirected in the ``redirect_to`` context variable.
Explicitly setting the active language
--------------------------------------
-.. highlightlang:: python
-
You may want to set the active language for the current session explicitly. Perhaps
a user's language preference is retrieved from another system, for example.
You've already been introduced to :func:`django.utils.translation.activate()`. That
diff --git a/docs/topics/security.txt b/docs/topics/security.txt
index 62be131..b3639ba 100644
--- a/docs/topics/security.txt
+++ b/docs/topics/security.txt
@@ -29,7 +29,8 @@ which are particularly dangerous to HTML. While this protects users from most
malicious input, it is not entirely foolproof. For example, it will not
protect the following:
-.. code-block:: html+django
+.. code-block:: text
+.. highlighting as html+django fails due to intentionally missing quotes.
<style class={{ var }}>...</style>
diff --git a/setup.cfg b/setup.cfg
index fac4f6b..e4cafa8 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -22,6 +22,6 @@ universal = 1
[egg_info]
tag_build =
-tag_date = 0
tag_svn_revision = 0
+tag_date = 0
diff --git a/tests/admin_scripts/tests.py b/tests/admin_scripts/tests.py
index 7b2617e..a8617fb 100644
--- a/tests/admin_scripts/tests.py
+++ b/tests/admin_scripts/tests.py
@@ -61,6 +61,7 @@ class AdminScriptTestCase(unittest.TestCase):
'SECRET_KEY',
'TEST_RUNNER', # We need to include TEST_RUNNER, otherwise we get a compatibility warning.
'MIDDLEWARE_CLASSES', # We need to include MIDDLEWARE_CLASSES, otherwise we get a compatibility warning.
+ 'SPATIALITE_LIBRARY_PATH',
]
for s in exports:
if hasattr(settings, s):
diff --git a/tests/admin_views/admin.py b/tests/admin_views/admin.py
index 7a6b25b..68960df 100644
--- a/tests/admin_views/admin.py
+++ b/tests/admin_views/admin.py
@@ -34,15 +34,15 @@ from .models import (
InlineReference, InlineReferer, Inquisition, Language, Link,
MainPrepopulated, ModelWithStringPrimaryKey, NotReferenced, OldSubscriber,
OtherStory, Paper, Parent, ParentWithDependentChildren, Person, Persona,
- Picture, Pizza, Plot, PlotDetails, PluggableSearchPerson, Podcast, Post,
- PrePopulatedPost, PrePopulatedPostLargeSlug, PrePopulatedSubPost, Promo,
- Question, Recipe, Recommendation, Recommender, ReferencedByGenRel,
- ReferencedByInline, ReferencedByParent, RelatedPrepopulated, Report,
- Reservation, Restaurant, RowLevelChangePermissionModel, Section,
- ShortMessage, Simple, Sketch, State, Story, StumpJoke, Subscriber,
- SuperVillain, Telegram, Thing, Topping, UnchangeableObject,
- UndeletableObject, UnorderedObject, UserMessenger, Villain, Vodcast,
- Whatsit, Widget, Worker, WorkHour,
+ Picture, Pizza, Plot, PlotDetails, PlotProxy, PluggableSearchPerson,
+ Podcast, Post, PrePopulatedPost, PrePopulatedPostLargeSlug,
+ PrePopulatedSubPost, Promo, Question, Recipe, Recommendation, Recommender,
+ ReferencedByGenRel, ReferencedByInline, ReferencedByParent,
+ RelatedPrepopulated, Report, Reservation, Restaurant,
+ RowLevelChangePermissionModel, Section, ShortMessage, Simple, Sketch,
+ State, Story, StumpJoke, Subscriber, SuperVillain, Telegram, Thing,
+ Topping, UnchangeableObject, UndeletableObject, UnorderedObject,
+ UserMessenger, Villain, Vodcast, Whatsit, Widget, Worker, WorkHour,
)
@@ -853,6 +853,10 @@ class InlineRefererAdmin(admin.ModelAdmin):
inlines = [InlineReferenceInline]
+class PlotReadonlyAdmin(admin.ModelAdmin):
+ readonly_fields = ('plotdetails',)
+
+
class GetFormsetsArgumentCheckingAdmin(admin.ModelAdmin):
fields = ['name']
@@ -907,6 +911,7 @@ site.register(Villain)
site.register(SuperVillain)
site.register(Plot)
site.register(PlotDetails)
+site.register(PlotProxy, PlotReadonlyAdmin)
site.register(CyclicOne)
site.register(CyclicTwo)
site.register(WorkHour, WorkHourAdmin)
diff --git a/tests/admin_views/models.py b/tests/admin_views/models.py
index d68c44f..9218241 100644
--- a/tests/admin_views/models.py
+++ b/tests/admin_views/models.py
@@ -501,12 +501,17 @@ class Plot(models.Model):
@python_2_unicode_compatible
class PlotDetails(models.Model):
details = models.CharField(max_length=100)
- plot = models.OneToOneField(Plot)
+ plot = models.OneToOneField(Plot, null=True, blank=True)
def __str__(self):
return self.details
+class PlotProxy(Plot):
+ class Meta:
+ proxy = True
+
+
@python_2_unicode_compatible
class SecretHideout(models.Model):
""" Secret! Not registered with the admin! """
diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py
index a64e4d7..cb804dc 100644
--- a/tests/admin_views/tests.py
+++ b/tests/admin_views/tests.py
@@ -52,11 +52,11 @@ from .models import (
FoodDelivery, FunkyTag, Gallery, Grommet, Inquisition, Language, Link,
MainPrepopulated, ModelWithStringPrimaryKey, OtherStory, Paper, Parent,
ParentWithDependentChildren, Person, Persona, Picture, Pizza, Plot,
- PluggableSearchPerson, Podcast, Post, Promo, Question, RelatedPrepopulated,
- Report, Restaurant, RowLevelChangePermissionModel, Section, ShortMessage,
- Simple, Story, Subscriber, Telegram, Topping, UnchangeableObject,
- UndeletableObject, UnorderedObject, Vodcast, Whatsit, Widget, Worker,
- WorkHour,
+ PlotDetails, PluggableSearchPerson, Podcast, Post, Promo, Question,
+ RelatedPrepopulated, Report, Restaurant, RowLevelChangePermissionModel,
+ Section, ShortMessage, Simple, Story, Subscriber, Telegram, Topping,
+ UnchangeableObject, UndeletableObject, UnorderedObject, Villain, Vodcast,
+ Whatsit, Widget, Worker, WorkHour,
)
@@ -64,6 +64,44 @@ ERROR_MESSAGE = "Please enter the correct username and password \
for a staff account. Note that both fields may be case-sensitive."
+class AdminFieldExtractionMixin(object):
+ """
+ Helper methods for extracting data from AdminForm.
+ """
+ def get_admin_form_fields(self, response):
+ """
+ Return a list of AdminFields for the AdminForm in the response.
+ """
+ admin_form = response.context['adminform']
+ fieldsets = list(admin_form)
+
+ field_lines = []
+ for fieldset in fieldsets:
+ field_lines += list(fieldset)
+
+ fields = []
+ for field_line in field_lines:
+ fields += list(field_line)
+
+ return fields
+
+ def get_admin_fields(self, response):
+ """
+ Return the fields for the response's AdminForm.
+ """
+ return [f for f in self.get_admin_form_fields(response)]
+
+ def get_admin_field(self, response, field_name):
+ """
+ Return the field for the given field_name.
+ """
+ fields = self.get_admin_fields(response)
+ for field in fields:
+ name = field.field['name'] if isinstance(field.field, dict) else field.field.name
+ if name == field_name:
+ return field
+
+
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',),
ROOT_URLCONF="admin_views.urls",
USE_I18N=True, USE_L10N=False, LANGUAGE_CODE='en')
@@ -4029,7 +4067,7 @@ class SeleniumAdminViewsIETests(SeleniumAdminViewsFirefoxTests):
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',),
ROOT_URLCONF="admin_views.urls")
-class ReadonlyTest(TestCase):
+class ReadonlyTest(AdminFieldExtractionMixin, TestCase):
fixtures = ['admin-views-users.xml']
def setUp(self):
@@ -4126,7 +4164,7 @@ class ReadonlyTest(TestCase):
self.assertContains(response, '<p>No opinion</p>', html=True)
self.assertNotContains(response, '<p>(None)</p>')
- def test_readonly_backwards_ref(self):
+ def test_readonly_manytomany_backwards_ref(self):
"""
Regression test for #16433 - backwards references for related objects
broke if the related field is read-only due to the help_text attribute
@@ -4137,6 +4175,26 @@ class ReadonlyTest(TestCase):
response = self.client.get(reverse('admin:admin_views_topping_add'))
self.assertEqual(response.status_code, 200)
+ def test_readonly_onetoone_backwards_ref(self):
+ """
+ Can reference a reverse OneToOneField in ModelAdmin.readonly_fields.
+ """
+ v1 = Villain.objects.create(name='Adam')
+ pl = Plot.objects.create(name='Test Plot', team_leader=v1, contact=v1)
+ pd = PlotDetails.objects.create(details='Brand New Plot', plot=pl)
+
+ response = self.client.get(reverse('admin:admin_views_plotproxy_change', args=(pl.pk,)))
+ field = self.get_admin_field(response, 'plotdetails')
+ self.assertEqual(field.contents(), 'Brand New Plot')
+
+ # The reverse relation also works if the OneToOneField is null.
+ pd.plot = None
+ pd.save()
+
+ response = self.client.get(reverse('admin:admin_views_plotproxy_change', args=(pl.pk,)))
+ field = self.get_admin_field(response, 'plotdetails')
+ self.assertEqual(force_text(field.contents()), '(None)')
+
def test_readonly_field_overrides(self):
"""
Regression test for #22087 - ModelForm Meta overrides are ignored by
@@ -4832,19 +4890,19 @@ class AdminCustomSaveRelatedTests(TestCase):
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',),
ROOT_URLCONF="admin_views.urls")
-class AdminViewLogoutTest(TestCase):
+class AdminViewLogoutTests(TestCase):
fixtures = ['admin-views-users.xml']
- def setUp(self):
+ def test_logout(self):
self.client.login(username='super', password='secret')
-
- def test_client_logout_url_can_be_used_to_login(self):
response = self.client.get(reverse('admin:logout'))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'registration/logged_out.html')
self.assertEqual(response.request['PATH_INFO'], reverse('admin:logout'))
+ self.assertFalse(response.context['has_permission'])
+ self.assertNotContains(response, 'user-tools') # user-tools div shouldn't visible.
- # we are now logged out
+ def test_client_logout_url_can_be_used_to_login(self):
response = self.client.get(reverse('admin:logout'))
self.assertEqual(response.status_code, 302) # we should be redirected to the login page.
diff --git a/tests/expressions_case/tests.py b/tests/expressions_case/tests.py
index 27aef93..de1859b 100644
--- a/tests/expressions_case/tests.py
+++ b/tests/expressions_case/tests.py
@@ -8,7 +8,7 @@ from uuid import UUID
from django.core.exceptions import FieldError
from django.db import connection, models
-from django.db.models import F, Q, Max, Min, Value
+from django.db.models import F, Q, Max, Min, Sum, Value
from django.db.models.expressions import Case, When
from django.test import TestCase
from django.utils import six
@@ -119,6 +119,17 @@ class CaseExpressionTests(TestCase):
transform=attrgetter('integer', 'join_test')
)
+ def test_annotate_with_in_clause(self):
+ fk_rels = FKCaseTestModel.objects.filter(integer__in=[5])
+ self.assertQuerysetEqual(
+ CaseTestModel.objects.only('pk', 'integer').annotate(in_test=Sum(Case(
+ When(fk_rel__in=fk_rels, then=F('fk_rel__integer')),
+ default=Value(0),
+ ))).order_by('pk'),
+ [(1, 0), (2, 0), (3, 0), (2, 0), (3, 0), (3, 0), (4, 5)],
+ transform=attrgetter('integer', 'in_test')
+ )
+
def test_annotate_with_join_in_condition(self):
self.assertQuerysetEqual(
CaseTestModel.objects.annotate(join_test=Case(
diff --git a/tests/forms_tests/templates/forms_tests/article_form.html b/tests/forms_tests/templates/forms_tests/article_form.html
index de38466..8ab7a85 100644
--- a/tests/forms_tests/templates/forms_tests/article_form.html
+++ b/tests/forms_tests/templates/forms_tests/article_form.html
@@ -1,6 +1,6 @@
<html>
<body>
- <form method="post" action=".">{% csrf_token %}
+ <form method="post" action="">{% csrf_token %}
{{ form.as_p }}<br>
<input id="submit" type="submit">
</form>
diff --git a/tests/gis_tests/distapp/tests.py b/tests/gis_tests/distapp/tests.py
index bde78a8..a047980 100644
--- a/tests/gis_tests/distapp/tests.py
+++ b/tests/gis_tests/distapp/tests.py
@@ -142,7 +142,7 @@ class DistanceTest(TestCase):
"""
Test the `distance` GeoQuerySet method on geodetic coordinate systems.
"""
- tol = 2 if oracle else 5
+ tol = 2 if oracle else 4
# Testing geodetic distance calculation with a non-point geometry
# (a LineString of Wollongong and Shellharbour coords).
diff --git a/tests/gis_tests/geogapp/tests.py b/tests/gis_tests/geogapp/tests.py
index e3e97f4..e2f7dc2 100644
--- a/tests/gis_tests/geogapp/tests.py
+++ b/tests/gis_tests/geogapp/tests.py
@@ -12,7 +12,7 @@ from django.contrib.gis.measure import D
from django.test import TestCase, skipUnlessDBFeature
from django.utils._os import upath
-from ..utils import oracle, postgis
+from ..utils import postgis
if HAS_GEOS:
from .models import City, County, Zipcode
@@ -97,7 +97,9 @@ class GeographyTest(TestCase):
def test06_geography_area(self):
"Testing that Area calculations work on geography columns."
# SELECT ST_Area(poly) FROM geogapp_zipcode WHERE code='77002';
- ref_area = 5439100.95415646 if oracle else 5439084.70637573
- tol = 5
z = Zipcode.objects.area().get(code='77002')
- self.assertAlmostEqual(z.area.sq_m, ref_area, tol)
+ # Round to the nearest thousand as possible values (depending on
+ # the database and geolib) include 5439084, 5439100, 5439101.
+ rounded_value = z.area.sq_m
+ rounded_value -= z.area.sq_m % 1000
+ self.assertEqual(rounded_value, 5439000)
diff --git a/tests/gis_tests/test_geoforms.py b/tests/gis_tests/test_geoforms.py
index bcbb5f0..d7fb631 100644
--- a/tests/gis_tests/test_geoforms.py
+++ b/tests/gis_tests/test_geoforms.py
@@ -2,7 +2,7 @@ from unittest import skipUnless
from django.contrib.gis.gdal import HAS_GDAL
from django.forms import ValidationError
-from django.test import SimpleTestCase, skipUnlessDBFeature
+from django.test import SimpleTestCase, override_settings, skipUnlessDBFeature
from django.utils import six
from django.utils.html import escape
@@ -154,6 +154,7 @@ class SpecializedFieldTest(SimpleTestCase):
self.assertTrue(form_instance.is_valid())
rendered = form_instance.as_p()
self.assertIn('new MapWidget(options);', rendered)
+ self.assertIn('map_srid: 4326,', rendered)
self.assertIn('gis/js/OLMapWidget.js', str(form_instance.media))
def assertTextarea(self, geom, rendered):
@@ -163,6 +164,8 @@ class SpecializedFieldTest(SimpleTestCase):
self.assertIn('required', rendered)
self.assertIn(geom.wkt, rendered)
+ # map_srid in operlayers.html template must not be localized.
+ @override_settings(USE_L10N=True, USE_THOUSAND_SEPARATOR=True)
def test_pointfield(self):
class PointForm(forms.Form):
p = forms.PointField()
diff --git a/tests/i18n/tests.py b/tests/i18n/tests.py
index 9a20ba5..7150578 100644
--- a/tests/i18n/tests.py
+++ b/tests/i18n/tests.py
@@ -1273,6 +1273,10 @@ class TestLanguageInfo(TestCase):
def test_unknown_language_code(self):
six.assertRaisesRegex(self, KeyError, r"Unknown language code xx\.", get_language_info, 'xx')
+ with translation.override('xx'):
+ # A language with no translation catalogs should fallback to the
+ # untranslated string.
+ self.assertEqual(ugettext("Title"), "Title")
def test_unknown_only_country_code(self):
li = get_language_info('de-xx')
diff --git a/tests/migrations/test_writer.py b/tests/migrations/test_writer.py
index a6527ca..f03e84c 100644
--- a/tests/migrations/test_writer.py
+++ b/tests/migrations/test_writer.py
@@ -281,6 +281,8 @@ class WriterTests(TestCase):
SettingsReference("someapp.model", "AUTH_USER_MODEL"),
("settings.AUTH_USER_MODEL", {"from django.conf import settings"})
)
+
+ def test_serialize_iterators(self):
... 323 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