Opened 3 years ago
Closed 3 years ago
#33538 closed Cleanup/optimization (invalid)
Migrations autodetector change for djangopolymorphicmodel
Reported by: | markp2 | Owned by: | nobody |
---|---|---|---|
Component: | Migrations | Version: | 4.0 |
Severity: | Normal | Keywords: | Migrations |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
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?
Unfortunately no, all auto-generated migrations should contain only no-op operations so no SQL statements are issued. If you're having trouble understanding how Django works, see TicketClosingReasons/UseSupportChannels for ways to get help.