Opened 11 years ago

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

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

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

### comment:1 Changed 11 years ago by Luke Plant

Description: modified (diff) Unreviewed → Accepted
Note: See TracTickets for help on using tickets.