Fixed #30254 -- Allowed model metaclasses to access the attribute dict in __init__().
Regression in a68ea23101
.
This commit is contained in:
parent
f976ab1b11
commit
58ad030d05
|
@ -84,9 +84,12 @@ class ModelBase(type):
|
||||||
# Pass all attrs without a (Django-specific) contribute_to_class()
|
# Pass all attrs without a (Django-specific) contribute_to_class()
|
||||||
# method to type.__new__() so that they're properly initialized
|
# method to type.__new__() so that they're properly initialized
|
||||||
# (i.e. __set_name__()).
|
# (i.e. __set_name__()).
|
||||||
|
contributable_attrs = {}
|
||||||
for obj_name, obj in list(attrs.items()):
|
for obj_name, obj in list(attrs.items()):
|
||||||
if not _has_contribute_to_class(obj):
|
if _has_contribute_to_class(obj):
|
||||||
new_attrs[obj_name] = attrs.pop(obj_name)
|
contributable_attrs[obj_name] = obj
|
||||||
|
else:
|
||||||
|
new_attrs[obj_name] = obj
|
||||||
new_class = super_new(cls, name, bases, new_attrs, **kwargs)
|
new_class = super_new(cls, name, bases, new_attrs, **kwargs)
|
||||||
|
|
||||||
abstract = getattr(attr_meta, 'abstract', False)
|
abstract = getattr(attr_meta, 'abstract', False)
|
||||||
|
@ -146,8 +149,9 @@ class ModelBase(type):
|
||||||
if is_proxy and base_meta and base_meta.swapped:
|
if is_proxy and base_meta and base_meta.swapped:
|
||||||
raise TypeError("%s cannot proxy the swapped model '%s'." % (name, base_meta.swapped))
|
raise TypeError("%s cannot proxy the swapped model '%s'." % (name, base_meta.swapped))
|
||||||
|
|
||||||
# Add all attributes to the class.
|
# Add remaining attributes (those with a contribute_to_class() method)
|
||||||
for obj_name, obj in attrs.items():
|
# to the class.
|
||||||
|
for obj_name, obj in contributable_attrs.items():
|
||||||
new_class.add_to_class(obj_name, obj)
|
new_class.add_to_class(obj_name, obj)
|
||||||
|
|
||||||
# All the fields of any type declared on this model
|
# All the fields of any type declared on this model
|
||||||
|
|
|
@ -2,9 +2,10 @@ import datetime
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
|
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.db import router
|
from django.db import models, router
|
||||||
from django.db.models.sql import InsertQuery
|
from django.db.models.sql import InsertQuery
|
||||||
from django.test import TestCase, skipUnlessDBFeature
|
from django.test import TestCase, skipUnlessDBFeature
|
||||||
|
from django.test.utils import isolate_apps
|
||||||
from django.utils.timezone import get_fixed_timezone
|
from django.utils.timezone import get_fixed_timezone
|
||||||
|
|
||||||
from .models import (
|
from .models import (
|
||||||
|
@ -217,6 +218,23 @@ class ModelTests(TestCase):
|
||||||
m3 = Model3.objects.get(model2=1000)
|
m3 = Model3.objects.get(model2=1000)
|
||||||
m3.model2
|
m3.model2
|
||||||
|
|
||||||
|
@isolate_apps('model_regress')
|
||||||
|
def test_metaclass_can_access_attribute_dict(self):
|
||||||
|
"""
|
||||||
|
Model metaclasses have access to the class attribute dict in
|
||||||
|
__init__() (#30254).
|
||||||
|
"""
|
||||||
|
class HorseBase(models.base.ModelBase):
|
||||||
|
def __init__(cls, name, bases, attrs):
|
||||||
|
super(HorseBase, cls).__init__(name, bases, attrs)
|
||||||
|
cls.horns = (1 if 'magic' in attrs else 0)
|
||||||
|
|
||||||
|
class Horse(models.Model, metaclass=HorseBase):
|
||||||
|
name = models.CharField(max_length=255)
|
||||||
|
magic = True
|
||||||
|
|
||||||
|
self.assertEqual(Horse.horns, 1)
|
||||||
|
|
||||||
|
|
||||||
class ModelValidationTest(TestCase):
|
class ModelValidationTest(TestCase):
|
||||||
def test_pk_validation(self):
|
def test_pk_validation(self):
|
||||||
|
|
Loading…
Reference in New Issue