我正在构建一个开源可重用应用,需要该应用的用户才能在choices
中的某些CharField
字段上设置自己的settings
。
让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()
添加到管理器中?
答案 0 :(得分:2)
It turns out this is not enabled for a reason (from 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.
However, you can go back to the initial migration and do
Time#round
Not very pretty and it could theoretically come back to bite you down the line, so refactoring with a class Migration(migrations.Migration):
operations = [
migrations.CreateModel(
name='owner',
fields=[
('city', models.CharField(choices=settings.CITIES, blank=True, max_length=3, db_index=True)),
]
and ForeignKey
in the select_related('cities')
in the manager might be the safest/least-hacky way to go about this, but this should never result in a new migration happening with a get_queryset()
change that results in a settings
change.
答案 1 :(得分:0)
I wouldn't make it that difficult on me to validate everything database/ORM wise, but do the validating in the controller/the form.
Here's what I would do building upon your sample code:
models.py:
class Owner(models.Model):
city = models.CharField(
verbose_name=u'City', max_length=255, blank=True, db_index=True
)
(No choices here!)
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)
If cities now is
CITIES = (('dusseldorf', 'Düsseldorf, Germany'), ('berlin', 'Berlin, Germany'))
the form will show Düsseldorf and Berlin, and if it's
CITIES = (('london', 'London, UK'), ('paris', 'Paris, France'))
the form will show London and Paris.