Fixed #22690 -- Added a check for proxy models containing fields.

Removed the FieldError raised by ModelBase.__new__ in this case.
This commit is contained in:
Craig de Stigter 2014-05-29 10:26:57 +12:00 committed by Tim Graham
parent 5046c110cf
commit ce993efda8
3 changed files with 36 additions and 10 deletions

View File

@ -194,9 +194,6 @@ class ModelBase(type):
base = parent base = parent
if base is None: if base is None:
raise TypeError("Proxy model '%s' has no non-abstract model base class." % name) 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.setup_proxy(base)
new_class._meta.concrete_model = base._meta.concrete_model new_class._meta.concrete_model = base._meta.concrete_model
else: else:
@ -1047,6 +1044,7 @@ class Model(six.with_metaclass(ModelBase)):
def check(cls, **kwargs): def check(cls, **kwargs):
errors = [] errors = []
errors.extend(cls._check_swappable()) errors.extend(cls._check_swappable())
errors.extend(cls._check_model())
errors.extend(cls._check_managers(**kwargs)) errors.extend(cls._check_managers(**kwargs))
if not cls._meta.swapped: if not cls._meta.swapped:
errors.extend(cls._check_fields(**kwargs)) errors.extend(cls._check_fields(**kwargs))
@ -1094,6 +1092,21 @@ class Model(six.with_metaclass(ModelBase)):
) )
return errors 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 @classmethod
def _check_managers(cls, **kwargs): def _check_managers(cls, **kwargs):
""" Perform all manager checks. """ """ Perform all manager checks. """

View File

@ -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.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.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.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 Fields
~~~~~~ ~~~~~~

View File

@ -4,7 +4,7 @@ from django.apps import apps
from django.contrib import admin from django.contrib import admin
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core import management 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 import models, DEFAULT_DB_ALIAS
from django.db.models import signals from django.db.models import signals
from django.test import TestCase, override_settings from django.test import TestCase, override_settings
@ -143,13 +143,25 @@ class ProxyModelTests(TestCase):
self.assertRaises(TypeError, build_no_base_classes) self.assertRaises(TypeError, build_no_base_classes)
def test_new_fields(self): def test_new_fields(self):
def build_new_fields(): class NoNewFields(Person):
class NoNewFields(Person): newfield = models.BooleanField()
newfield = models.BooleanField()
class Meta: class Meta:
proxy = True 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') @override_settings(TEST_SWAPPABLE_MODEL='proxy_models.AlternateModel')
def test_swappable(self): def test_swappable(self):