﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
33538	Migrations autodetector change for djangopolymorphicmodel	markp2	nobody	"We use Django-polymorphic and now get spurious migration AlterField operation. We note that this is referenced in the 4.0 release notes:

Migrations autodetector changes¶
The migrations autodetector now uses model states instead of model classes. Also, migration operations for ForeignKey and ManyToManyField fields no longer specify attributes which were not passed to the fields during initialization.
As a side-effect, running makemigrations might generate no-op AlterField operations for ManyToManyField and ForeignKey fields in some cases

However, we de not understand what is a model state [vs a model class]?

The auto-generated migration looks like this:

{{{
    operations = [
        migrations.AlterField(
            model_name='polymorphicmodel',
            name='polymorphic_ctype',
            field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_%(app_label)s.%(class)s_set+', to='contenttypes.contenttype'),
        ),
    ]
}}}

Presumably based on our [simple] sub-class of PolymorphicModel:


{{{
class PolymorphicModel(poly_models.PolymorphicModel):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self.__class__ == PolymorphicModel:
            return
        tag = self.get_polymorphic_tag()
        if not tag and args:
            tag = args[self.get_polymorphic_tag_index() + 1]
        setattr(self, self.get_polymorphic_tag_name(), tag)

    @classmethod
    def get_polymorphic_tag(cls) -> str:
        baseclass = cls.get_polymorphic_concrete_base_model()
        assert cls.__name__.startswith(baseclass.__name__)
        return cls.__name__[len(baseclass.__name__):]

    @classmethod
    def get_polymorphic_tag_name(cls) -> str:
        i = cls.get_polymorphic_tag_index()
        return cls.get_polymorphic_base_model()._meta.fields[i + 1].name

    @classmethod
    def get_polymorphic_tag_index(cls) -> int:
        internal_fields = len(cls.get_polymorphic_internal_model_fields())
        return internal_fields + 1

    @classmethod
    def get_polymorphic_submodels(cls) -> List[Type['PolymorphicModel']]:
        baseclass = cls.get_polymorphic_concrete_base_model()
        submodels = [m for m in apps.get_models() if issubclass(m, baseclass) and m != baseclass]
        return submodels

    @classmethod
    def get_polymorphic_submodel(cls, tag) -> Type['PolymorphicModel']:
        models = [m for m in cls.get_polymorphic_submodels() if m.get_polymorphic_tag() == tag]
        return models[0]

    @classmethod
    def get_polymorphic_base_model(cls):
        raise NotImplementedError()

    @classmethod
    def get_polymorphic_concrete_base_model(cls):
        raise NotImplementedError()

    @classmethod
    def get_polymorphic_internal_model_fields(cls):
        return cls.polymorphic_internal_model_fields

    @classmethod
    def fqn(cls):
        return cls.__module__ + '.' + cls.__name__
}}}

Is there any way to resolve this and not have the migration auto generated?"	Cleanup/optimization	closed	Migrations	4.0	Normal	invalid	Migrations		Unreviewed	0	0	0	0	0	0
