1

I had a Django model that looked like the following:

class Foobar(models.Model):
    baz = models.CharField(max_length=12, default=some_func)

some_func existed in a file /someproj/utils/utils.py

This was fine, and all was well. I created my migration for this model and worked as expected. Roughly the migration looked like:

from __future__ import unicode_literals

from django.db import migrations, models
import someproj.utils.utils


class Migration(migrations.Migration):

    dependencies = [("someproj", "0008_auto_20180928_0002")]

    operations = [
        migrations.CreateModel(
            name="Foobar",
            fields=[
                (
                    "baz",
                    models.CharField(
                        default=someproj.utils.utils.some_func,
                        max_length=12,
                        serialize=False,
                    ),
                ),
            ],
        )
    ]

Then I later realized I wanted to rename some_func to something else. I renamed the function in utils.py, and of course now the migration fails as some_func no longer exists. If I modify the migration by hand that works, but the rule of thumb that was explained to me is you (almost) never edit a migration by hand.

What is a way to accommodate this change? Is it you have to edit the migration by hand? Wouldn't that be problematic if I had to run an older version of the code (ie say I had to checkout a previous commit to a point in time before the rename)?

Adam Parkin
  • 17,891
  • 17
  • 66
  • 87
  • Run `python manage.py makemigrations`, that will rebuild your models. – wanderer0810 Oct 16 '18 at 00:11
  • Do you have information already stored in your `models` that you need to save? – Carl Brubaker Oct 16 '18 at 02:28
  • @CarlBrubaker I did not, which is what I ended up taking advantage of: I deleted this migration & recreated it, dumping everything from the DB. That obviously doesn't feel like a sustainable strategy though so I'd like to learn the best practice to handle this scenario. – Adam Parkin Oct 16 '18 at 15:17
  • 1
    @wanderer0810 I did run makemigrations, which was what errored out since ```some_func``` no longer existed. – Adam Parkin Oct 16 '18 at 15:17
  • You could do a double migration: 1 to delete the field and then another to add it again. Or you probably have to write some method that finds all the objects with some_func set and change it to something else. – Carl Brubaker Oct 16 '18 at 15:54
  • @AdamParkin I see, in that case you can revert a migration by running `python manage.py migrate `. After that you can safely delete it. – wanderer0810 Oct 17 '18 at 19:50

1 Answers1

0

If you only have 1 database, this should work. If you have more than 1, I'm not sure.

Start by writing your method to handle the default of the field:

def rewrite_field_default(self):
    for object in Foobar.objects.all()
        object.baz = some_func
        object.save()

Make an empty migration:

python3 manage.py makemigrations --empty app

Then you can import that into a migration.

operations = [
        migrations.RunPython(rewrite_field_default)
    ]

Then run your migrations as usual.

If it doens't seem to work, let me know.

Carl Brubaker
  • 1,602
  • 11
  • 26