Search code examples
pythondjangodjango-modelsdjango-migrationsdjango-database

Django custom field change not detected by migrations


I have multiple custom fields in Django. First, they extended PositiveSmallIntegerField as we used int choices like:

class BusinessLegalFormField(models.PositiveSmallIntegerField):
    choices = [(1,'SRO'), (2, ....]

    def __init__(self, *args, **kwargs):
        if not args or not args[0]:
            kwargs.setdefault('verbose_name', 'Právna forma')

        kwargs['choices'] = self.choices
        super().__init__(*args, **kwargs)

Then I changed it to CharField and TextChoices:

class BusinessLegalFormField(models.CharField):
    class Choices(models.TextChoices):
        ZIVNOST = 'zivnost', 'Živnosť'
        SRO = 'sro', 'Spoločnosť s ručením obmedzeným'
        AS = 'as', 'Akciová spoločnosť'

    def __init__(self, *args, **kwargs):
        if not args or not args[0]:
            kwargs.setdefault('verbose_name', 'Právna forma')
        kwargs.setdefault('max_length', 64)
        kwargs['choices'] = self.Choices.choices
        super().__init__(*args, **kwargs)

The problem is that I just realized that Django didn't detect the type change. When I change something like null=True to null=False it is detected, but the DB type is not changed from number to char.

How can I make it work?


Solution

  • This very situation, and the solution for it, is described in the documentation:

    You can’t change the base class of a custom field because Django won’t detect the change and make a migration for it... You must create a new custom field class and update your models to reference it.

    class CustomCharField(models.CharField):
        ...
    
    class CustomTextField(models.TextField):
        ...