diff --git a/django/db/models/base.py b/django/db/models/base.py index 5db600764a..e8ef2db913 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -60,7 +60,7 @@ def subclass_exception(name, bases, module, attached_to): class ModelBase(type): """Metaclass for all models.""" - def __new__(cls, name, bases, attrs): + def __new__(cls, name, bases, attrs, **kwargs): super_new = super().__new__ # Also ensure initialization is only performed for subclasses of Model @@ -75,7 +75,7 @@ class ModelBase(type): classcell = attrs.pop('__classcell__', None) if classcell is not None: new_attrs['__classcell__'] = classcell - new_class = super_new(cls, name, bases, new_attrs) + new_class = super_new(cls, name, bases, new_attrs, **kwargs) attr_meta = attrs.pop('Meta', None) abstract = getattr(attr_meta, 'abstract', False) if not attr_meta: diff --git a/docs/releases/2.1.txt b/docs/releases/2.1.txt index 516f6163eb..22768e2f1b 100644 --- a/docs/releases/2.1.txt +++ b/docs/releases/2.1.txt @@ -153,7 +153,7 @@ Migrations Models ~~~~~~ -* ... +* Models can now use ``__init_subclass__()`` from :pep:`487`. Requests and Responses ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/model_inheritance/tests.py b/tests/model_inheritance/tests.py index e1eca65742..88f1e623c4 100644 --- a/tests/model_inheritance/tests.py +++ b/tests/model_inheritance/tests.py @@ -1,9 +1,11 @@ +import unittest from operator import attrgetter from django.core.exceptions import FieldError, ValidationError from django.db import connection, models from django.test import SimpleTestCase, TestCase from django.test.utils import CaptureQueriesContext, isolate_apps +from django.utils.version import PY36 from .models import ( Base, Chef, CommonInfo, GrandChild, GrandParent, ItalianRestaurant, @@ -156,6 +158,23 @@ class ModelInheritanceTests(TestCase): self.assertIs(C._meta.parents[A], C._meta.get_field('a')) + @unittest.skipUnless(PY36, 'init_subclass is new in Python 3.6') + @isolate_apps('model_inheritance') + def test_init_subclass(self): + saved_kwargs = {} + + class A: + def __init_subclass__(cls, **kwargs): + super().__init_subclass__() + saved_kwargs.update(kwargs) + + kwargs = {'x': 1, 'y': 2, 'z': 3} + + class B(A, models.Model, **kwargs): + pass + + self.assertEqual(saved_kwargs, kwargs) + class ModelInheritanceDataTests(TestCase): @classmethod