首页 > 解决方案 > No new migration for subclass of subclass of a field

问题描述

I have the following setup (Django 2.0.6, also in 2.2), the first migration is with the field having max_length=64 and now I want to change the DummyCharField.max_length to 255:

class BaseDummyCharField(models.CharField):
    def __init__(self, *args, **kwargs):
        if 'max_length' not in kwargs:
            kwargs['max_length'] = 64
        super().__init__(*args, **kwargs)


class DummyCharField(BaseDummyCharField):
    def __init__(self, *args, **kwargs):
        kwargs['max_length'] = 255
        super().__init__(*args, **kwargs)


class AnotherDummyCharField(BaseDummyCharField):
    ...


class DummyModel(models.Model):
    dummy = DummyCharField()

When running makemigrations, it just says "No changes detected".

I also tried using deconstruct() as told in the docs, but it still didn't work.

class DummyCharField(BaseDummyCharField):
    def __init__(self, *args, **kwargs):
        kwargs['max_length'] = 255
        super().__init__(*args, **kwargs)

    def deconstruct(self):
        name, path, args, kwargs = super().deconstruct()
        del kwargs['max_length']
        return name, path, args, kwargs

As a workaround I made the following:

class DummyCharField(BaseDummyCharField):
    def __init__(self, *args, **kwargs):
        # If wrapped inside an `if`, it works...
        if 'max_length' not in kwargs:
            kwargs['max_length'] = 255
        ...

Am I missing something here or what exactly is my fault in this case?

标签: pythondjangomigration

解决方案


1. Intro

You were using the __init__() method in wrong way.

While Django's makemigrations command, it analyzing the changes made by us. During the process, it calls the __init__() methods to generate the old-parameter and new parameters. (here, old param is max_length=64 and new param is max_length=256)


2. Culprit?

The statement, kwargs['max_length'] = 255 in __init__() method.

The Model Field is initialized with max_length=255 everytime which caused an overwrite here. While detecting the model changes, this statement causes No Changes, since you were set max_length to a "CONSTANT".


3. Solution?

Simply put a if.. condition in __init__() method.

def __init__(self, *args, **kwargs):
    if 'max_length'  not in kwargs:
        kwargs['max_length'] = 255

4. Final Code Snippet

class DummyCharField(BaseDummyCharField):
    def __init__(self, *args, **kwargs):
        kwargs.setdefault('max_length', 123)
        super().__init__(*args, **kwargs)

5. References--[source code]

  1. makemigrations command module
  2. detecting any changes
  3. changes() method of MigrationAutodetector class
  4. _detect_changes() method of MigrationAutodetector class
  5. generate_altered_fields() method of MigrationAutodetector class
  6. deep_deconstruct() method of MigrationAutodetector class

推荐阅读