2015-08-03 12 views
13

Ho un'app core di django chiamata "foocore".Arresta Django dalla creazione di migrazioni se l'elenco delle scelte di un campo cambia

Esistono diverse app plug-in opzionali. Ad esempio "superfoo".

Nel mio caso ogni plugin aggiunge una nuova scelta in un modello CharField che appartiene a "foocore".

Le migrazioni di Django rilevano le modifiche se l'elenco delle scelte viene modificato.

Penso che questo non sia necessario. Almeno un altro sviluppatore pensa lo stesso:

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

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

Il codice per ottenere le scelte:

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

Il nucleo "foocore" viene utilizzato in diversi progetti e ogni installazione ha un diversi set di plugin. Django cerca di creare migrazioni inutili ....

C'è un modo per aggirare questo?

+1

Sì questa è una caratteristica terribile. Condivido il tuo dolore. – demux

risposta

11

Vai a questa segnalazione di bug e la discussione per ulteriori informazioni: https://code.djangoproject.com/ticket/22837

La soluzione proposta era quella di utilizzare un richiamabile come argomento per le scelte, ma sembra che non è stato eseguito per i campi, ma solo per le forme.

Se hai davvero bisogno di scelte dinamiche, una soluzione ForeignKey è la migliore.

Una soluzione alternativa può essere quella di aggiungere il requisito tramite un metodo di pulizia personalizzato per il campo e/o la creazione di un modulo personalizzato. I campi modulo supportano callable choices.

Vedere questa risposta per maggiori informazioni: https://stackoverflow.com/a/33514551/54017

+0

Utilizziamo Django 1.7 fino ad ora. Le scelte richiamabili sono supportate dal momento che Django 1.8 ... – guettli

+2

In tal caso potresti essere sfortunato per una soluzione pulita. Posso solo pensare agli hack per risolverlo per il tuo caso ... modificando le scelte in fase di esecuzione, codificando le scelte se 'sys.argv' contiene' makemigrations', ecc. – Wolph

+0

Non riesco a far funzionare tutto questo sulle scelte dei modelli, secondo docs è disponibile solo su forms.ChoiceFields. Il tentativo di aggiungere un callable alle scelte del modello solleva un '(fields.E004) 'choice' deve essere un iterable (ad es. Un elenco o una tupla) .' – Andrew

5

Ho avuto un problema simile con un campo personalizzato che ho fatto per un progetto di 1.6 Django che aveva la stessa struttura generale. Sono venuto per la seguente soluzione che funziona bene:

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=[]) 

Questo è per Python 3, per Python 2 è necessario specificare il metaclasse come segue:

class ActivePlugin(models.Model): 
    __metaclass__ = ActivePluginMeta 

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

Grazie per questa risposta. – guettli

+0

+1 per essere intelligenti ma, purtroppo anche questo non funziona più (Django 1.10 comunque). Mi sembra che Django ora istanzia il modello prima di effettuare le migrazioni. = ( – mkoistinen

Problemi correlati