2015-07-28 4 views
2

Я создаю приложение для многократного использования с открытым исходным кодом, которое требует от пользователей приложения возможности устанавливать свои собственные choices на некоторые поля CharField в settings.Игнорировать изменения в CharField «выборы» во время создания миграции Django

Возможно ли разумное изменение параметров 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() к менеджеру?

Для справки, here's the Django makemigrations inspector code

+1

Это по дизайну, поэтому я все еще использую Юг для выполнения моих миграций. Вот лучшее объяснение вашего вопроса http://stackoverflow.com/questions/26152633/why-does-django-1-7-creates-migrations-for-changes-in-field-choices –

+0

Черт, боялся этого. Нашел хакерский способ сделать это в середине дня сегодня после того, как я прочитал этот ответ/эти билеты и добавил этот ответ. Спасибо за головы! – NickCatal

ответ

1

Оказывается, это не включен по причине (из this answer)

Это дизайн. Есть несколько причин, не в последнюю очередь из-за меня, что данные в точках истории должны иметь полное точное представление моделей, включая все их варианты, а не только те, которые влияют на базу данных.

Однако, вы можете вернуться к первоначальной миграции и сделать

class Migration(migrations.Migration): 
    operations = [ 
     migrations.CreateModel(
      name='owner', 
      fields=[ 
       ('city', models.CharField(choices=settings.CITIES, blank=True, max_length=3, db_index=True)), 
    ] 

Не очень красиво, и это теоретически может вернуться укусить вас вниз по линии, поэтому рефакторинга с ForeignKey и select_related('cities') в get_queryset() в менеджере может быть самым безопасным/наименее опасным способом для этого, но это не должно приводить к новой миграции, произошедшей с изменением settings, что приводит к изменению choices.

0

я бы не сделать это, что трудно на меня, чтобы проверить все базы данных/ОРМ мудрый, но сделать Проверяющий в контроллер/форме.

Вот что я хотел бы сделать здание на примере кода:

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') 

Формы.ру:

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'))

форма покажет Лондон и Париж.

+1

Правильно, это сработает для форм. Но 'owner.get_city_display()' (в appcode)/'{{owner.get_city_display}}' (в шаблонах) не будет работать в этой ситуации. – NickCatal