Made Model.__eq__ consider proxy models equivalent

Fixed #11892, fixed #16458, fixed #14492.
This commit is contained in:
Anssi Kääriäinen 2013-08-07 09:51:32 +03:00
parent 4090982617
commit 4668c142dc
7 changed files with 60 additions and 1 deletions

View File

@ -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)

View File

@ -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``
-------------------- --------------------

View File

@ -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
========================== ==========================

View File

@ -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):

View File

@ -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)

View File

@ -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))

View File

@ -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']