Kaydet (Commit) 4668c142 authored tarafından Anssi Kääriäinen's avatar Anssi Kääriäinen

Made Model.__eq__ consider proxy models equivalent

Fixed #11892, fixed #16458, fixed #14492.
üst 40909826
...@@ -459,7 +459,9 @@ class Model(six.with_metaclass(ModelBase)): ...@@ -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:: ...@@ -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 ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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']
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment