Commit 724e6008 authored by Craig de Stigter's avatar Craig de Stigter Committed by Tim Graham
Browse files

[1.7.x] Fixed #22690 -- Added a check for proxy models containing fields.

Removed the FieldError raised by ModelBase.__new__ in this case.

Backport of ce993efd from master
parent 160fd6c7
Loading
Loading
Loading
Loading
+16 −3
Original line number Diff line number Diff line
@@ -193,9 +193,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:
@@ -1044,6 +1041,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))
@@ -1091,6 +1089,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. """
+1 −0
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ Models
* **models.E013**: ``index_together/unique_together`` refers to a ManyToManyField ``<field name>``, but ManyToManyFields are not supported for that option.
* **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.E017**: Proxy model ``<model>`` contains model fields.

Fields
~~~~~~
+20 −8
Original line number Diff line number Diff line
@@ -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
@@ -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):