22

I have one model in my app running in a server with a few entries. I need to add a SlugField, unique and not-null for this model. The SlugField will be populated based on trading_name. I've changed my model in order to add this new field and modified save method:

class Supplier(StatusModel):
    SLUG_MAX_LENGTH = 210
    slug = models.SlugField(unique=True, max_length=SLUG_MAX_LENGTH)
    trading_name = models.CharField(max_length=200, verbose_name=_('trading name'))
    ...

    def save(self, *args, **kwargs):
        self.slug = orig = slugify(self.trading_name)[:Supplier.SLUG_MAX_LENGTH]

        for x in itertools.count(1):
            if not Supplier.objects.filter(slug=self.slug).exists():
                break
            # Truncate the original slug dynamically. Minus 1 for the hyphen.
            self.slug = "%s-%d" % (orig[:Supplier.SLUG_MAX_LENGTH - len(str(x)) - 1], x)

        self.full_clean()
        super(Supplier, self).save(*args, **kwargs)

After changing the model, I've run manage.py makemigrations and got this migration as output:

class Migration(migrations.Migration):

    dependencies = [
        ('opti', '0003_auto_20141226_1755'),
    ]

    operations = [
        migrations.AddField(
            model_name='supplier',
            name='slug',
            field=models.SlugField(unique=True, default='', max_length=210),
            preserve_default=False,
        ),
    ]

I can't run manage.py migrate because the default value wont work due to the unique constrant.

My question is: How can I do this with Django 1.7? I need to apply the schema change and keep the current entries in my database.

MatheusJardimB
  • 3,599
  • 7
  • 46
  • 70

2 Answers2

33

Unfortunatelly, I found no answer but I could create one solution:

  • First I have created a migration that allows the slug field to be nullable;
  • Then I have created another migration that populates the slug column with proper values to every row in the model;
  • Then another migration which adds the not-null constraint in the column.
MatheusJardimB
  • 3,599
  • 7
  • 46
  • 70
  • 7
    It looks like this is Django's suggestion as well - https://docs.djangoproject.com/en/1.9/howto/writing-migrations/#migrations-that-add-unique-fields – wasabigeek Feb 28 '16 at 09:16
  • 4
    That link is broken. You can use https://docs.djangoproject.com/en/2.2/howto/writing-migrations/#migrations-that-add-unique-fields – FiddleStix Jan 08 '20 at 12:12
2

You do your model changes (add field, change, etc), then you call manage.py makemigrations, then apply the migrations with manage.py migrate

You can add the field with null=True, then you e.g. make a script to populate it one time

Otherwise, if you need to populate the field within the migration you can write a custom one, see https://docs.djangoproject.com/en/1.7/ref/migration-operations/#writing-your-own

bakkal
  • 54,350
  • 12
  • 131
  • 107