[afpy/django] Exécution multiple des signaux lorsqu'on les définie dans models.py ?

Lior Gradstein lior at gradstein.info
Sam 16 Mai 23:06:14 CEST 2009


Tu as tout à fait raison :-) J'avais oublié de poster la réponse
(j'étais pressé de rentrer chez moi, on était vendredi soir :-)

Pour résumer ma situation, histoire que vous compreniez bien :

Si l'on fait un "signals.pre_save.connect(ma_methode, sender=MyModel)"
dans son models.py, dans la théorie il sera exécuté à chaque fois que
l'on fait un 'from models import MonModel', ce qui est assez courant
(dans admin.py, form.py, fields.py, etc).

Pour empêcher ça, les dev de Django ont mis un test dans
django/dispatch/dispatcher.py:
class Signal:
[...]
   def connect(...):
       [...]
       lookup_key = (_make_id(receiver), _make_id(sender))
       for r_key, _ in self.receivers:
            if r_key == lookup_key:
                break
[...]

En gros, on prend la signature du module qui est appelé et on la
compare à la liste des méthodes déjà stockées. Mon problème c'était
que à un endroit j'avais mis un 'from monapp.models import MonModele'
et dans un autre module 'from models import MonModele', ce qui donne
une signature différente...


Merci benoit !


2009/5/16 Benoit Chesneau <bchesneau at gmail.com>:
> Le 16 mai 2009 18:37, Stéphane Bunel <stephane+djangofr at bpf.st> a écrit :
>> Le vendredi 15 mai 2009 11:57:16, Lior Gradstein a écrit :
>>> Bonjour,
>>>
>>> J'attache une methode à un signal avec la commande
>>> "signals.pre_save.connect(ma_methode, sender=MonModele)", que j'inclue dans
>>> mon fichier models.py:
>>>
>>> def ma_methode(sender, instance, signal, *args, **kwargs):
>>>    print "Hello world"
>>>
>>> from django.db.models import signals
>>> signals.pre_save.connect(ma_methode, sender=MyModel)
>>>
>>>
>>> Mon problème: si je mets un print dans cette methode, je vois qu'elle est
>>> appelée plusieurs fois lors de la création de mon modele (soumission de mon
>>> formulaire), alors qu'il ne devrait y passer qu'une fois.
>>>
>>> La raison: j'ai mis ce signals.pre_save.connect() à la fin de mon models.py,
>>> ce qui fait qu'il est exécuté dès que dans un autre module je fais un "from
>>> models import MyModel" (par exemple dans mon form.py, ce que, je suppose,
>>> tout le monde fait). Pourtant, lorsque je regarde dans ce qui se fait dans
>>> les autres projets, le placement dans le models.py est recommandé.
>>>
>>> Alors comment est-ce possible ? Je ne souhaite pas que ma méthode soit
>>> appelée plusieurs fois !
>>
>> J'ai rencontré ce cas. Il est en fait très logique car le dispatcher est
>> sollicité à chaque import et enregistre donc plusieurs fois les signaux.
>>
>> Pour éviter d'enregistrer plusieurs fois le même signal il suffit de lui donner
>> un identifiant au moment de l'enregistrer.
>>
>> Ainsi le dispatcher pourra alors se rendre compte, grâce à l'identifiant, si
>> l'on tente d'enregistrer plusieurs fois le même signale.
>>
>> Exemple:
>>
>> signals.post_save.connect( person_post_save_callback,
>>    sender = Person,
>>    dispatch_uid = 'person_post_save_callback' )
>>
>> Je donne le nom de la méthode invoquée comme identifiant mais c'est un choix
>> personnel et arbitraire.
>>
>> Stéphane Bunel.
>> (...)
>>
>> _______________________________________________
>> django mailing list
>> django at lists.afpy.org
>> http://lists.afpy.org/mailman/listinfo/django
>>
>
> rien de logique à cela si on on considère que id donne un identifiant
> unique. Ceci dit comme vu sur irc models.mafonction ne renvoie pas le
> même id que mafonction seul. D'ou le problème et la nécessité quand on
> est pas homogène dans son code d'utiliser dispatch_uid.
>
> Dans tous les cas il serait bien quand une personne a trouvé ou eu une
> réponse sur irc de mettre à jour ses posts sur la ml. Et de partager
> dans le même temps la solution ;) Just a talk....
> _______________________________________________
> django mailing list
> django at lists.afpy.org
> http://lists.afpy.org/mailman/listinfo/django
>


Plus d'informations sur la liste de diffusion django