#12876 closed (fixed)
maximum recursion error when caching querysets on models
Reported by: | zbyte64 | Owned by: | elachuni |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 1.2-beta |
Severity: | Keywords: | pycamp2010 | |
Cc: | zbyte64@… | 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 following test case causes a runtime exception against django 1.2 beta 1:
from django.test import TestCase from django.db import models class TestModel(models.Model): def cachedmethod(self): if not hasattr(self, '_cachedmethod'): self._cachedmethod = RelatedModel.objects.all().filter(test_model=self) return self._cachedmethod class RelatedModel(models.Model): test_model = models.ForeignKey(TestModel) category = models.CharField(max_length=50) class dummy(object): def __init__(self, parent): self.parent = parent def cachedmethod(self): if not hasattr(self, '_cachedmethod'): self._cachedmethod = RelatedModel.objects.all().filter(test_model=self.parent) return self._cachedmethod class BreakMeTest(TestCase): def test_caching(self): parent = TestModel() parent.save() related = RelatedModel(category='foo', test_model=parent) related.save() adummy = dummy(parent) adummy.cachedmethod() adummy.cachedmethod().filter(category='foo') #this doesn't break it parent.cachedmethod() parent.cachedmethod().filter(category='foo') #this breaks it
Attachments (2)
Change History (11)
by , 15 years ago
Attachment: | results.txt added |
---|
comment:1 by , 15 years ago
milestone: | → 1.2 |
---|---|
Triage Stage: | Unreviewed → Accepted |
comment:2 by , 15 years ago
Component: | Uncategorized → Database layer (models, ORM) |
---|
follow-up: 5 comment:3 by , 15 years ago
Owner: | changed from | to
---|
django.db.models.sql.Query
defines a custom __deepcopy__
that calls self.clone()
, disregarding the provided memo dict.
So, if the query contains a reference to a model instance that in turn contains a reference to a reference (as in this case), deepcopy will end up in an endless loop.
The model itself could work around this problem by providing its own __deepcopy__
implementation, that just didn't include the query. For the example in the bugreport:
class TestModel(models.Model): def __deepcopy__(self, memo): return TestModel(id=self.id) ....
comment:4 by , 15 years ago
Has patch: | set |
---|---|
Keywords: | pycamp2010 added |
comment:5 by , 15 years ago
The attached patch adds an optional argument 'memo' to clone, to be able to correctly implement deepcopy.
Replying to elachuni:
So, if the query contains a reference to a model instance that in turn contains a reference to a reference (...)
Should have been a reference to a query here.
comment:6 by , 15 years ago
Triage Stage: | Accepted → Ready for checkin |
---|
comment:7 by , 15 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
Stack trace of exception