[Fixed]-Default value for foreign key in Django migrations.AddField

32👍

You can’t do it directly. The recommended way of doing this is to create a migration to add it with null=True, then add a data migration that uses either Python or SQL to update all the existing ones to point to available_state_id, then a third migration that changes it to null=False.

23👍

I just had the same issue and stumbled upon this answer, so here is how I did it:

  operations = [
        # We are forced to create the field as non-nullable before
        # assigning each Car to a Brand
        migrations.AddField(
            model_name="car",
            name="brand",
            field=models.ForeignKey(
                null=True,
                on_delete=django.db.models.deletion.PROTECT,
                to="model.Brand",
            ),
        ),

        # assign_car_to_brand loops over all my Car objects and sets their
        # "brand" field
        migrations.RunPython(add_category_to_tags, do_nothing),

        # Make the field non-nullable to force all future Car to have a Brand
        migrations.AlterField(
            model_name="car",
            name="brand",
            field=models.ForeignKey(
                null=False,
                on_delete=django.db.models.deletion.PROTECT,
                to="model.Brand",
            ),
            preserve_default=False
        ),

    ]

2👍

Here is a relatively complete example:

Step One

python manage.py makemigrations, set the temporary default value to None

Step Two

Change the genrated migration code to below style

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


def set_default_author_to_blog(apps, schema_editor):
    User = apps.get_model("auth", "User")
    Blog = apps.get_model("blog", "Blog")
    Blog.objects.update(author=User.objects.first())


def revert_set_default_autor_to_blog(apps, schema_editor):
    Blog = apps.get_model("blog", "Blog")
    Blog.objects.update(author=None)


class Migration(migrations.Migration):
    dependencies = [
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
        ('blog', '0001_auto_20220425_1017'),
    ]

    operations = [
        migrations.AddField(
            model_name='blog',
            name='author',
            field=models.ForeignKey(null=True, db_constraint=False, on_delete=django.db.models.deletion.PROTECT,
                                    to='auth.user', verbose_name='Author')
        ),
        migrations.RunPython(set_default_author_to_blog, reverse_code=revert_set_default_autor_to_blog),
        migrations.AlterField(
            model_name='blog',
            name='author',
            field=models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.PROTECT,
                                    to='auth.user', verbose_name='Author')
        ),
    ]

Step Three

python manage.py migrate

Leave a comment