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.