2015-08-03 10 views
13

Mam główną aplikację django o nazwie "foocore".Zatrzymaj Django przed utworzeniem migracji, jeśli zmieni się lista opcji pola

Istnieje kilka opcjonalnych aplikacji do pluginowania. Na przykład "superfoo".

W moim przypadku każda wtyczka dodaje nowy wybór w modelu CharField, który należy do "foocore".

Migracje Django wykrywają zmiany, jeśli lista opcji zostanie zmieniona.

Myślę, że to nie jest konieczne. Co najmniej jeden inny deweloper myśli tak samo:

https://code.djangoproject.com/ticket/22837

class ActivePlugin(models.Model): 
    plugin_name = models.CharField(max_length=32, choices=get_active_plugins()) 

kodu, aby uzyskać opcje:

class get_active_plugins(object): 
    def __iter__(self): 
     for item in ....: 
      yield item 

Rdzeń „foocore” przyzwyczaja się w kilku projektach i każda instalacja ma inny zestaw wtyczek. Django próbuje utworzyć bezużyteczne migracje ...

Czy istnieje sposób obejścia tego?

+1

Tak to jest straszna cecha. Czuję twój ból. – demux

Odpowiedz

11

Zobacz ten raport o błędzie i dyskusję o więcej informacji: https://code.djangoproject.com/ticket/22837

Proponowane rozwiązanie było użyć wywoływalnym jako argument do wyborów, ale wydaje się to nie zostało wykonane dla pól ale tylko form.

Jeśli naprawdę potrzebujesz dynamicznych opcji niż ForeignKey, to najlepsze rozwiązanie.

Alternatywnym rozwiązaniem może być dodanie wymogu za pomocą niestandardowej metody czyszczenia pola i/lub utworzenia niestandardowego formularza. Pola formularza obsługują wywoływanie choices.

Zobacz tę odpowiedź, aby uzyskać więcej informacji: https://stackoverflow.com/a/33514551/54017

+0

Do tej pory używamy Django 1.7. Wybieralne opcje są obsługiwane, ponieważ Django 1.8 ... – guettli

+2

W takim przypadku możesz mieć pecha dla czystego rozwiązania. Mogę tylko pomyśleć o hackach, aby rozwiązać to dla twojej sprawy ... modyfikując wybory w czasie wykonywania, zakodowując wybory, jeśli 'sys.argv' zawiera' makemigrations', itd. – Wolph

+0

Nie mogę tego użyć do wyboru modeli, zgodnie z Dokumenty są dostępne tylko na forms.ChoiceFields. Próba dodania możliwości wywołania do modelu powoduje, że wybory '(pola.E004) 'muszą być wartością iterowalną (np. Listą lub krotką).' – Andrew

5

miałem podobny problem z niestandardowym polu, które zrobiłem dla Django 1.6 projektu, który miał taką samą ogólną strukturę. Doszedłem do następnego rozwiązania, które działa w porządku:

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 cls 

class ActivePlugin(models.Model, metaclass=ActivePluginMeta): 
    plugin_name_choices = get_active_plugins() 
    plugin_name = models.CharField(max_length=32, choices=[]) 

To jest dla Pythona 3, dla Pythona 2 trzeba określić metaklasą następująco:

class ActivePlugin(models.Model): 
    __metaclass__ = ActivePluginMeta 

    plugin_name_choices = get_active_plugins() 
    plugin_name = models.CharField(max_length=32, choices=[]) 
+0

Dziękuję za tę odpowiedź. – guettli

+0

+1 za bycie sprytnym, ale niestety już to nie działa (mimo to Django 1.10). Wygląda na to, że Django tworzy teraz model przed wykonaniem migracji. = ( – mkoistinen

Powiązane problemy