Opened 6 years ago
Closed 6 years ago
#30041 closed Bug (fixed)
Can't use __init_subclass__ in the Model subclass directly (not as a mixin class)
Reported by: | Tatiana Tereshchenko | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 2.1 |
Severity: | Normal | Keywords: | |
Cc: | 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
There is a closed Django ticket which references PEP and describes the new __init_subclass__
in Python 3.6, it solves the case when __init_subclass__
is used in a mixin class.
Unfortunately, a direct usage of init_subclass in a subclass of Django Model class results in TypeError:
$ python manage.py shell Traceback (most recent call last): File "manage.py", line 15, in <module> execute_from_command_line(sys.argv) File "/home/tt/django_reproducer/lib64/python3.6/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line utility.execute() File "/home/tt/django_reproducer/lib64/python3.6/site-packages/django/core/management/__init__.py", line 357, in execute django.setup() File "/home/tt/django_reproducer/lib64/python3.6/site-packages/django/__init__.py", line 24, in setup apps.populate(settings.INSTALLED_APPS) File "/home/tt/django_reproducer/lib64/python3.6/site-packages/django/apps/registry.py", line 112, in populate app_config.import_models() File "/home/tt/django_reproducer/lib64/python3.6/site-packages/django/apps/config.py", line 198, in import_models self.models_module = import_module(models_module_name) File "/usr/lib64/python3.6/importlib/__init__.py", line 126, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "<frozen importlib._bootstrap>", line 994, in _gcd_import File "<frozen importlib._bootstrap>", line 971, in _find_and_load File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 665, in _load_unlocked File "<frozen importlib._bootstrap_external>", line 678, in exec_module File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed File "/home/tt/mysite/polls/models.py", line 25, in <module> class MyPluginModel(MyMasterModel): File "/home/tt/django_reproducer/lib64/python3.6/site-packages/django/db/models/base.py", line 78, in __new__ new_class = super_new(cls, name, bases, new_attrs, **kwargs) TypeError: __init_subclass__() missing 1 required positional argument: 'cls'
To reproduce, just use the code below in models.py:
(FWIW, I created a django project and then polls app using the tutorial and then added the code to models.py)
from django.db import models # It works as a mixin class. # Expected/actual result: MyModel.some_attr == 'added_by __init_subclass__' class MyMixin: def __init_subclass__(cls, **kwargs): cls.some_attr = 'added_by __init_subclass__' super().__init_subclass__(**kwargs) class MyModel(models.Model, MyMixin): pass # It doesn't work directly in the subclass of the Model class # Expected result: MyPluginModel.some_attr == 'added_by __init_subclass__' # Actual result: TypeError: __init_subclass__() missing 1 required positional argument: 'cls' class MyMasterModel(models.Model): # remove inheritance from models.Model and it will work. def __init_subclass__(cls, **kwargs): cls.some_attr = 'added_by __init_subclass__' super().__init_subclass__(**kwargs) class MyPluginModel(MyMasterModel): pass
OS: Fedora 28
Django: 2.1.4
Python: 3.6.6
Change History (5)
comment:1 by , 6 years ago
Type: | Uncategorized → Bug |
---|
comment:2 by , 6 years ago
comment:4 by , 6 years ago
Component: | Uncategorized → Database layer (models, ORM) |
---|---|
Triage Stage: | Unreviewed → Ready for checkin |
Note:
See TracTickets
for help on using tickets.
It seems that explicit
@classmethod
decorator helps, though PEP says that requiring it is among "rejected design options".See example of __init_subclass__ usage from PEP