Made Model.__eq__ consider proxy models equivalent
Fixed #11892, fixed #16458, fixed #14492.
This commit is contained in:
parent
4090982617
commit
4668c142dc
|
@ -459,7 +459,9 @@ class Model(six.with_metaclass(ModelBase)):
|
|||
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)
|
||||
|
|
|
@ -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``
|
||||
--------------------
|
||||
|
||||
|
|
|
@ -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
|
||||
==========================
|
||||
|
||||
|
|
|
@ -707,6 +707,10 @@ class ModelTest(TestCase):
|
|||
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):
|
||||
|
||||
|
|
|
@ -183,3 +183,9 @@ class DeferTests(TestCase):
|
|||
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)
|
||||
|
|
|
@ -318,3 +318,8 @@ class ModelInheritanceTests(TestCase):
|
|||
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))
|
||||
|
|
|
@ -362,6 +362,9 @@ class ProxyModelTests(TestCase):
|
|||
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']
|
||||
|
|
Loading…
Reference in New Issue