0%

Generate Django Model Choices Dynamically

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 models


class 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 models


def 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, models
from ..models import get_source_choices


class 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.

如果我的文字帮到了您,那么可不可以请我喝罐可乐?