Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django migration default value callable generates identical entry

I am adding a new field to an existing db table. it is to be auto-generated with strings.
Here is my code:

from django.utils.crypto import get_random_string

...
Model:
    verification_token = models.CharField(max_length=60, null=False, blank=False, default=get_random_string)

I generate my migration file with ./manage.py makemigrations and a file is generated. I verify the new file has default set to field=models.CharField(default=django.utils.crypto.get_random_string, max_length=60)

so all seems fine.
Proceed with ./manage.py migrate it goes with no error from terminal. However when i check my table i see all the token fields are filled with identical values.
enter image description here

Is this something i am doing wrong? How can i fix this within migrations?

like image 715
Justin M. Ucar Avatar asked Jul 22 '26 15:07

Justin M. Ucar


1 Answers

When a new column is added to a table, and the column is NOT NULL, each entry in the column must be filled with a valid value during the creation of the column. Django does this by adding a DEFAULT clause to the column definition. Since this is a single default value for the whole column, your function will only be called once.

You can populate the column with unique values using a data migration. The procedure for a slightly different use-case is described in the documentation, but the basics of the data migrations are as follows:

from django.db import migrations, models
from django.utils.crypto import get_random_string

def generate_verification_token(apps, schema_editor):
    MyModel = apps.get_model('myapp', 'MyModel')
    for row in MyModel.objects.all():
        row.verification_token = get_random_string()
        row.save()

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0004_add_verification_token_field'),
    ]

    operations = [
        # omit reverse_code=... if you don't want the migration to be reversible.
        migrations.RunPython(generate_verification_token, reverse_code=migrations.RunPython.noop),
    ]

Just add this in a new migration file, change the apps.get_model() call and change the dependencies to point to the previous migration in the app.

like image 55
knbk Avatar answered Jul 25 '26 09:07

knbk



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!