Changes between Initial Version and Version 1 of Ticket #16458
- Timestamp:
- Jul 13, 2011, 10:14:24 AM (13 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
Ticket #16458
- Property Triage Stage Unreviewed → Accepted
-
Ticket #16458 – Description
initial v1 1 Problem outline 2 --------------- 1 == Problem outline == 2 3 3 In math is is a common assumption that the equality operator should be commutative, i.e. A==B would always correspond to B==A. 4 4 In django's Model class I found non-commutative behaviour. 5 5 6 6 7 Affected code 8 ------------- 7 == Affected code == 8 9 9 file: django.db.models.base.py 10 10 {{{ 11 11 class Model(object): 12 12 ... … … 15 15 return isinstance(other, self.__class__) and self._get_pk_val() == other._get_pk_val() 16 16 ... 17 }}} 17 18 18 19 Problem detail 20 -------------- 19 == Problem detail == 21 20 22 21 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. 23 22 24 23 assume this: 25 class MyModel(models.Model) 26 class MyDerivedModel(MyModel) 24 {{{ 25 class MyModel(models.Model): pass 26 class MyDerivedModel(MyModel): pass 27 27 A = MyModel() 28 28 B = MyDerivedModel() … … 30 30 (A==B) # --> A.__eq__ returns True if (a.pk == b.pk) 31 31 (B==A) # --> B.__eq__ returns False 32 }}} 32 33 34 == Further analysis == 33 35 34 Further analysis35 ----------------36 36 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. 37 37 … … 39 39 40 40 41 Suggested solution 42 ------------------ 41 == Suggested solution == 42 43 43 Make the type comparison between self and other symmetrical. 44 44 {{{ 45 45 class Model(object): 46 46 def __eq__(self, other): 47 47 return (isinstance(other, self.__class__) or isinstance(self, other.__class__)) and \ 48 48 (self._get_pk_val() == other._get_pk_val()) 49 }}}