Taky se vám NĚKDY odpálí signál dvakrát?

Možná se Vám už někdy stalo, že při použití signálu v Djangu se vaše obslužná funkce zavolala vícekrát. Mě se to naposledy stalo dnes.

Best practice

Na umístění kódu pro signály si dávám pozor. Dle dobrých Django mravů mám v adresáři s aplikací soubor signals.py, v něm kód obslužné funkce i její pověšení na konkrétní signál. Na konci models.py pak vkládám import signals a všechno funguje jako víno.

Až do dneška.

Prapodivný test

Dělal jsem drobné změny v projektu a po jejich dokončení spustil testy. Hle, chybička! A jak už to tak bývá, šlo o něco divného — když jsem spustil všechny testy aplikací najednou, došlo k chybě v jednom konkrétním testu. Když jsem ale spustil problémový test samostatně, tak prošel.

Po delší analýze jsem přišel na to, že během inicializace testů dojde k dvojímu zaregistrování funkce na signál (a kvůli tomu má obslužná funkce odvedla svou práci rovněž dvakrát).

Co s tím?

Krátká odpověď: dispatch_uid

Delší odpověď: funkci connect můžete zavolat s parametrem dispatch_uid, který vaší obsluze přiřadí jedinečný identifikátor. Pokud by někdy v budoucnu náhodou mělo dojít k vícenásobnému zaregistrování funkce na signál, s pomocí dispatch_uid funkce connect pozná, že obsuha již zaregistrována byla a další registrace neprovede.

Zavěšování funkcí na signály proto doporučuji provádět následovně:

from django.db.models.signals import pre_save
from myapp.models import MyModel

def my_handler(sender, **kwargs):
    ...

pre_save.connect(my_handler, sender=MyModel, dispatch_uid="jedinecne id")

Poučení? Registrujte své funkce s využitím parametru dispatch_uid a pište testy.

Blog comments powered by Disqus