﻿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): pass
class MyDerivedModel(MyModel): pass
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				Accepted	1	0	0	0	0	0
