Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Made Model.__eq__ consider proxy models equivalent

Fixed #11892, fixed #16458, fixed #14492.
  • Loading branch information...
commit 4668c142dce77c6f29fb75532c1acfa1b2d322ff 1 parent 4090982
@akaariai akaariai authored
View
4 django/db/models/base.py
@@ -459,7 +459,9 @@ def __str__(self):
return '%s object' % self.__class__.__name__
def __eq__(self, other):
- return isinstance(other, self.__class__) and self._get_pk_val() == other._get_pk_val()
+ return (isinstance(other, Model) and
+ self._meta.concrete_model == other._meta.concrete_model and
+ self._get_pk_val() == other._get_pk_val())
def __ne__(self, other):
return not self.__eq__(other)
View
34 docs/ref/models/instances.txt
@@ -494,6 +494,40 @@ using ``__str__()`` like this::
# first_name and last_name will be unicode strings.
return force_bytes('%s %s' % (self.first_name, self.last_name))
+``__eq__``
+----------
+
+.. method:: Model.__eq__()
+
+The equality method is defined such that instances with the same primary
+key value and the same concrete class are considered equal. The term
+concrete class means proxy model's first non-proxy parent or the class
+itself if it isn't a proxy class.
+
+For example::
+
+ form django.db import models
+
+ class MyModel(models.Model):
+ id = models.AutoField(primary_key=True)
+
+ class MyProxyModel(MyModel):
+ class Meta:
+ proxy = True
+
+ class MultitableInherited(MyModel):
+ pass
+
+ MyModel(id=1) == MyModel(id=1)
+ MyModel(id=1) == MyProxyModel(id=1)
+ MyModel(id=1) != MultitableInherited(id=1)
+ MyModel(id=1) != MyModel(id=2)
+
+.. versionchanged:: 1.7
+
+ In previous versions only instances of the exact same class and same
+ primary key value were considered equal.
+
``get_absolute_url``
--------------------
View
5 docs/releases/1.7.txt
@@ -194,6 +194,11 @@ Miscellaneous
removes the ability for visitors to generate spurious HTTP 500 errors by
requesting static files that don't exist or haven't been collected yet.
+* The :meth:`django.db.models.Model.__eq__` method is now defined in a
+ way where instances of a proxy model and its base model are considered
+ equal when primary keys match. Previously only instances of exact same
+ class were considered equal on primary key match.
+
Features deprecated in 1.7
==========================
View
4 tests/basic/tests.py
@@ -707,6 +707,10 @@ def test_ticket_20278(self):
with self.assertRaises(ObjectDoesNotExist):
SelfRef.objects.get(selfref=sr)
+ def test_eq(self):
+ self.assertNotEqual(Article(id=1), object())
+ self.assertNotEqual(object(), Article(id=1))
+
class ConcurrentSaveTests(TransactionTestCase):
View
6 tests/defer/tests.py
@@ -183,3 +183,9 @@ def test_defer_inheritance_pk_chaining(self):
with self.assertNumQueries(0):
bc_deferred.id
self.assertEqual(bc_deferred.pk, bc_deferred.id)
+
+ def test_eq(self):
+ s1 = Secondary.objects.create(first="x1", second="y1")
+ s1_defer = Secondary.objects.only('pk').get(pk=s1.pk)
+ self.assertEqual(s1, s1_defer)
+ self.assertEqual(s1_defer, s1)
View
5 tests/model_inheritance/tests.py
@@ -318,3 +318,8 @@ def test_update_parent_filtering(self):
sql = query['sql']
if 'UPDATE' in sql:
self.assertEqual(expected_sql, sql)
+
+ def test_eq(self):
+ # Equality doesn't transfer in multitable inheritance.
+ self.assertNotEqual(Place(id=1), Restaurant(id=1))
+ self.assertNotEqual(Restaurant(id=1), Place(id=1))
View
3  tests/proxy_models/tests.py
@@ -362,6 +362,9 @@ def test_proxy_load_from_fixture(self):
p = MyPerson.objects.get(pk=100)
self.assertEqual(p.name, 'Elvis Presley')
+ def test_eq(self):
+ self.assertEqual(MyPerson(id=100), Person(id=100))
+
class ProxyModelAdminTests(TestCase):
fixtures = ['myhorses']

0 comments on commit 4668c14

Please sign in to comment.
Something went wrong with that request. Please try again.