summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorAnssi Kääriäinen <akaariai@gmail.com>2013-08-14 11:05:01 +0300
committerAnssi Kääriäinen <akaariai@gmail.com>2013-08-22 17:24:07 +0300
commit6af05e7a0f0e4604d6a67899acaa99d73ec0dfaa (patch)
treede9bc5025ba6062a3ff71cb234c6e0c84a9daf9c /django
parent768bbf3efe0c412bced1e865e90139a0f07dc613 (diff)
Fixed model.__eq__ and __hash__ for no pk value cases
The __eq__ method now considers two instances without primary key value equal only when they have same id(). The __hash__ method raises TypeError for no primary key case. Fixed #18864, fixed #18250 Thanks to Tim Graham for docs review.
Diffstat (limited to 'django')
-rw-r--r--django/db/models/base.py13
-rw-r--r--django/forms/models.py6
2 files changed, 15 insertions, 4 deletions
diff --git a/django/db/models/base.py b/django/db/models/base.py
index 3e2ae8d425..a5b0f188b4 100644
--- a/django/db/models/base.py
+++ b/django/db/models/base.py
@@ -459,14 +459,21 @@ class Model(six.with_metaclass(ModelBase)):
return '%s object' % self.__class__.__name__
def __eq__(self, other):
- return (isinstance(other, Model) and
- self._meta.concrete_model == other._meta.concrete_model and
- self._get_pk_val() == other._get_pk_val())
+ if not isinstance(other, Model):
+ return False
+ if self._meta.concrete_model != other._meta.concrete_model:
+ return False
+ my_pk = self._get_pk_val()
+ if my_pk is None:
+ return self is other
+ return my_pk == other._get_pk_val()
def __ne__(self, other):
return not self.__eq__(other)
def __hash__(self):
+ if self._get_pk_val() is None:
+ raise TypeError("Model instances without primary key value are unhashable")
return hash(self._get_pk_val())
def __reduce__(self):
diff --git a/django/forms/models.py b/django/forms/models.py
index a5b82e521d..4c6ee9c6ed 100644
--- a/django/forms/models.py
+++ b/django/forms/models.py
@@ -631,7 +631,11 @@ class BaseModelFormSet(BaseFormSet):
seen_data = set()
for form in valid_forms:
# get data for each field of each of unique_check
- row_data = tuple([form.cleaned_data[field] for field in unique_check if field in form.cleaned_data])
+ row_data = (form.cleaned_data[field]
+ for field in unique_check if field in form.cleaned_data)
+ # Reduce Model instances to their primary key values
+ row_data = tuple(d._get_pk_val() if hasattr(d, '_get_pk_val') else d
+ for d in row_data)
if row_data and not None in row_data:
# if we've already seen it then we have a uniqueness failure
if row_data in seen_data: