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@… anonymous "== 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 closed Database layer (models, ORM) 1.3 Normal fixed anssi.kaariainen@… Ready for checkin 1 0 0 0 0 0