Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Made Model.__eq__ consider proxy models equivalent

Fixed #11892, fixed #16458, fixed #14492.
  • Loading branch information...
commit 4668c142dce77c6f29fb75532c1acfa1b2d322ff 1 parent 4090982
Anssi Kääriäinen authored
4  django/db/models/base.py
@@ -459,7 +459,9 @@ def __str__(self):
459 459
         return '%s object' % self.__class__.__name__
460 460
 
461 461
     def __eq__(self, other):
462  
-        return isinstance(other, self.__class__) and self._get_pk_val() == other._get_pk_val()
  462
+        return (isinstance(other, Model) and
  463
+                self._meta.concrete_model == other._meta.concrete_model and
  464
+                self._get_pk_val() == other._get_pk_val())
463 465
 
464 466
     def __ne__(self, other):
465 467
         return not self.__eq__(other)
34  docs/ref/models/instances.txt
@@ -494,6 +494,40 @@ using ``__str__()`` like this::
494 494
             # first_name and last_name will be unicode strings.
495 495
             return force_bytes('%s %s' % (self.first_name, self.last_name))
496 496
 
  497
+``__eq__``
  498
+----------
  499
+
  500
+.. method:: Model.__eq__()
  501
+
  502
+The equality method is defined such that instances with the same primary
  503
+key value and the same concrete class are considered equal. The term
  504
+concrete class means proxy model's first non-proxy parent or the class
  505
+itself if it isn't a proxy class.
  506
+
  507
+For example::
  508
+
  509
+    form django.db import models
  510
+
  511
+    class MyModel(models.Model):
  512
+        id = models.AutoField(primary_key=True)
  513
+
  514
+    class MyProxyModel(MyModel):
  515
+        class Meta:
  516
+            proxy = True
  517
+
  518
+    class MultitableInherited(MyModel):
  519
+        pass
  520
+
  521
+    MyModel(id=1) == MyModel(id=1)
  522
+    MyModel(id=1) == MyProxyModel(id=1)
  523
+    MyModel(id=1) != MultitableInherited(id=1)
  524
+    MyModel(id=1) != MyModel(id=2)
  525
+
  526
+.. versionchanged:: 1.7
  527
+
  528
+  In previous versions only instances of the exact same class and same
  529
+  primary key value were considered equal.
  530
+
497 531
 ``get_absolute_url``
498 532
 --------------------
499 533
 
5  docs/releases/1.7.txt
@@ -194,6 +194,11 @@ Miscellaneous
194 194
   removes the ability for visitors to generate spurious HTTP 500 errors by
195 195
   requesting static files that don't exist or haven't been collected yet.
196 196
 
  197
+* The :meth:`django.db.models.Model.__eq__` method is now defined in a
  198
+  way where instances of a proxy model and its base model are considered
  199
+  equal when primary keys match. Previously only instances of exact same
  200
+  class were considered equal on primary key match.
  201
+
197 202
 Features deprecated in 1.7
198 203
 ==========================
199 204
 
4  tests/basic/tests.py
@@ -707,6 +707,10 @@ def test_ticket_20278(self):
707 707
         with self.assertRaises(ObjectDoesNotExist):
708 708
             SelfRef.objects.get(selfref=sr)
709 709
 
  710
+    def test_eq(self):
  711
+        self.assertNotEqual(Article(id=1), object())
  712
+        self.assertNotEqual(object(), Article(id=1))
  713
+
710 714
 
711 715
 class ConcurrentSaveTests(TransactionTestCase):
712 716
 
6  tests/defer/tests.py
@@ -183,3 +183,9 @@ def test_defer_inheritance_pk_chaining(self):
183 183
         with self.assertNumQueries(0):
184 184
             bc_deferred.id
185 185
         self.assertEqual(bc_deferred.pk, bc_deferred.id)
  186
+
  187
+    def test_eq(self):
  188
+        s1 = Secondary.objects.create(first="x1", second="y1")
  189
+        s1_defer = Secondary.objects.only('pk').get(pk=s1.pk)
  190
+        self.assertEqual(s1, s1_defer)
  191
+        self.assertEqual(s1_defer, s1)
5  tests/model_inheritance/tests.py
@@ -318,3 +318,8 @@ def test_update_parent_filtering(self):
318 318
             sql = query['sql']
319 319
             if 'UPDATE' in sql:
320 320
                 self.assertEqual(expected_sql, sql)
  321
+
  322
+    def test_eq(self):
  323
+        # Equality doesn't transfer in multitable inheritance.
  324
+        self.assertNotEqual(Place(id=1), Restaurant(id=1))
  325
+        self.assertNotEqual(Restaurant(id=1), Place(id=1))
3  tests/proxy_models/tests.py
@@ -362,6 +362,9 @@ def test_proxy_load_from_fixture(self):
362 362
         p = MyPerson.objects.get(pk=100)
363 363
         self.assertEqual(p.name, 'Elvis Presley')
364 364
 
  365
+    def test_eq(self):
  366
+        self.assertEqual(MyPerson(id=100), Person(id=100))
  367
+
365 368
 
366 369
 class ProxyModelAdminTests(TestCase):
367 370
     fixtures = ['myhorses']

0 notes on commit 4668c14

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