Opened 11 years ago

# Equality operator on django.db.models.Model not commutative — at Initial Version

Reported by: Owned by: freek.wiekmeijer@… nobody Database layer (models, ORM) 1.3 Normal anssi.kaariainen@… Ready for checkin yes no no no no no

### Description

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

### Change History (0)

Note: See TracTickets for help on using tickets.