在 Django 迁移创建期间忽略 CharField "choices" 中的更改
Ignore changes in CharField "choices" during Django migration creation
我正在构建一个开源可重复使用的应用程序,它需要该应用程序的用户能够在 settings
中的某些 CharField
字段上设置自己的 choices
。
是否 possible/reasonable 让 Django 忽略对 choices
字段选项的更改并且从不(应该添加该功能)实现数据库级选择选择?
这不是实际代码,而是
这将在 models.py
class Owner(models.Model):
city = models.CharField(
verbose_name=u'City',
max_length=255,
blank=True,
choices=settings.CITIES,
db_index=True)
这将在 settings.py
CITIES = (
('chicago', 'Chicago, IL'),
('milwaukee', 'Milwaukee, WI')
)
这将导致此迁移
class Migration(migrations.Migration):
operations = [
migrations.CreateModel(
name='owner',
fields=[
('city', models.CharField(blank=True, max_length=3, db_index=True, choices=[(b'chicago', b'Chicago, IL'), (b'milwaukee', b'Milwaukee, WI')])),
]
现在,假设最终用户想要更改他们的应用程序以在他们的 settings.py
CITIES = (
('los_angeles', 'Los Angeles, CA'),
('san_fransisco', 'San Fransisco, CA')
)
这将导致使用 python manage.py makemigrations
创建另一个迁移,如下所示:
class Migration(migrations.Migration):
dependencies = [
('appname', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='user',
name='city',
field=models.CharField(blank=True, max_length=255, verbose_name='City', db_index=True, choices=[(b'los_angeles', b'Los Angeles, CA'), (b'san_fransisco', b'San Fransisco, CA')]),
),
]
即使该应用的其他用户可能拥有完全不同的支持城市列表。
稍后当我发布具有 0002
迁移编号的开源应用程序的新版本时,这可能会导致冲突,并且如果有数据库级别的选择强制执行,这可能会造成严重破坏。
是否可以让 Django 在迁移创建期间忽略对 choices
字段的更改?扩展 CharField
似乎是合理的。
或者我是否必须使用永不更改的 ForeignKey
重构它并将 select_related()
添加到管理器?
我不会让我在 database/ORM 明智地验证所有事情变得那么困难,但是以 controller/the 形式进行验证。
以下是我将基于您的示例代码执行的操作:
models.py:
class Owner(models.Model):
city = models.CharField(
verbose_name=u'City', max_length=255, blank=True, db_index=True
)
(这里没有选择!)
views.py:
class CitySelectionView(FormView):
template_name = "city_selection.html"
form_class = forms.CitySelectionForm
def form_valid(self, form):
obj = models.Owner(city=form.cleaned_data['city']
obj.save()
return redirect('index')
forms.py:
class CitySelectionForm(forms.Form):
city = forms.MultipleChoiceField(choices=settings.CITIES)
如果城市现在是
CITIES = (('dusseldorf', 'Düsseldorf, Germany'), ('berlin', 'Berlin, Germany'))
表格将显示杜塞尔多夫和柏林,如果是
CITIES = (('london', 'London, UK'), ('paris', 'Paris, France'))
表格将显示伦敦和巴黎。
事实证明这是出于某种原因未启用(来自 this answer)
This is by design. There are several reasons, not least of which for me that datamigrations at points in history need to have a full accurate representation of the models, including all their options not just those which affect the database.
但是,您可以返回初始迁移并执行
class Migration(migrations.Migration):
operations = [
migrations.CreateModel(
name='owner',
fields=[
('city', models.CharField(choices=settings.CITIES, blank=True, max_length=3, db_index=True)),
]
不是很漂亮,理论上它可能会反过来咬你一口,所以在管理器的 get_queryset()
中使用 ForeignKey
和 select_related('cities')
进行重构可能是 safest/least-hacky 解决此问题的方法,但这绝不会导致新的迁移发生 settings
更改导致 choices
更改。
我正在构建一个开源可重复使用的应用程序,它需要该应用程序的用户能够在 settings
中的某些 CharField
字段上设置自己的 choices
。
是否 possible/reasonable 让 Django 忽略对 choices
字段选项的更改并且从不(应该添加该功能)实现数据库级选择选择?
这不是实际代码,而是
这将在 models.py
class Owner(models.Model):
city = models.CharField(
verbose_name=u'City',
max_length=255,
blank=True,
choices=settings.CITIES,
db_index=True)
这将在 settings.py
CITIES = (
('chicago', 'Chicago, IL'),
('milwaukee', 'Milwaukee, WI')
)
这将导致此迁移
class Migration(migrations.Migration):
operations = [
migrations.CreateModel(
name='owner',
fields=[
('city', models.CharField(blank=True, max_length=3, db_index=True, choices=[(b'chicago', b'Chicago, IL'), (b'milwaukee', b'Milwaukee, WI')])),
]
现在,假设最终用户想要更改他们的应用程序以在他们的 settings.py
CITIES = (
('los_angeles', 'Los Angeles, CA'),
('san_fransisco', 'San Fransisco, CA')
)
这将导致使用 python manage.py makemigrations
创建另一个迁移,如下所示:
class Migration(migrations.Migration):
dependencies = [
('appname', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='user',
name='city',
field=models.CharField(blank=True, max_length=255, verbose_name='City', db_index=True, choices=[(b'los_angeles', b'Los Angeles, CA'), (b'san_fransisco', b'San Fransisco, CA')]),
),
]
即使该应用的其他用户可能拥有完全不同的支持城市列表。
稍后当我发布具有 0002
迁移编号的开源应用程序的新版本时,这可能会导致冲突,并且如果有数据库级别的选择强制执行,这可能会造成严重破坏。
是否可以让 Django 在迁移创建期间忽略对 choices
字段的更改?扩展 CharField
似乎是合理的。
或者我是否必须使用永不更改的 ForeignKey
重构它并将 select_related()
添加到管理器?
我不会让我在 database/ORM 明智地验证所有事情变得那么困难,但是以 controller/the 形式进行验证。
以下是我将基于您的示例代码执行的操作:
models.py:
class Owner(models.Model):
city = models.CharField(
verbose_name=u'City', max_length=255, blank=True, db_index=True
)
(这里没有选择!)
views.py:
class CitySelectionView(FormView):
template_name = "city_selection.html"
form_class = forms.CitySelectionForm
def form_valid(self, form):
obj = models.Owner(city=form.cleaned_data['city']
obj.save()
return redirect('index')
forms.py:
class CitySelectionForm(forms.Form):
city = forms.MultipleChoiceField(choices=settings.CITIES)
如果城市现在是
CITIES = (('dusseldorf', 'Düsseldorf, Germany'), ('berlin', 'Berlin, Germany'))
表格将显示杜塞尔多夫和柏林,如果是
CITIES = (('london', 'London, UK'), ('paris', 'Paris, France'))
表格将显示伦敦和巴黎。
事实证明这是出于某种原因未启用(来自 this answer)
This is by design. There are several reasons, not least of which for me that datamigrations at points in history need to have a full accurate representation of the models, including all their options not just those which affect the database.
但是,您可以返回初始迁移并执行
class Migration(migrations.Migration):
operations = [
migrations.CreateModel(
name='owner',
fields=[
('city', models.CharField(choices=settings.CITIES, blank=True, max_length=3, db_index=True)),
]
不是很漂亮,理论上它可能会反过来咬你一口,所以在管理器的 get_queryset()
中使用 ForeignKey
和 select_related('cities')
进行重构可能是 safest/least-hacky 解决此问题的方法,但这绝不会导致新的迁移发生 settings
更改导致 choices
更改。