Opened 16 years ago
Closed 12 years ago
#11892 closed Bug (fixed)
Model __eq__ is not symmetric.
| Reported by: | Owned by: | nobody | |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | dev |
| Severity: | Normal | Keywords: | |
| Cc: | Colin Copeland, anssi.kaariainen@…, marti@… | Triage Stage: | Ready for checkin |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
The Model test for equal implemented in eq is not symmetric. A non-deferred instance compares equal to a deferred instance, but a deferred instance compares unequal to a non-deferred instance. This is due to the following implementation of eq:
def __eq__(self, other):
return isinstance(other, self.__class__ and self._get_pk_val() == other._get_pk_val()
This needs to be changed to:
def __eq__(self, other):
return (isinstance(other, self.__class__) or isinstance(self, other.__class__)) and self._get_pk_val() == other._get_pk_val()
Which allows for complete symmetric of comparisons.
Attachments (2)
Change History (15)
by , 16 years ago
| Attachment: | 11892.diff added |
|---|
comment:1 by , 16 years ago
| Cc: | added |
|---|
comment:2 by , 16 years ago
| Has patch: | set |
|---|---|
| Triage Stage: | Unreviewed → Accepted |
comment:3 by , 16 years ago
| Patch needs improvement: | set |
|---|
This patch also changes how __eq__ behaves for inherited models. Given:
class Base(models.Model): pass class Sub(Base): pass
With the patch sub.base == sub, while currently sub.base != sub.
It also doen't handle the case where both instances have different deferred fields: qs.defer('f1)[0] != qs.defer('f2')[0].
Something like the following could work, but it seems the special-casing should rather happen in deferred_class_factory.
def __eq__(self, other): other_model = other.__class__ if getattr(other_model, '_deferred', False): other_model = other_model.mro()[1] self_model = self.__class__ if getattr(self_model, '_deferred', False): self_model = self_model.mro()[1] return issubclass(other_model, self_model) and self._get_pk_val() == other._get_pk_val()
by , 16 years ago
| Attachment: | 11892.deferred_model_eq.diff added |
|---|
comment:4 by , 16 years ago
| Patch needs improvement: | unset |
|---|
The patch uses the approach described in my previous comment.
comment:5 by , 16 years ago
| Patch needs improvement: | set |
|---|---|
| Version: | 1.1 → SVN |
comment:6 by , 15 years ago
| Severity: | → Normal |
|---|---|
| Type: | → Bug |
follow-up: 9 comment:8 by , 14 years ago
#16458 is about inheritance, this one is about deferred instances. They're independent issues with similar symptoms.
comment:9 by , 14 years ago
| Cc: | added |
|---|
comment:11 by , 13 years ago
| Cc: | added |
|---|
comment:12 by , 12 years ago
| Patch needs improvement: | unset |
|---|---|
| Triage Stage: | Accepted → Ready for checkin |
Patch for #16458 is RFC.
comment:13 by , 12 years ago
| Resolution: | → fixed |
|---|---|
| Status: | new → closed |
Uploaded a patch with pmcnerthney's fix and an accompanying test.