[Python-modules-commits] [python-django] 01/07: Import python-django_1.9.4.orig.tar.gz
Luke Faraone
lfaraone at moszumanska.debian.org
Sat Mar 5 21:05:22 UTC 2016
This is an automated email from the git hooks/post-receive script.
lfaraone pushed a commit to branch debian/master
in repository python-django.
commit b849285b12d9ba5635c7c84b03652d81ae147dac
Author: Luke Faraone <lfaraone at debian.org>
Date: Sat Mar 5 20:10:07 2016 +0000
Import python-django_1.9.4.orig.tar.gz
---
Django.egg-info/PKG-INFO | 2 +-
Django.egg-info/SOURCES.txt | 5 +
PKG-INFO | 2 +-
django/__init__.py | 2 +-
django/contrib/admin/templates/admin/login.html | 2 +-
django/contrib/auth/base_user.py | 2 +-
django/contrib/auth/hashers.py | 77 +++++++++----
django/contrib/contenttypes/models.py | 20 ++--
django/contrib/postgres/fields/array.py | 7 +-
django/contrib/postgres/fields/ranges.py | 8 +-
django/core/checks/urls.py | 10 +-
django/core/validators.py | 9 +-
django/db/backends/base/operations.py | 2 +-
django/db/backends/postgresql/base.py | 2 +-
django/db/migrations/state.py | 2 +-
django/db/models/expressions.py | 2 +-
django/db/models/fields/__init__.py | 2 +-
django/db/models/fields/related.py | 50 ++++----
django/db/models/fields/related_descriptors.py | 2 +-
django/db/models/query.py | 8 +-
django/db/models/query_utils.py | 2 +-
django/db/models/sql/query.py | 2 +-
django/forms/boundfield.py | 2 +-
django/middleware/common.py | 2 +-
django/template/loaders/cached.py | 2 +-
django/template/response.py | 6 +-
django/test/signals.py | 2 +-
django/utils/http.py | 13 ++-
django/utils/translation/__init__.py | 7 ++
docs/conf.py | 9 ++
docs/faq/general.txt | 2 +-
docs/howto/custom-model-fields.txt | 3 +-
docs/howto/deployment/checklist.txt | 5 +-
docs/howto/deployment/wsgi/apache-auth.txt | 4 +-
docs/howto/deployment/wsgi/modwsgi.txt | 4 +-
docs/howto/outputting-pdf.txt | 6 +-
docs/internals/deprecation.txt | 3 +
docs/internals/release-process.txt | 5 +-
docs/intro/reusable-apps.txt | 6 +-
docs/intro/tutorial02.txt | 13 ++-
docs/intro/tutorial04.txt | 2 +-
docs/ref/applications.txt | 12 +-
docs/ref/class-based-views/generic-date-based.txt | 32 ++++--
docs/ref/contrib/admin/admindocs.txt | 9 --
docs/ref/contrib/admin/index.txt | 16 ++-
docs/ref/contrib/gis/feeds.txt | 4 +-
docs/ref/contrib/gis/geos.txt | 2 +-
docs/ref/contrib/gis/testing.txt | 4 +-
docs/ref/contrib/gis/tutorial.txt | 8 +-
docs/ref/csrf.txt | 61 ++++++++--
docs/ref/models/expressions.txt | 37 +++++-
docs/ref/models/fields.txt | 29 +++++
docs/ref/models/meta.txt | 4 +-
docs/ref/settings.txt | 75 +++++++-----
docs/ref/templates/builtins.txt | 5 +-
docs/ref/validators.txt | 6 +-
docs/releases/1.6.txt | 4 +-
docs/releases/1.8.10.txt | 80 +++++++++++++
docs/releases/1.8.11.txt | 8 ++
docs/releases/1.8.txt | 7 +-
docs/releases/1.9.1.txt | 2 +-
docs/releases/1.9.3.txt | 107 +++++++++++++++++
docs/releases/1.9.4.txt | 8 ++
docs/releases/index.txt | 4 +
docs/releases/security.txt | 38 ++++++
docs/spelling_wordlist | 2 +
docs/topics/auth/customizing.txt | 128 ++++++---------------
docs/topics/auth/default.txt | 2 +-
docs/topics/auth/passwords.txt | 114 ++++++++++++++++++
docs/topics/db/models.txt | 11 +-
docs/topics/db/multi-db.txt | 4 +-
docs/topics/email.txt | 2 +
docs/topics/i18n/translation.txt | 24 +---
docs/topics/security.txt | 3 +-
docs/topics/settings.txt | 11 ++
docs/topics/testing/tools.txt | 96 +++++++---------
setup.cfg | 2 +-
tests/admin_filters/tests.py | 19 ++-
tests/auth_tests/test_forms.py | 34 ++++++
tests/auth_tests/test_handlers.py | 7 +-
tests/auth_tests/test_hashers.py | 58 +++++++++-
tests/backends/tests.py | 5 +
tests/check_framework/test_urls.py | 7 ++
tests/contenttypes_tests/test_models.py | 14 ++-
tests/foreign_object/models/article.py | 13 +++
tests/foreign_object/tests.py | 13 +++
tests/forms_tests/tests/test_fields.py | 3 +
tests/forms_tests/tests/test_forms.py | 14 +++
tests/i18n/tests.py | 8 ++
tests/invalid_models_tests/test_relative_fields.py | 36 +++++-
tests/model_fields/tests.py | 66 ++++++-----
tests/postgres_tests/test_array.py | 6 +-
tests/postgres_tests/test_hstore.py | 9 +-
tests/postgres_tests/test_json.py | 6 +-
tests/postgres_tests/test_ranges.py | 11 ++
tests/queries/tests.py | 12 ++
tests/raw_query/models.py | 1 +
tests/raw_query/tests.py | 6 +
tests/requests/tests.py | 8 +-
tests/template_tests/test_loaders.py | 12 ++
tests/template_tests/test_response_deprecations.py | 42 +++++++
tests/utils_tests/test_http.py | 24 ++++
tests/validators/invalid_urls.txt | 4 +-
tests/validators/valid_urls.txt | 4 +
104 files changed, 1277 insertions(+), 442 deletions(-)
diff --git a/Django.egg-info/PKG-INFO b/Django.egg-info/PKG-INFO
index 72647a0..265a382 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.9.2
+Version: 1.9.4
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 9fd152c..cedc787 100644
--- a/Django.egg-info/SOURCES.txt
+++ b/Django.egg-info/SOURCES.txt
@@ -3487,6 +3487,8 @@ docs/releases/1.7.8.txt
docs/releases/1.7.9.txt
docs/releases/1.7.txt
docs/releases/1.8.1.txt
+docs/releases/1.8.10.txt
+docs/releases/1.8.11.txt
docs/releases/1.8.2.txt
docs/releases/1.8.3.txt
docs/releases/1.8.4.txt
@@ -3498,6 +3500,8 @@ docs/releases/1.8.9.txt
docs/releases/1.8.txt
docs/releases/1.9.1.txt
docs/releases/1.9.2.txt
+docs/releases/1.9.3.txt
+docs/releases/1.9.4.txt
docs/releases/1.9.txt
docs/releases/index.txt
docs/releases/security.txt
@@ -4980,6 +4984,7 @@ tests/template_tests/test_logging.py
tests/template_tests/test_nodelist.py
tests/template_tests/test_parser.py
tests/template_tests/test_response.py
+tests/template_tests/test_response_deprecations.py
tests/template_tests/test_smartif.py
tests/template_tests/test_unicode.py
tests/template_tests/tests.py
diff --git a/PKG-INFO b/PKG-INFO
index 72647a0..265a382 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: Django
-Version: 1.9.2
+Version: 1.9.4
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 3dbe18f..e0c468f 100644
--- a/django/__init__.py
+++ b/django/__init__.py
@@ -1,6 +1,6 @@
from django.utils.version import get_version
-VERSION = (1, 9, 2, 'final', 0)
+VERSION = (1, 9, 4, 'final', 0)
__version__ = get_version(VERSION)
diff --git a/django/contrib/admin/templates/admin/login.html b/django/contrib/admin/templates/admin/login.html
index 7a0d650..adb58d6 100644
--- a/django/contrib/admin/templates/admin/login.html
+++ b/django/contrib/admin/templates/admin/login.html
@@ -34,7 +34,7 @@
{% if user.is_authenticated %}
<p class="errornote">
-{% blocktrans with username=request.user.username trimmed %}
+{% blocktrans with username=request.user.get_username trimmed %}
You are authenticated as {{ username }}, but are not authorized to
access this page. Would you like to login to a different account?
{% endblocktrans %}
diff --git a/django/contrib/auth/base_user.py b/django/contrib/auth/base_user.py
index 31fec4f..48ab950 100644
--- a/django/contrib/auth/base_user.py
+++ b/django/contrib/auth/base_user.py
@@ -19,7 +19,7 @@ class BaseUserManager(models.Manager):
@classmethod
def normalize_email(cls, email):
"""
- Normalize the email address by lowercasing the domain part of the it.
+ Normalize the email address by lowercasing the domain part of it.
"""
email = email or ''
try:
diff --git a/django/contrib/auth/hashers.py b/django/contrib/auth/hashers.py
index 93d4598..05ac849 100644
--- a/django/contrib/auth/hashers.py
+++ b/django/contrib/auth/hashers.py
@@ -4,6 +4,7 @@ import base64
import binascii
import hashlib
import importlib
+import warnings
from collections import OrderedDict
from django.conf import settings
@@ -46,10 +47,17 @@ def check_password(password, encoded, setter=None, preferred='default'):
preferred = get_hasher(preferred)
hasher = identify_hasher(encoded)
- must_update = hasher.algorithm != preferred.algorithm
- if not must_update:
- must_update = preferred.must_update(encoded)
+ hasher_changed = hasher.algorithm != preferred.algorithm
+ must_update = hasher_changed or preferred.must_update(encoded)
is_correct = hasher.verify(password, encoded)
+
+ # If the hasher didn't change (we don't protect against enumeration if it
+ # does) and the password should get updated, try to close the timing gap
+ # between the work factor of the current encoded password and the default
+ # work factor.
+ if not is_correct and not hasher_changed and must_update:
+ hasher.harden_runtime(password, encoded)
+
if setter and is_correct and must_update:
setter(password)
return is_correct
@@ -216,6 +224,19 @@ class BasePasswordHasher(object):
def must_update(self, encoded):
return False
+ def harden_runtime(self, password, encoded):
+ """
+ Bridge the runtime gap between the work factor supplied in `encoded`
+ and the work factor suggested by this hasher.
+
+ Taking PBKDF2 as an example, if `encoded` contains 20000 iterations and
+ `self.iterations` is 30000, this method should run password through
+ another 10000 iterations of PBKDF2. Similar approaches should exist
+ for any hasher that has a work factor. If not, this method should be
+ defined as a no-op to silence the warning.
+ """
+ warnings.warn('subclasses of BasePasswordHasher should provide a harden_runtime() method')
+
class PBKDF2PasswordHasher(BasePasswordHasher):
"""
@@ -258,6 +279,12 @@ class PBKDF2PasswordHasher(BasePasswordHasher):
algorithm, iterations, salt, hash = encoded.split('$', 3)
return int(iterations) != self.iterations
+ def harden_runtime(self, password, encoded):
+ algorithm, iterations, salt, hash = encoded.split('$', 3)
+ extra_iterations = self.iterations - int(iterations)
+ if extra_iterations > 0:
+ self.encode(password, salt, extra_iterations)
+
class PBKDF2SHA1PasswordHasher(PBKDF2PasswordHasher):
"""
@@ -308,23 +335,8 @@ class BCryptSHA256PasswordHasher(BasePasswordHasher):
def verify(self, password, encoded):
algorithm, data = encoded.split('$', 1)
assert algorithm == self.algorithm
- bcrypt = self._load_library()
-
- # Hash the password prior to using bcrypt to prevent password truncation
- # See: https://code.djangoproject.com/ticket/20138
- if self.digest is not None:
- # We use binascii.hexlify here because Python3 decided that a hex encoded
- # bytestring is somehow a unicode.
- password = binascii.hexlify(self.digest(force_bytes(password)).digest())
- else:
- password = force_bytes(password)
-
- # Ensure that our data is a bytestring
- data = force_bytes(data)
- # force_bytes() necessary for py-bcrypt compatibility
- hashpw = force_bytes(bcrypt.hashpw(password, data))
-
- return constant_time_compare(data, hashpw)
+ encoded_2 = self.encode(password, force_bytes(data))
+ return constant_time_compare(encoded, encoded_2)
def safe_summary(self, encoded):
algorithm, empty, algostr, work_factor, data = encoded.split('$', 4)
@@ -341,6 +353,16 @@ class BCryptSHA256PasswordHasher(BasePasswordHasher):
algorithm, empty, algostr, rounds, data = encoded.split('$', 4)
return int(rounds) != self.rounds
+ def harden_runtime(self, password, encoded):
+ _, data = encoded.split('$', 1)
+ salt = data[:29] # Length of the salt in bcrypt.
+ rounds = data.split('$')[2]
+ # work factor is logarithmic, adding one doubles the load.
+ diff = 2**(self.rounds - int(rounds)) - 1
+ while diff > 0:
+ self.encode(password, force_bytes(salt))
+ diff -= 1
+
class BCryptPasswordHasher(BCryptSHA256PasswordHasher):
"""
@@ -388,6 +410,9 @@ class SHA1PasswordHasher(BasePasswordHasher):
(_('hash'), mask_hash(hash)),
])
+ def harden_runtime(self, password, encoded):
+ pass
+
class MD5PasswordHasher(BasePasswordHasher):
"""
@@ -416,6 +441,9 @@ class MD5PasswordHasher(BasePasswordHasher):
(_('hash'), mask_hash(hash)),
])
+ def harden_runtime(self, password, encoded):
+ pass
+
class UnsaltedSHA1PasswordHasher(BasePasswordHasher):
"""
@@ -448,6 +476,9 @@ class UnsaltedSHA1PasswordHasher(BasePasswordHasher):
(_('hash'), mask_hash(hash)),
])
+ def harden_runtime(self, password, encoded):
+ pass
+
class UnsaltedMD5PasswordHasher(BasePasswordHasher):
"""
@@ -481,6 +512,9 @@ class UnsaltedMD5PasswordHasher(BasePasswordHasher):
(_('hash'), mask_hash(encoded, show=3)),
])
+ def harden_runtime(self, password, encoded):
+ pass
+
class CryptPasswordHasher(BasePasswordHasher):
"""
@@ -515,3 +549,6 @@ class CryptPasswordHasher(BasePasswordHasher):
(_('salt'), salt),
(_('hash'), mask_hash(data, show=3)),
])
+
+ def harden_runtime(self, password, encoded):
+ pass
diff --git a/django/contrib/contenttypes/models.py b/django/contrib/contenttypes/models.py
index 27a5388..8d459f6 100644
--- a/django/contrib/contenttypes/models.py
+++ b/django/contrib/contenttypes/models.py
@@ -13,13 +13,15 @@ from django.utils.translation import ugettext_lazy as _
class ContentTypeManager(models.Manager):
use_in_migrations = True
- # Cache to avoid re-looking up ContentType objects all over the place.
- # This cache is shared by all the get_for_* methods.
- _cache = {}
+ def __init__(self, *args, **kwargs):
+ super(ContentTypeManager, self).__init__(*args, **kwargs)
+ # Cache shared by all the get_for_* methods to speed up
+ # ContentType retrieval.
+ self._cache = {}
def get_by_natural_key(self, app_label, model):
try:
- ct = self.__class__._cache[self.db][(app_label, model)]
+ ct = self._cache[self.db][(app_label, model)]
except KeyError:
ct = self.get(app_label=app_label, model=model)
self._add_to_cache(self.db, ct)
@@ -34,7 +36,7 @@ class ContentTypeManager(models.Manager):
def _get_from_cache(self, opts):
key = (opts.app_label, opts.model_name)
- return self.__class__._cache[self.db][key]
+ return self._cache[self.db][key]
def create(self, **kwargs):
if 'name' in kwargs:
@@ -129,7 +131,7 @@ class ContentTypeManager(models.Manager):
(though ContentTypes are obviously not created on-the-fly by get_by_id).
"""
try:
- ct = self.__class__._cache[self.db][id]
+ ct = self._cache[self.db][id]
except KeyError:
# This could raise a DoesNotExist; that's correct behavior and will
# make sure that only correct ctypes get stored in the cache dict.
@@ -144,15 +146,15 @@ class ContentTypeManager(models.Manager):
django.contrib.contenttypes.management.update_contenttypes for where
this gets called).
"""
- self.__class__._cache.clear()
+ self._cache.clear()
def _add_to_cache(self, using, ct):
"""Insert a ContentType into the cache."""
# Note it's possible for ContentType objects to be stale; model_class() will return None.
# Hence, there is no reliance on model._meta.app_label here, just using the model fields instead.
key = (ct.app_label, ct.model)
- self.__class__._cache.setdefault(using, {})[key] = ct
- self.__class__._cache.setdefault(using, {})[ct.id] = ct
+ self._cache.setdefault(using, {})[key] = ct
+ self._cache.setdefault(using, {})[ct.id] = ct
@python_2_unicode_compatible
diff --git a/django/contrib/postgres/fields/array.py b/django/contrib/postgres/fields/array.py
index 65f2867..28e592c 100644
--- a/django/contrib/postgres/fields/array.py
+++ b/django/contrib/postgres/fields/array.py
@@ -107,8 +107,11 @@ class ArrayField(Field):
base_field = self.base_field
for val in vals:
- obj = AttributeSetter(base_field.attname, val)
- values.append(base_field.value_to_string(obj))
+ if val is None:
+ values.append(None)
+ else:
+ obj = AttributeSetter(base_field.attname, val)
+ values.append(base_field.value_to_string(obj))
return json.dumps(values)
def get_transform(self, name):
diff --git a/django/contrib/postgres/fields/ranges.py b/django/contrib/postgres/fields/ranges.py
index bf3f8cb..5bce074 100644
--- a/django/contrib/postgres/fields/ranges.py
+++ b/django/contrib/postgres/fields/ranges.py
@@ -51,8 +51,12 @@ class RangeField(models.Field):
base_field = self.base_field
result = {"bounds": value._bounds}
for end in ('lower', 'upper'):
- obj = AttributeSetter(base_field.attname, getattr(value, end))
- result[end] = base_field.value_to_string(obj)
+ val = getattr(value, end)
+ if val is None:
+ result[end] = None
+ else:
+ obj = AttributeSetter(base_field.attname, val)
+ result[end] = base_field.value_to_string(obj)
return json.dumps(result)
def formfield(self, **kwargs):
diff --git a/django/core/checks/urls.py b/django/core/checks/urls.py
index d2aac61..387d2b4 100644
--- a/django/core/checks/urls.py
+++ b/django/core/checks/urls.py
@@ -1,13 +1,17 @@
from __future__ import unicode_literals
+from django.conf import settings
+
from . import Tags, Warning, register
@register(Tags.urls)
def check_url_config(app_configs, **kwargs):
- from django.core.urlresolvers import get_resolver
- resolver = get_resolver()
- return check_resolver(resolver)
+ if getattr(settings, 'ROOT_URLCONF', None):
+ from django.core.urlresolvers import get_resolver
+ resolver = get_resolver()
+ return check_resolver(resolver)
+ return []
def check_resolver(resolver):
diff --git a/django/core/validators.py b/django/core/validators.py
index 69cc76f..852ff49 100644
--- a/django/core/validators.py
+++ b/django/core/validators.py
@@ -85,7 +85,14 @@ class URLValidator(RegexValidator):
# Host patterns
hostname_re = r'[a-z' + ul + r'0-9](?:[a-z' + ul + r'0-9-]*[a-z' + ul + r'0-9])?'
domain_re = r'(?:\.(?!-)[a-z' + ul + r'0-9-]+(?<!-))*'
- tld_re = r'\.(?:[a-z' + ul + r']{2,}|xn--[a-z0-9]+)\.?'
+ tld_re = (
+ '\.' # dot
+ '(?!-)' # can't start with a dash
+ '(?:[a-z' + ul + '-]{2,}' # domain label
+ '|xn--[a-z0-9]+)' # or punycode label
+ '(?<!-)' # can't end with a dash
+ '\.?' # may have a trailing dot
+ )
host_re = '(' + hostname_re + domain_re + tld_re + '|localhost)'
regex = _lazy_re_compile(
diff --git a/django/db/backends/base/operations.py b/django/db/backends/base/operations.py
index 6e5aff1..acca127 100644
--- a/django/db/backends/base/operations.py
+++ b/django/db/backends/base/operations.py
@@ -485,7 +485,7 @@ class BaseDatabaseOperations(object):
raise ValueError("Django does not support timezone-aware times.")
return six.text_type(value)
- def adapt_decimalfield_value(self, value, max_digits, decimal_places):
+ def adapt_decimalfield_value(self, value, max_digits=None, decimal_places=None):
"""
Transforms a decimal.Decimal value to an object compatible with what is
expected by the backend driver for decimal (numeric) columns.
diff --git a/django/db/backends/postgresql/base.py b/django/db/backends/postgresql/base.py
index 383601e..6a53648 100644
--- a/django/db/backends/postgresql/base.py
+++ b/django/db/backends/postgresql/base.py
@@ -196,7 +196,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
conn_timezone_name = self.connection.get_parameter_status('TimeZone')
- if conn_timezone_name != self.timezone_name:
+ if self.timezone_name and conn_timezone_name != self.timezone_name:
cursor = self.connection.cursor()
try:
cursor.execute(self.ops.set_time_zone_sql(), [self.timezone_name])
diff --git a/django/db/migrations/state.py b/django/db/migrations/state.py
index 2365e39..117f320 100644
--- a/django/db/migrations/state.py
+++ b/django/db/migrations/state.py
@@ -245,7 +245,7 @@ class StateApps(Apps):
"""
def extract_field(operation):
# operation is annotated with the field in
- # apps.register.Apps.lazy_model_operation().
+ # apps.registry.Apps.lazy_model_operation().
return getattr(operation, 'field', None)
def extract_field_names(operations):
diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py
index f03a273..b558668 100644
--- a/django/db/models/expressions.py
+++ b/django/db/models/expressions.py
@@ -210,7 +210,7 @@ class BaseExpression(object):
])
return c
- def _prepare(self):
+ def _prepare(self, field):
"""
Hook used by Field.get_prep_lookup() to do custom preparation.
"""
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index 9449904..df2e3b4 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -732,7 +732,7 @@ class Field(RegisterLookupMixin):
Perform preliminary non-db specific lookup checks and conversions
"""
if hasattr(value, '_prepare'):
- return value._prepare()
+ return value._prepare(self)
if lookup_type in {
'iexact', 'contains', 'icontains',
diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
index ff820ae..5d9b881 100644
--- a/django/db/models/fields/related.py
+++ b/django/db/models/fields/related.py
@@ -8,6 +8,7 @@ from django.apps import apps
from django.core import checks, exceptions
from django.db import connection, router
from django.db.backends import utils
+from django.db.models import Q
from django.db.models.deletion import CASCADE, SET_DEFAULT, SET_NULL
from django.db.models.query_utils import PathInfo
from django.db.models.utils import make_model_tuple
@@ -39,7 +40,7 @@ from .reverse_related import (
RECURSIVE_RELATIONSHIP_CONSTANT = 'self'
-def resolve_relation(scope_model, relation, resolve_recursive_relationship=True):
+def resolve_relation(scope_model, relation):
"""
Transform relation into a model or fully-qualified model string of the form
"app_label.ModelName", relative to scope_model.
@@ -54,11 +55,12 @@ def resolve_relation(scope_model, relation, resolve_recursive_relationship=True)
"""
# Check for recursive relations
if relation == RECURSIVE_RELATIONSHIP_CONSTANT:
- if resolve_recursive_relationship:
- relation = scope_model
+ relation = scope_model
+
# Look for an "app.Model" relation
- elif isinstance(relation, six.string_types) and '.' not in relation:
- relation = "%s.%s" % (scope_model._meta.app_label, relation)
+ if isinstance(relation, six.string_types):
+ if "." not in relation:
+ relation = "%s.%s" % (scope_model._meta.app_label, relation)
return relation
@@ -196,12 +198,6 @@ class RelatedField(Field):
if not isinstance(self.remote_field.model, ModelBase):
return []
- # If the field doesn't install backward relation on the target model (so
- # `is_hidden` returns True), then there are no clashes to check and we
- # can skip these fields.
- if self.remote_field.is_hidden():
- return []
-
# Consider that we are checking field `Model.foreign` and the models
# are:
#
@@ -213,12 +209,15 @@ class RelatedField(Field):
# foreign = models.ForeignKey(Target)
# m2m = models.ManyToManyField(Target)
- rel_opts = self.remote_field.model._meta
# rel_opts.object_name == "Target"
+ rel_opts = self.remote_field.model._meta
+ # If the field doesn't install a backward relation on the target model
+ # (so `is_hidden` returns True), then there are no clashes to check
+ # and we can skip these fields.
+ rel_is_hidden = self.remote_field.is_hidden()
rel_name = self.remote_field.get_accessor_name() # i. e. "model_set"
rel_query_name = self.related_query_name() # i. e. "model"
- field_name = "%s.%s" % (opts.object_name,
- self.name) # i. e. "Model.field"
+ field_name = "%s.%s" % (opts.object_name, self.name) # i. e. "Model.field"
# Check clashes between accessor or reverse query name of `field`
# and any other field name -- i.e. accessor for Model.foreign is
@@ -227,7 +226,7 @@ class RelatedField(Field):
for clash_field in potential_clashes:
clash_name = "%s.%s" % (rel_opts.object_name,
clash_field.name) # i. e. "Target.model_set"
- if clash_field.name == rel_name:
+ if not rel_is_hidden and clash_field.name == rel_name:
errors.append(
checks.Error(
"Reverse accessor for '%s' clashes with field name '%s'." % (field_name, clash_name),
@@ -257,7 +256,7 @@ class RelatedField(Field):
clash_name = "%s.%s" % ( # i. e. "Model.m2m"
clash_field.related_model._meta.object_name,
clash_field.field.name)
- if clash_field.get_accessor_name() == rel_name:
+ if not rel_is_hidden and clash_field.get_accessor_name() == rel_name:
errors.append(
checks.Error(
"Reverse accessor for '%s' clashes with reverse accessor for '%s'." % (field_name, clash_name),
@@ -305,11 +304,6 @@ class RelatedField(Field):
field.remote_field.model = related
field.do_related_class(related, model)
lazy_related_operation(resolve_related_class, cls, self.remote_field.model, field=self)
- else:
- # Bind a lazy reference to the app in which the model is defined.
- self.remote_field.model = resolve_relation(
- cls, self.remote_field.model, resolve_recursive_relationship=False
- )
def get_forward_related_filter(self, obj):
"""
@@ -335,8 +329,13 @@ class RelatedField(Field):
rh_field.attname: getattr(obj, lh_field.attname)
for lh_field, rh_field in self.related_fields
}
- base_filter.update(self.get_extra_descriptor_filter(obj) or {})
- return base_filter
+ descriptor_filter = self.get_extra_descriptor_filter(obj)
+ base_q = Q(**base_filter)
+ if isinstance(descriptor_filter, dict):
+ return base_q & Q(**descriptor_filter)
+ elif descriptor_filter:
+ return base_q & descriptor_filter
+ return base_q
@property
def swappable_setting(self):
@@ -1581,11 +1580,6 @@ class ManyToManyField(RelatedField):
lazy_related_operation(resolve_through_model, cls, self.remote_field.through, field=self)
elif not cls._meta.swapped:
self.remote_field.through = create_many_to_many_intermediary_model(self, cls)
- else:
- # Bind a lazy reference to the app in which the model is defined.
- self.remote_field.through = resolve_relation(
- cls, self.remote_field.through, resolve_recursive_relationship=False
- )
# Add the descriptor for the m2m relation.
setattr(cls, self.name, ManyToManyDescriptor(self.remote_field, reverse=False))
diff --git a/django/db/models/fields/related_descriptors.py b/django/db/models/fields/related_descriptors.py
index e9caa26..abfa728 100644
--- a/django/db/models/fields/related_descriptors.py
+++ b/django/db/models/fields/related_descriptors.py
@@ -164,7 +164,7 @@ class ForwardManyToOneDescriptor(object):
rel_obj = None
else:
qs = self.get_queryset(instance=instance)
- qs = qs.filter(**self.field.get_reverse_related_filter(instance))
+ qs = qs.filter(self.field.get_reverse_related_filter(instance))
# Assuming the database enforces foreign keys, this won't fail.
rel_obj = qs.get()
# If this is a one-to-one relation, set the reverse accessor
diff --git a/django/db/models/query.py b/django/db/models/query.py
index 852a5ba..cb02085 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -1107,12 +1107,18 @@ class QuerySet(object):
for field, objects in other._known_related_objects.items():
self._known_related_objects.setdefault(field, {}).update(objects)
- def _prepare(self):
+ def _prepare(self, field):
if self._fields is not None:
# values() queryset can only be used as nested queries
# if they are set up to select only a single field.
if len(self._fields or self.model._meta.concrete_fields) > 1:
raise TypeError('Cannot use multi-field values as a filter value.')
+ else:
+ # If the query is used as a subquery for a ForeignKey with non-pk
+ # target field, make sure to select the target field in the subquery.
+ foreign_fields = getattr(field, 'foreign_related_fields', ())
+ if len(foreign_fields) == 1 and not foreign_fields[0].primary_key:
+ return self.values(foreign_fields[0].name)
return self
def _as_sql(self, connection):
diff --git a/django/db/models/query_utils.py b/django/db/models/query_utils.py
index b25b408..195e8f4 100644
--- a/django/db/models/query_utils.py
+++ b/django/db/models/query_utils.py
@@ -45,7 +45,7 @@ class QueryWrapper(object):
class Q(tree.Node):
"""
Encapsulates filters as objects that can then be combined logically (using
- & and |).
+ `&` and `|`).
"""
# Connection types
AND = 'AND'
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index 2b446b9..29fe885 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -244,7 +244,7 @@ class Query(object):
memo[id(self)] = result
return result
- def _prepare(self):
+ def _prepare(self, field):
return self
def get_compiler(self, using=None, connection=None):
diff --git a/django/forms/boundfield.py b/django/forms/boundfield.py
index bcfe2e2..6567c4f 100644
--- a/django/forms/boundfield.py
+++ b/django/forms/boundfield.py
@@ -60,7 +60,7 @@ class BoundField(object):
def __getitem__(self, idx):
# Prevent unnecessary reevaluation when accessing BoundField's attrs
# from templates.
- if not isinstance(idx, six.integer_types):
+ if not isinstance(idx, six.integer_types + (slice,)):
raise TypeError
return list(self.__iter__())[idx]
diff --git a/django/middleware/common.py b/django/middleware/common.py
index a8958a8..50acf32 100644
--- a/django/middleware/common.py
+++ b/django/middleware/common.py
@@ -85,7 +85,7 @@ class CommonMiddleware(object):
Return the full path of the request with a trailing slash appended.
Raise a RuntimeError if settings.DEBUG is True and request.method is
- GET, PUT, or PATCH.
+ POST, PUT, or PATCH.
"""
new_path = request.get_full_path(force_append_slash=True)
if settings.DEBUG and request.method in ('POST', 'PUT', 'PATCH'):
diff --git a/django/template/loaders/cached.py b/django/template/loaders/cached.py
index c13346b..5bf5c10 100644
--- a/django/template/loaders/cached.py
+++ b/django/template/loaders/cached.py
@@ -131,7 +131,7 @@ class Loader(BaseLoader):
template_tuple = self.template_cache.get(key)
# A cached previous failure:
if template_tuple is TemplateDoesNotExist:
- raise TemplateDoesNotExist
+ raise TemplateDoesNotExist(template_name)
elif template_tuple is None:
template, origin = self.find_template(template_name, template_dirs)
if not hasattr(template, 'render'):
diff --git a/django/template/response.py b/django/template/response.py
index 17b6066..a30d982 100644
--- a/django/template/response.py
+++ b/django/template/response.py
@@ -4,7 +4,7 @@ from django.http import HttpResponse
from django.utils import six
from django.utils.deprecation import RemovedInDjango110Warning
-from .backends.django import Template as BackendTemplate
+from .backends.django import DjangoTemplates, Template as BackendTemplate
from .base import Template
from .context import Context, RequestContext, _current_app_undefined
from .loader import get_template, select_template
@@ -25,7 +25,7 @@ class SimpleTemplateResponse(HttpResponse):
"anymore. It may be a backend-specific template like those "
"created by get_template().".format(self.__class__.__name__),
RemovedInDjango110Warning, stacklevel=2)
- template = BackendTemplate(template)
+ template = BackendTemplate(template, DjangoTemplates)
# It would seem obvious to call these next two members 'template' and
# 'context', but those names are reserved as part of the test Client
@@ -95,7 +95,7 @@ class SimpleTemplateResponse(HttpResponse):
"{}.".format(
self.__class__.__name__, new_template.__class__.__name__),
RemovedInDjango110Warning, stacklevel=2)
- new_template = BackendTemplate(new_template)
+ new_template = BackendTemplate(new_template, DjangoTemplates)
return new_template
def resolve_context(self, context):
diff --git a/django/test/signals.py b/django/test/signals.py
index f783663..bb04af6 100644
--- a/django/test/signals.py
+++ b/django/test/signals.py
@@ -69,7 +69,7 @@ def update_connections_time_zone(**kwargs):
except AttributeError:
pass
tz_sql = conn.ops.set_time_zone_sql()
- if tz_sql:
+ if tz_sql and conn.timezone_name:
with conn.cursor() as cursor:
cursor.execute(tz_sql, [conn.timezone_name])
diff --git a/django/utils/http.py b/django/utils/http.py
index 70bcbd9..62e854d 100644
--- a/django/utils/http.py
+++ b/django/utils/http.py
@@ -290,8 +290,17 @@ def is_safe_url(url, host=None):
url = url.strip()
if not url:
return False
- # Chrome treats \ completely as /
- url = url.replace('\\', '/')
+ if six.PY2:
+ try:
+ url = force_text(url)
+ except UnicodeDecodeError:
+ return False
+ # Chrome treats \ completely as / in paths but it could be part of some
+ # basic auth credentials so we need to check both URLs.
+ return _is_safe_url(url, host) and _is_safe_url(url.replace('\\', '/'), host)
+
+
+def _is_safe_url(url, host):
# Chrome considers any URL with more than two slashes to be absolute, but
# urlparse is not so flexible. Treat any url with three slashes as unsafe.
if url.startswith('///'):
diff --git a/django/utils/translation/__init__.py b/django/utils/translation/__init__.py
index 7311a61..9b66493 100644
--- a/django/utils/translation/__init__.py
+++ b/django/utils/translation/__init__.py
@@ -106,6 +106,8 @@ def lazy_number(func, resultclass, number=None, **kwargs):
kwargs['number'] = number
proxy = lazy(func, resultclass)(**kwargs)
else:
+ original_kwargs = kwargs.copy()
+
class NumberAwareString(resultclass):
def __mod__(self, rhs):
if isinstance(rhs, dict) and number:
@@ -128,9 +130,14 @@ def lazy_number(func, resultclass, number=None, **kwargs):
return translated
proxy = lazy(lambda **kwargs: NumberAwareString(), NumberAwareString)(**kwargs)
+ proxy.__reduce__ = lambda: (_lazy_number_unpickle, (func, resultclass, number, original_kwargs))
return proxy
+def _lazy_number_unpickle(func, resultclass, number, kwargs):
+ return lazy_number(func, resultclass, number=number, **kwargs)
+
+
def ngettext_lazy(singular, plural, number=None):
return lazy_number(ngettext, str, singular=singular, plural=plural, number=number)
diff --git a/docs/conf.py b/docs/conf.py
index b23f62d..b146392 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -16,6 +16,15 @@ from __future__ import unicode_literals
import sys
from os.path import abspath, dirname, join
+# Workaround for sphinx-build recursion limit overflow:
+# pickle.dump(doctree, f, pickle.HIGHEST_PROTOCOL)
+# RuntimeError: maximum recursion depth exceeded while pickling an object
+#
+# Python's default allowed recursion depth is 1000 but this isn't enough for
+# building docs/ref/settings.txt sometimes.
+# https://groups.google.com/d/topic/sphinx-dev/MtRf64eGtv4/discussion
+sys.setrecursionlimit(2000)
+
# Make sure we get the version of this copy of Django
sys.path.insert(1, dirname(dirname(abspath(__file__))))
diff --git a/docs/faq/general.txt b/docs/faq/general.txt
index cb31e8b..22d37fe 100644
--- a/docs/faq/general.txt
+++ b/docs/faq/general.txt
@@ -32,7 +32,7 @@ thrilled to be able to give something back to the open-source community.
What does "Django" mean, and how do you pronounce it?
=====================================================
-Django is named after `Django Reinhardt`_, a gypsy jazz guitarist from the 1930s
+Django is named after `Django Reinhardt`_, a jazz manouche guitarist from the 1930s
to early 1950s. To this day, he's considered one of the best guitarists of all time.
Listen to his music. You'll like it.
diff --git a/docs/howto/custom-model-fields.txt b/docs/howto/custom-model-fields.txt
index 375b4c1..3485c8a 100644
--- a/docs/howto/custom-model-fields.txt
+++ b/docs/howto/custom-model-fields.txt
@@ -464,6 +464,7 @@ instances::
from django.core.exceptions import ValidationError
from django.db import models
+ from django.utils.translation import ugettext_lazy as _
def parse_hand(hand_string):
"""Takes a string of cards and splits into a full hand."""
@@ -471,7 +472,7 @@ instances::
p2 = re.compile('..')
args = [p2.findall(x) for x in p1.findall(hand_string)]
if len(args) != 4:
- raise ValidationError("Invalid input for a Hand instance")
+ raise ValidationError(_("Invalid input for a Hand instance"))
return Hand(*args)
class HandField(models.Field):
diff --git a/docs/howto/deployment/checklist.txt b/docs/howto/deployment/checklist.txt
index 5971719..5effdb7 100644
--- a/docs/howto/deployment/checklist.txt
+++ b/docs/howto/deployment/checklist.txt
@@ -254,8 +254,9 @@ Python Options
==============
It's strongly recommended that you invoke the Python process running your
-Django application using the `-R`_ option or with the
-:envvar:`PYTHONHASHSEED` environment variable set to ``random``.
+Django application using the `-R`_ option or with the :envvar:`PYTHONHASHSEED`
+environment variable set to ``random``. This option is enabled by default
+starting with Python 3.3.
These options help protect your site from denial-of-service (DoS)
attacks triggered by carefully crafted inputs. Such an attack can
diff --git a/docs/howto/deployment/wsgi/apache-auth.txt b/docs/howto/deployment/wsgi/apache-auth.txt
index 9246c08..e6fea98 100644
--- a/docs/howto/deployment/wsgi/apache-auth.txt
+++ b/docs/howto/deployment/wsgi/apache-auth.txt
@@ -97,8 +97,8 @@ Requests beginning with ``/secret/`` will now require a user to authenticate.
The mod_wsgi `access control mechanisms documentation`_ provides additional
details and information about alternative methods of authentication.
-.. _Defining Application Groups: https://code.google.com/p/modwsgi/wiki/ConfigurationGuidelines#Defining_Application_Groups
-.. _access control mechanisms documentation: https://code.google.com/p/modwsgi/wiki/AccessControlMechanisms
+.. _Defining Application Groups: https://modwsgi.readthedocs.org/en/develop/user-guides/configuration-guidelines.html#defining-application-groups
+.. _access control mechanisms documentation: https://modwsgi.readthedocs.org/en/develop/user-guides/access-control-mechanisms.html
Authorization with ``mod_wsgi`` and Django groups
-------------------------------------------------
diff --git a/docs/howto/deployment/wsgi/modwsgi.txt b/docs/howto/deployment/wsgi/modwsgi.txt
index a3d5e8a..988ff8a 100644
--- a/docs/howto/deployment/wsgi/modwsgi.txt
+++ b/docs/howto/deployment/wsgi/modwsgi.txt
@@ -140,7 +140,7 @@ to the configuration above:
See the official mod_wsgi documentation for `details on setting up daemon
mode`_.
-.. _details on setting up daemon mode: https://code.google.com/p/modwsgi/wiki/QuickConfigurationGuide#Delegation_To_Daemon_Process
+.. _details on setting up daemon mode: https://modwsgi.readthedocs.org/en/develop/user-guides/quick-configuration-guide.html#delegation-to-daemon-process
.. _serving-files:
@@ -198,7 +198,7 @@ If you are using a version of Apache older than 2.4, replace
.. More details on configuring a mod_wsgi site to serve static files can be found
.. in the mod_wsgi documentation on `hosting static files`_.
-.. _hosting static files: https://code.google.com/p/modwsgi/wiki/ConfigurationGuidelines#Hosting_Of_Static_Files
+.. _hosting static files: https://modwsgi.readthedocs.org/en/develop/user-guides/configuration-guidelines.html#hosting-of-static-files
.. _serving-the-admin-files:
... 2701 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