Loading django/db/models/base.py +16 −3 Original line number Diff line number Diff line Loading @@ -194,9 +194,6 @@ class ModelBase(type): base = parent if base is None: raise TypeError("Proxy model '%s' has no non-abstract model base class." % name) if (new_class._meta.local_fields or new_class._meta.local_many_to_many): raise FieldError("Proxy model '%s' contains model fields." % name) new_class._meta.setup_proxy(base) new_class._meta.concrete_model = base._meta.concrete_model else: Loading Loading @@ -1047,6 +1044,7 @@ class Model(six.with_metaclass(ModelBase)): def check(cls, **kwargs): errors = [] errors.extend(cls._check_swappable()) errors.extend(cls._check_model()) errors.extend(cls._check_managers(**kwargs)) if not cls._meta.swapped: errors.extend(cls._check_fields(**kwargs)) Loading Loading @@ -1094,6 +1092,21 @@ class Model(six.with_metaclass(ModelBase)): ) return errors @classmethod def _check_model(cls): errors = [] if cls._meta.proxy: if cls._meta.local_fields or cls._meta.local_many_to_many: errors.append( checks.Error( "Proxy model '%s' contains model fields." % cls.__name__, hint=None, obj=None, id='models.E017', ) ) return errors @classmethod def _check_managers(cls, **kwargs): """ Perform all manager checks. """ Loading docs/ref/checks.txt +1 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ Models * **models.E014**: ``ordering`` must be a tuple or list (even if you want to order by only one field). * **models.E015**: ``ordering`` refers to the non-existent field ``<field name>``. * **models.E016**: ``index_together/unique_together`` refers to field ``<field_name>`` which is not local to model ``<model>``. * **models.E017**: Proxy model ``<model>`` contains model fields. Fields ~~~~~~ Loading tests/proxy_models/tests.py +20 −8 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ from django.apps import apps from django.contrib import admin from django.contrib.contenttypes.models import ContentType from django.core import management from django.core.exceptions import FieldError from django.core import checks from django.db import models, DEFAULT_DB_ALIAS from django.db.models import signals from django.test import TestCase, override_settings Loading Loading @@ -143,13 +143,25 @@ class ProxyModelTests(TestCase): self.assertRaises(TypeError, build_no_base_classes) def test_new_fields(self): def build_new_fields(): class NoNewFields(Person): newfield = models.BooleanField() class Meta: proxy = True self.assertRaises(FieldError, build_new_fields) # don't register this model in the app_cache for the current app, # otherwise the check fails when other tests are being run. app_label = 'no_such_app' errors = NoNewFields.check() expected = [ checks.Error( "Proxy model 'NoNewFields' contains model fields.", hint=None, obj=None, id='models.E017', ) ] self.assertEqual(errors, expected) @override_settings(TEST_SWAPPABLE_MODEL='proxy_models.AlternateModel') def test_swappable(self): Loading Loading
django/db/models/base.py +16 −3 Original line number Diff line number Diff line Loading @@ -194,9 +194,6 @@ class ModelBase(type): base = parent if base is None: raise TypeError("Proxy model '%s' has no non-abstract model base class." % name) if (new_class._meta.local_fields or new_class._meta.local_many_to_many): raise FieldError("Proxy model '%s' contains model fields." % name) new_class._meta.setup_proxy(base) new_class._meta.concrete_model = base._meta.concrete_model else: Loading Loading @@ -1047,6 +1044,7 @@ class Model(six.with_metaclass(ModelBase)): def check(cls, **kwargs): errors = [] errors.extend(cls._check_swappable()) errors.extend(cls._check_model()) errors.extend(cls._check_managers(**kwargs)) if not cls._meta.swapped: errors.extend(cls._check_fields(**kwargs)) Loading Loading @@ -1094,6 +1092,21 @@ class Model(six.with_metaclass(ModelBase)): ) return errors @classmethod def _check_model(cls): errors = [] if cls._meta.proxy: if cls._meta.local_fields or cls._meta.local_many_to_many: errors.append( checks.Error( "Proxy model '%s' contains model fields." % cls.__name__, hint=None, obj=None, id='models.E017', ) ) return errors @classmethod def _check_managers(cls, **kwargs): """ Perform all manager checks. """ Loading
docs/ref/checks.txt +1 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ Models * **models.E014**: ``ordering`` must be a tuple or list (even if you want to order by only one field). * **models.E015**: ``ordering`` refers to the non-existent field ``<field name>``. * **models.E016**: ``index_together/unique_together`` refers to field ``<field_name>`` which is not local to model ``<model>``. * **models.E017**: Proxy model ``<model>`` contains model fields. Fields ~~~~~~ Loading
tests/proxy_models/tests.py +20 −8 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ from django.apps import apps from django.contrib import admin from django.contrib.contenttypes.models import ContentType from django.core import management from django.core.exceptions import FieldError from django.core import checks from django.db import models, DEFAULT_DB_ALIAS from django.db.models import signals from django.test import TestCase, override_settings Loading Loading @@ -143,13 +143,25 @@ class ProxyModelTests(TestCase): self.assertRaises(TypeError, build_no_base_classes) def test_new_fields(self): def build_new_fields(): class NoNewFields(Person): newfield = models.BooleanField() class Meta: proxy = True self.assertRaises(FieldError, build_new_fields) # don't register this model in the app_cache for the current app, # otherwise the check fails when other tests are being run. app_label = 'no_such_app' errors = NoNewFields.check() expected = [ checks.Error( "Proxy model 'NoNewFields' contains model fields.", hint=None, obj=None, id='models.E017', ) ] self.assertEqual(errors, expected) @override_settings(TEST_SWAPPABLE_MODEL='proxy_models.AlternateModel') def test_swappable(self): Loading