Stop Django from creating migrations if the list of choices of a field changes
See this bug report and discussion for more info: https://code.djangoproject.com/ticket/22837
The proposed solution was to use a callable as the argument for choices, but it appears this has not been executed for fields but for forms only.
If you really need dynamic choices than a ForeignKey
is the best solution.
An alternative solution can be to add the requirement through a custom clean method for the field and/or creating a custom form. Form fields do support callable choices
.
See this answer for more info: https://stackoverflow.com/a/33514551/54017
I had a similar problem. My choices were dynamic (all years from a starting point to the present) and every year the first time makemigrations
was run it generated new migrations for the new choice. The solution I found was customizing the field so the choices
change wouldn't be detected by makemigrations
:
from django.db import modelsclass YearField(models.IntegerField): description = "A year from 2015 to the present" def deconstruct(self): name, path, args, kwargs = super(YearField, self).deconstruct() # Ignore choice changes when generating migrations kwargs.pop('choices', None) return (name, path, args, kwargs)
I had a similar problem with a custom field that I made for a Django 1.6 project that had the same general structure. I came to the following solution which works alright:
class ActivePluginMeta(ModelBase): def __new__(cls, name, bases, attrs): # Override choices attr cls = models.base.ModelBase.__new__(cls, name, bases, attrs) setattr(cls._meta.get_field('plugin_name'), 'choices', cls.plugin_name_choices) return clsclass ActivePlugin(models.Model, metaclass=ActivePluginMeta): plugin_name_choices = get_active_plugins() plugin_name = models.CharField(max_length=32, choices=[])
That is for python 3, for python 2 you have to specify the metaclass as follows:
class ActivePlugin(models.Model): __metaclass__ = ActivePluginMeta plugin_name_choices = get_active_plugins() plugin_name = models.CharField(max_length=32, choices=[])