﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
16458	Equality operator on django.db.models.Model not commutative	freek.wiekmeijer@…	nobody	"Problem outline
---------------
In math is is a common assumption that the equality operator should be commutative, i.e. A==B would always correspond to B==A.
In django's Model class I found non-commutative behaviour.


Affected code
-------------
file: django.db.models.base.py

class Model(object):
...

   def __eq__(self, other):
        return isinstance(other, self.__class__) and self._get_pk_val() == other._get_pk_val()
...


Problem detail
--------------

This implementation of __eq__() will cause a different outcome between (A==B) and (B==A) in cases where one of the two compared objects is a derived class of the other.

assume this:
class MyModel(models.Model)
class MyDerivedModel(MyModel)
A = MyModel()
B = MyDerivedModel()

(A==B) # --> A.__eq__ returns True if (a.pk == b.pk)
(B==A) # --> B.__eq__ returns False


Further analysis
----------------
I checked how derived models are created in the database (MySQL 5.0 backend). The table for MyDerivedModel does not contain its own primary key, but a reference to the PK in MyModel instead. This means that there can never be a collision between the primary key of MyModel and the primary key of MyDerivedModel.

So it is safe to compare PKs across base and derived classes, as is currently done.


Suggested solution
------------------
Make the type comparison between self and other symmetrical. 

class Model(object):
   def __eq__(self, other):
        return (isinstance(other, self.__class__) or isinstance(self, other.__class__)) and \
               (self._get_pk_val() == other._get_pk_val())
"	Bug	new	Database layer (models, ORM)	1.3	Normal				Unreviewed	1	0	0	0	0	0
