48 votes

Comment éviter le conflit entre les projecteurs et le code de signal django post_save?

Dans mon application, je veux créer des entrées dans certains tableaux lorsqu'un nouvel utilisateur se connecte. Par exemple, je veux créer un profil utilisateur qui va alors faire référence à leur société et de certains autres dossiers pour eux. Je l'ai fait avec un post_save signal:

def callback_create_profile(sender, **kwargs):
    # check if we are creating a new User
    if kwargs.get('created', True):
        user = kwargs.get('instance')
        company = Company.objects.create(name="My Company")
        employee = Employee.objects.create(company=company, name_first=user.first_name, name_last=user.last_name)
        profile = UserProfile.objects.create(user=user, employee=employee, partner=partner)
# Register the callback
post_save.connect(callback_create_profile, sender=User, dispatch_uid="core.models")

Cela fonctionne bien lorsque vous l'exécutez. Je peux utiliser l'administrateur de créer un nouvel utilisateur et les trois autres tables entrées avec des ainsi. (Sauf que c'est, l'employé, car l'utilisateur.prenom et l'utilisateur.le nom ne sont pas remplis dans l'admin du formulaire lors de l'enregistrement. Je ne comprends toujours pas pourquoi c'est fait comme ça)

Le problème est venu quand j'ai couru mon test de suite. Avant cela, j'avais créé un groupe de luminaires pour créer ces entrées dans les tables. Maintenant, je reçois un message d'erreur indiquant:

IntegrityError: duplicate key value violates unique constraint "core_userprofile_user_id_key"

Je pense que c'est parce que j'ai déjà créé une entreprise,les salariés et les fiches de profil de l'appareil avec l'id "1" et maintenant, le post_save signal est d'essayer de le recréer.

Mon questios sont: puis-je désactiver cette post_save signal lors de l'exécution des montages? Puis-je détecter que je suis en cours d'exécution dans le cadre de la suite de test et de ne pas créer ces dossiers? Dois-je supprimer ces enregistrements des appareils (même si le signal n'établit pas par défaut les valeurs que je veux tester contre)? Pourquoi ne pas le gabarit de chargement de code juste remplacer les disques créés?

Comment les gens font cela?

73voto

poswald Points 840

Je pense que j'ai trouvé un moyen pour ce faire. Il est "brut" paramètre dans la kwargs passé dans le long avec des signaux afin que je puisse remplacer mon test ci-dessus avec celui-ci:

if (kwargs.get('created', True) and not kwargs.get('raw', False)):

Raw est utilisé lors de la loaddata est en cours d'exécution. Ce qui semble faire l'affaire.

Il est mentionné ici: http://code.djangoproject.com/ticket/13299

Ce serait bien si cela a été documenté: http://docs.djangoproject.com/en/1.2/ref/signals/#django.db.models.signals.post_save

18voto

ben Points 753

C'est une vieille question, mais la solution que j'ai trouvée la plus simple consiste à utiliser l'argument 'raw', passé par les données de charge, et à décorer les fonctions d'écoute, par exemple:

 from functools import wraps


def disable_for_loaddata(signal_handler):
    @wraps(signal_handler)
    def wrapper(*args, **kwargs):
        if kwargs['raw']:
            print "Skipping signal for %s %s" % (args, kwargs)
            return
        signal_handler(*args, **kwargs)
    return wrapper
 

puis

 @disable_for_loaddata
def callback_create_profile(sender, **kwargs):
    # check if we are creating a new User
    ...
 

12voto

J.Viola Points 1

Solution simple, ajoutez ceci au début de votre fonction post_save:

 if kwargs.get('raw', False):
    return False
 

Cela entraînera la fermeture de cette fonction lors du chargement d’un appareil.

Voir: https://docs.djangoproject.com/en/dev/ref/signals/#post-save

2voto

Manoj Govindan Points 24030

J'ai fait face à un problème similaire dans un de mes projets. Dans mon cas, les signaux de ralentissement de la tests. J'ai fini par abandonner les signaux en faveur de la substitution d'un Model.save() méthode à la place.

Dans votre cas, cependant, je ne pense pas que cela a du sens pour y parvenir, de remplacer les save() méthodes. Dans ce cas, vous pourriez vouloir essayer cette. Avertissement, je ne l'ai essayé qu'une seule fois. Il semblait que le travail, mais n'est pas testé en profondeur.

  1. Créez votre propre test runner.
  2. Avant de charger les appareils, débranchez l' callback_create_profile fonction de l' User de la classe' post_save de signal.
  3. Laissez-les appareils de charge.
  4. Connecter la fonction de retour du signal.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X