Search code examples
pythondjangodjango-modelsdjango-rest-frameworkdjango-migrations

Unable to apply migration on altered model in django


I am new to django. I have changed some fields in my already created Django model. But It says this message when I try to apply migrations on it:

It is impossible to add a non-nullable field 'name' to table_name without specifying a default. This is because the database needs something to populate existing rows.
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
 2) Quit and manually define a default value in models.py.

Although I have deleted the data of this table from database. I cannot set it's default value because the field has to store unique values. Do I need to delete my previous migration file related to that table?

I have applied data migrations, but still getting the same error when applying migrations again:

def add_name_and_teacher(apps, schema_editor):
    Student = apps.get_model('app_name', 'Student')
    Teacher = apps.get_model('app_name', 'Teacher')
    for student in Student.objects.all():
        student.name = 'name'
        student.teacher = Teacher.objects.get(id=1)
        student.save()

class Migration(migrations.Migration):

    dependencies = [
        ('app', '0045_standup_standupupdate'),
    ]

    operations = [
        migrations.RunPython(add_name_and_teacher),
    ]

Solution

  • So, before you had a nullable field "name". This means that it's possible to have null set as that field's value.

    If you add a not null constraint to that field (null=False), and you run the migrations, you will get an integrity error from the database because there are rows in that table that have null set as that field's value.

    In case you just made two migrations where first you added a nullable field, but then remembered it mustn't be nullable and you added the not null constraint, you should simply revert your migrations and delete the previous migration. It's the cleanest solution.

    You can revert by running python manage.py migrate <app name> <the migration that you want to keep>

    Then you simply delete the new migrations and run python manage.py makemigrations again.

    In case the migration with the nullable field was defined very early on and there is already data there and it's impossible to delete that migration, you will need to figure out how to populate that data. Since you say that there is also the unique constraint, you can't just provide a default because it will cause issues with that constraint.

    My suggestion is to edit the migration file and add migrations.RunSQL where you write custom SQL code which will insert values to the field. Make sure you place the RunSQL operation before the operation that adds the not null constraint (it should be AlterField or AddConstraint) as they are run in order.

    You could also use migrations.RunPython, but I prefer the RunSQL because future changes in the code might break your migrations which is a hassle to deal with.

    Docs for RunSQL