I recently used Django admin to add and remove data through the backend UI. The model field used choices to render a dropdown, but later I found that every time the choices list changed, Django wanted to generate a new migration file. To avoid that, I looked for a way to make the choices dynamic.
Suppose we start with a model like this:
1 2 3 4 5 6 7 8 from django.db import modelsclass Dynamics (models.Model ): source = models.CharField(max_length=64 , choices=( ('baidu' , 'baidu' ), ('google' , 'google' ), ))
After running makemigrations, the generated migration contains the choices inline:
1 2 3 4 5 6 7 8 9 operations = [ migrations.CreateModel( name='Dynamics' , fields=[ ('id' , models.AutoField(auto_created=True , primary_key=True , serialize=False , verbose_name='ID' )), ('source' , models.CharField(choices=[('baidu' , 'baidu' ), ('google' , 'google' )], max_length=64 )), ], ), ]
That means every later change to choices triggers a new migration.
One workaround is to generate the choices from a helper function:
1 2 3 4 5 6 7 8 9 10 11 12 13 from django.db import modelsdef get_source_choices (): return ( ('baidu' , 'baidu' ), ('google' , 'google' ), ('duckduckgo' , 'duckduckgo' ), ) class Dynamics (models.Model ): source = models.CharField(max_length=64 , choices=get_source_choices())
Then modify the migration file that was generated earlier so that it imports and calls the same function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from django.db import migrations, modelsfrom ..models import get_source_choicesclass Migration (migrations.Migration ): initial = True dependencies = [ ] operations = [ migrations.CreateModel( name='Dynamics' , fields=[ ('id' , models.AutoField(auto_created=True , primary_key=True , serialize=False , verbose_name='ID' )), ('source' , models.CharField(choices=get_source_choices(), max_length=64 )), ], ), ]
After that, future changes only need to update get_source_choices(), and no new migration will be generated just because the dropdown options changed.