2015-10-15 4 views
5

J'ai un modèle avec des choix dynamiques, et je voudrais retourner une liste de choix vide si je peux garantir que le code est exécuté dans le cas d'un Commande django-admin.py migrate/makemigrations pour l'empêcher de créer ou de signaler des modifications de choix inutiles.Détecter si le code est en cours d'exécution dans le contexte de la commande migrate/makemigrations

code:

from artist.models import Performance 
from location.models import Location 

def lazy_discover_foreign_id_choices(): 
    choices = [] 

    performances = Performance.objects.all() 
    choices += {performance.id: str(performance) for performance in performances}.items() 

    locations = Location.objects.all() 
    choices += {location.id: str(location) for location in locations}.items() 

    return choices 
lazy_discover_foreign_id_choices = lazy(lazy_discover_foreign_id_choices, list) 


class DiscoverEntry(Model): 
    foreign_id = models.PositiveIntegerField('Foreign Reference', choices=lazy_discover_foreign_id_choices(),) 

Je pense donc que si je peux détecter le contexte de l'exécution dans lazy_discover_foreign_id_choices je peux choisir de sortir une liste de choix vide. Je pensais à tester sys.argv et __main__.__name__ mais j'espère qu'il y a peut-être un moyen plus fiable ou une API?

+1

Comment vos choix sont-ils dynamiques? Pourriez-vous poster du code? – aumo

+0

Bien sûr, code ajouté – DanH

+0

Comment importer 'Performance' et' Location'? – Ivan

Répondre

2

Une solution que je peux penser serait de sous-classer la commande Django makemigrations pour définir un indicateur avant d'effectuer réellement l'opération réelle.

Exemple:

Mettez ce code dans <someapp>/management/commands/makemigrations.py, il remplace par défaut commande makemigrations de Django.

from django.core.management.commands import makemigrations 
from django.db import migrations 


class Command(makemigrations.Command): 
    def handle(self, *args, **kwargs): 
     # Set the flag. 
     migrations.MIGRATION_OPERATION_IN_PROGRESS = True 

     # Execute the normal behaviour. 
     super(Command, self).handle(*args, **kwargs) 

Faites de même pour la commande migrate.

Et modifier votre choix fonction dynamique:

from django.db import migrations 


def lazy_discover_foreign_id_choices(): 
    if getattr(migrations, 'MIGRATION_OPERATION_IN_PROGRESS', False): 
     return [] 
    # Leave the rest as is. 

Il est très hacky mais assez facile à installer.

+0

Merci pour la suggestion, mais cela ne fonctionne pas. On dirait que le choix du champ du modèle est exécuté avant 'Command.handle()' – DanH

+0

Je l'ai essayé sur un de mes projets et ça a semblé fonctionner, je vais enquêter. – aumo

+0

@DanH Je confirme que cela fonctionne bien sur une installation propre de Django 1.8.5, êtes-vous sûr que c'est la nouvelle commande qui est exécutée et non celle par défaut? – aumo

4

Voici une façon assez non hacky de le faire (depuis django crée déjà des drapeaux pour nous):

import sys 
def lazy_discover_foreign_id_choices(): 
    if ('makemigrations' in sys.argv or 'migrate' in sys.argv): 
     return [] 
    # Leave the rest as is. 

Cela devrait fonctionner dans tous les cas.

+0

Oh, c'est une très bonne façon de faire ça. –