summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Johnson <me@adamj.eu>2017-06-04 22:58:24 +0100
committerTim Graham <timograham@gmail.com>2017-06-05 09:15:55 -0400
commitb7d6077517c6cb2daa5e5faf2ae9f94698c06ca9 (patch)
tree0cbaa66892979188ebf170540ec6c6b1f902a65b
parentfa8346b9a9d9e16c4b6e928648538fccf9c82a2e (diff)
[1.11.x] Fixed #28269 -- Fixed Model.__init__() crash on models with a field that has an instance only descriptor.
Regression in d2a26c1a90e837777dabdf3d67ceec4d2a70fb86. Backport of ed244199c72f5bbf33ab4547e06e69873d7271d0 from master
-rw-r--r--django/db/models/options.py14
-rw-r--r--docs/releases/1.11.3.txt3
-rw-r--r--tests/model_meta/models.py9
-rw-r--r--tests/model_meta/tests.py2
4 files changed, 24 insertions, 4 deletions
diff --git a/django/db/models/options.py b/django/db/models/options.py
index 56a7e87b70..71b80b8abb 100644
--- a/django/db/models/options.py
+++ b/django/db/models/options.py
@@ -882,7 +882,13 @@ class Options(object):
@cached_property
def _property_names(self):
"""Return a set of the names of the properties defined on the model."""
- return frozenset({
- attr for attr in
- dir(self.model) if isinstance(getattr(self.model, attr), property)
- })
+ names = []
+ for name in dir(self.model):
+ try:
+ attr = getattr(self.model, name)
+ except AttributeError:
+ pass
+ else:
+ if isinstance(attr, property):
+ names.append(name)
+ return frozenset(names)
diff --git a/docs/releases/1.11.3.txt b/docs/releases/1.11.3.txt
index 15200fafd5..ed2bf31cf5 100644
--- a/docs/releases/1.11.3.txt
+++ b/docs/releases/1.11.3.txt
@@ -12,3 +12,6 @@ Bugfixes
* Removed an incorrect deprecation warning about a missing ``renderer``
argument if a ``Widget.render()`` method accepts ``**kwargs``
(:ticket:`28265`).
+
+* Fixed a regression causing ``Model.__init__()`` to crash if a field has an
+ instance only descriptor (:ticket:`28269`).
diff --git a/tests/model_meta/models.py b/tests/model_meta/models.py
index 882ac2c9fd..bd7e7f1889 100644
--- a/tests/model_meta/models.py
+++ b/tests/model_meta/models.py
@@ -9,6 +9,13 @@ class Relation(models.Model):
pass
+class InstanceOnlyDescriptor(object):
+ def __get__(self, instance, cls=None):
+ if instance is None:
+ raise AttributeError('Instance only')
+ return 1
+
+
class AbstractPerson(models.Model):
# DATA fields
data_abstract = models.CharField(max_length=10)
@@ -43,6 +50,8 @@ class AbstractPerson(models.Model):
def test_property(self):
return 1
+ test_instance_only_descriptor = InstanceOnlyDescriptor()
+
class BasePerson(AbstractPerson):
# DATA fields
diff --git a/tests/model_meta/tests.py b/tests/model_meta/tests.py
index 265e180331..1b71c95b3e 100644
--- a/tests/model_meta/tests.py
+++ b/tests/model_meta/tests.py
@@ -276,4 +276,6 @@ class ParentListTests(SimpleTestCase):
class PropertyNamesTests(SimpleTestCase):
def test_person(self):
+ # Instance only descriptors don't appear in _property_names.
+ self.assertEqual(AbstractPerson().test_instance_only_descriptor, 1)
self.assertEqual(AbstractPerson._meta._property_names, frozenset(['pk', 'test_property']))