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__
|
return '%s object' % self.__class__.__name__
|
||||||
|
|
||||||
def __eq__(self, other):
|
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):
|
def __ne__(self, other):
|
||||||
return not self.__eq__(other)
|
return not self.__eq__(other)
|
||||||
|
|
|
@ -494,6 +494,40 @@ using ``__str__()`` like this::
|
||||||
# first_name and last_name will be unicode strings.
|
# first_name and last_name will be unicode strings.
|
||||||
return force_bytes('%s %s' % (self.first_name, self.last_name))
|
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``
|
``get_absolute_url``
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
|
|
@ -194,6 +194,11 @@ Miscellaneous
|
||||||
removes the ability for visitors to generate spurious HTTP 500 errors by
|
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.
|
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
|
Features deprecated in 1.7
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
|
|
|
@ -707,6 +707,10 @@ class ModelTest(TestCase):
|
||||||
with self.assertRaises(ObjectDoesNotExist):
|
with self.assertRaises(ObjectDoesNotExist):
|
||||||
SelfRef.objects.get(selfref=sr)
|
SelfRef.objects.get(selfref=sr)
|
||||||
|
|
||||||
|
def test_eq(self):
|
||||||
|
self.assertNotEqual(Article(id=1), object())
|
||||||
|
self.assertNotEqual(object(), Article(id=1))
|
||||||
|
|
||||||
|
|
||||||
class ConcurrentSaveTests(TransactionTestCase):
|
class ConcurrentSaveTests(TransactionTestCase):
|
||||||
|
|
||||||
|
|
|
@ -183,3 +183,9 @@ class DeferTests(TestCase):
|
||||||
with self.assertNumQueries(0):
|
with self.assertNumQueries(0):
|
||||||
bc_deferred.id
|
bc_deferred.id
|
||||||
self.assertEqual(bc_deferred.pk, 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']
|
sql = query['sql']
|
||||||
if 'UPDATE' in sql:
|
if 'UPDATE' in sql:
|
||||||
self.assertEqual(expected_sql, 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)
|
p = MyPerson.objects.get(pk=100)
|
||||||
self.assertEqual(p.name, 'Elvis Presley')
|
self.assertEqual(p.name, 'Elvis Presley')
|
||||||
|
|
||||||
|
def test_eq(self):
|
||||||
|
self.assertEqual(MyPerson(id=100), Person(id=100))
|
||||||
|
|
||||||
|
|
||||||
class ProxyModelAdminTests(TestCase):
|
class ProxyModelAdminTests(TestCase):
|
||||||
fixtures = ['myhorses']
|
fixtures = ['myhorses']
|
||||||
|
|
Loading…
Reference in New Issue