Issues with model Manager and inheritance.
|Reported by:||loic84||Owned by:||nobody|
|Component:||Database layer (models, ORM)||Version:||master|
|Cc:||akaariai, LaurensBER, aronp@…, mjtamlyn||Triage Stage:||Ready for checkin|
|Has patch:||yes||Needs documentation:||no|
|Needs tests:||no||Patch needs improvement:||no|
Description (last modified by loic)
I've found a couple of issues with the current handling of managers with inheritance.
class AbstractEvent(models.Model): events = models.Manager() class Meta: abstract = True class BachelorParty(AbstractEvent): objects = models.Manager() class MessyBachelorParty(BachelorParty): pass
If AbstractEvent has a manager called anything but objects (e.g. events):
MessyBachelorParty.objects.model == <class 'model_inheritance_regress.models.BachelorParty'>
Which causes the following failure:
model_inheritance_regress.tests.ModelInheritanceTest.test_abstract_base_class_m2m_relation_inheritance` fails with `AttributeError: 'BachelorParty' object has no attribute 'bachelorparty_ptr'.
If AbstractEvent doesn't have an explicit manager, or has one called objects:
MessyBachelorParty.objects.model == <class 'model_inheritance_regress.models.MessyBachelorParty'> which is the expected result.
- Managers in MTI *are* inherited, contrary to what is said in the docs (now tracked specifically in #25897):
"Managers defined on non-abstract base classes are not inherited by child classes. [...] Therefore, they aren’t passed onto child classes.".
The problem is that, since we create the new class by calling object.__new__(), normal Python attribute resolution applies, and we gain access to the attributes of the base classes. This doesn't happen to fields because these are removed during the class creation process, but managers are left behind. It's always tempting to think we could just delete them, but you cannot delete something that is not in your own __dict__. The problem is not so much that we inherit those managers, but that they don't return the right model type as demonstrated in https://github.com/loic/django/compare/manager_inheritance_bug2.
Change History (23)
comment:1 Changed 3 years ago by loic84
- Has patch set
- Needs documentation unset
- Needs tests set
- Patch needs improvement set
comment:10 follow-up: ↓ 11 Changed 4 months ago by loic
comment:11 in reply to: ↑ 10 ; follow-up: ↓ 12 Changed 3 months ago by poleha
comment:12 in reply to: ↑ 11 Changed 3 months ago by loic
comment:21 Changed 10 days ago by timgraham
- Needs documentation unset
- Needs tests unset
- Patch needs improvement unset
- Triage Stage changed from Accepted to Ready for checkin
comment:22 Changed 10 days ago by Loïc Bistuer <loic.bistuer@…>
- Resolution set to fixed
- Status changed from new to closed