Django 2.1

Signals




django

Signals

Django में एक "सिग्नल डिस्पैचर" शामिल है, जो डिक्रूफ़ किए गए एप्लिकेशन को अधिसूचित करने में मदद करता है जब फ्रेमवर्क में कहीं और कार्रवाई होती है। संक्षेप में, संकेत कुछ प्रेषकों को रिसीवर के एक सेट को सूचित करने की अनुमति देते हैं कि कुछ कार्रवाई हुई है। वे विशेष रूप से उपयोगी होते हैं जब कोड के कई टुकड़े समान घटनाओं में रुचि रखते हैं।

Django अंतर्निहित संकेतों का एक सेट प्रदान करता है जो उपयोगकर्ता कोड को Django द्वारा कुछ कार्यों के बारे में सूचित करने देता है। इनमें कुछ उपयोगी सूचनाएं शामिल हैं:

पूरी सूची के लिए अंतर्निहित सिग्नल प्रलेखन , और प्रत्येक संकेत का पूरा विवरण देखें।

आप अपने स्वयं के कस्टम संकेतों को भी परिभाषित और भेज सकते हैं ; निचे देखो।

संकेतों को सुनकर

सिग्नल प्राप्त करने के लिए, Signal.connect() विधि का उपयोग करके एक रिसीवर फ़ंक्शन पंजीकृत करें। सिग्नल भेजे जाने पर रिसीवर फंक्शन को कहा जाता है।

Signal.connect(receiver, sender=None, weak=True, dispatch_uid=None) [source]
पैरामीटर:
  • रिसीवर - कॉलबैक फ़ंक्शन जो इस सिग्नल से जुड़ा होगा। अधिक जानकारी के लिए रिसीवर फ़ंक्शंस देखें।
  • प्रेषक - संकेत प्राप्त करने के लिए किसी विशेष प्रेषक को निर्दिष्ट करता है। अधिक जानकारी के लिए विशिष्ट प्रेषकों द्वारा भेजे गए संकेतों से जुड़ना देखें।
  • कमजोर - Django सिग्नल संचालकों को डिफ़ॉल्ट रूप से कमजोर संदर्भ के रूप में संग्रहीत करता है। इस प्रकार, यदि आपका रिसीवर एक स्थानीय फ़ंक्शन है, तो यह कचरा एकत्र किया जा सकता है। इसे रोकने के लिए, सिग्नल के connect() विधि को कॉल करने पर weak=False पास करें।
  • dispatch_uid - उन मामलों में सिग्नल रिसीवर के लिए एक विशिष्ट पहचानकर्ता, जहां डुप्लिकेट सिग्नल भेजे जा सकते हैं। अधिक जानकारी के लिए डुप्लिकेट संकेतों को रोकना देखें।

आइए देखें कि यह कैसे काम करता है एक सिग्नल दर्ज करके जो प्रत्येक HTTP अनुरोध समाप्त होने के बाद कहा जाता है। हम django.core.signals.request_finished सिग्नल से django.core.signals.request_finished

रिसीवर के कार्य

सबसे पहले, हमें एक रिसीवर फ़ंक्शन को परिभाषित करने की आवश्यकता है। एक रिसीवर किसी भी पायथन फ़ंक्शन या विधि हो सकता है:

def my_callback(sender, **kwargs):
    print("Request finished!")

ध्यान दें कि फ़ंक्शन वाइल्डकार्ड कीवर्ड तर्क ( **kwargs ) के साथ एक sender तर्क लेता है; सभी सिग्नल हैंडलर को ये तर्क देने होंगे।

हम प्रेषकों को थोड़ा बाद में देखेंगे, लेकिन अभी **kwargs तर्क पर नज़र डालते हैं। सभी सिग्नल कीवर्ड तर्क भेजते हैं, और किसी भी समय वे कीवर्ड तर्क बदल सकते हैं। django.core.signals.request_finished के मामले में, इसे कोई तर्क नहीं भेजने के रूप में प्रलेखित किया गया है, जिसका अर्थ है कि हमें my_callback(sender) रूप में हमारे सिग्नल हैंडलिंग को लिखने के लिए लुभाया जा सकता है।

यह गलत होगा - वास्तव में, यदि आप ऐसा करते हैं तो Django एक त्रुटि फेंक देगा। ऐसा इसलिए है क्योंकि किसी भी बिंदु पर तर्क सिग्नल में जुड़ सकते हैं और आपका रिसीवर उन नए तर्कों को संभालने में सक्षम होना चाहिए।

रिसीवर कार्यों को जोड़ना

एक रिसीवर को सिग्नल से कनेक्ट करने के दो तरीके हैं। आप मैनुअल कनेक्ट मार्ग ले सकते हैं:

from django.core.signals import request_finished

request_finished.connect(my_callback)

वैकल्पिक रूप से, आप एक receiver() डेकोरेटर का उपयोग कर सकते हैं:

receiver(signal) [source]
पैरामीटर: सिग्नल - किसी फ़ंक्शन को कनेक्ट करने के लिए सिग्नल या सिग्नल की सूची।

यहां बताया गया है कि आप डेकोरेटर से कैसे जुड़ते हैं:

from django.core.signals import request_finished
from django.dispatch import receiver

@receiver(request_finished)
def my_callback(sender, **kwargs):
    print("Request finished!")

अब, हमारे my_callback फ़ंक्शन को प्रत्येक बार अनुरोध समाप्त होने पर कहा जाएगा।

यह कोड कहां रहना चाहिए?

कड़ाई से बोलना, सिग्नल हैंडलिंग और पंजीकरण कोड आप की तरह कहीं भी रह सकते हैं, हालांकि यह आयात कोड के साइड-इफेक्ट को कम करने के लिए एप्लिकेशन के रूट मॉड्यूल और इसके models मॉड्यूल से बचने के लिए अनुशंसित है।

व्यवहार में, सिग्नल हैंडलर आमतौर पर उस एप्लिकेशन के signals में परिभाषित किए जाते हैं जो वे संबंधित हैं। सिग्नल रिसीवर आपके एप्लिकेशन कॉन्फ़िगरेशन क्लास के ready() तरीके से जुड़े हुए हैं। यदि आप receiver() डेकोरेटर का उपयोग कर रहे हैं, तो बस ready() अंदर signals सबमॉड्यूल आयात करें।

ध्यान दें

परीक्षण के दौरान ready() विधि को एक से अधिक बार निष्पादित किया जा सकता है, इसलिए आप अपने संकेतों को दोहराव से संरक्षित करना चाह सकते हैं, खासकर यदि आप उन्हें परीक्षणों के भीतर भेजने की योजना बना रहे हैं।

विशिष्ट प्रेषकों द्वारा भेजे गए संकेतों से जुड़ना

कुछ संकेतों को कई बार भेजा जाता है, लेकिन आप केवल उन संकेतों का एक निश्चित सबसेट प्राप्त करने में रुचि लेंगे। उदाहरण के लिए, किसी मॉडल के सहेजे जाने से पहले भेजे गए django.db.models.signals.pre_save सिग्नल पर विचार करें। अधिकांश समय, आपको यह जानने की जरूरत नहीं है कि कोई मॉडल कब सहेजा जाता है - बस जब एक विशिष्ट मॉडल सहेजा जाता है।

इन मामलों में, आप केवल विशेष प्रेषकों द्वारा भेजे गए संकेतों को प्राप्त करने के लिए पंजीकरण कर सकते हैं। django.db.models.signals.pre_save के मामले में, प्रेषक सहेजे जाने वाले मॉडल वर्ग होगा, इसलिए आप संकेत दे सकते हैं कि आप केवल कुछ मॉडल द्वारा भेजे गए संकेत चाहते हैं:

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


@receiver(pre_save, sender=MyModel)
def my_handler(sender, **kwargs):
    ...

my_handler फ़ंक्शन को तभी बुलाया जाएगा जब MyModel का एक उदाहरण सहेजा जाएगा।

विभिन्न संकेत उनके प्रेषक के रूप में विभिन्न वस्तुओं का उपयोग करते हैं; आपको प्रत्येक विशेष सिग्नल के विवरण के लिए अंतर्निहित सिग्नल प्रलेखन से परामर्श करने की आवश्यकता होगी।

नकल के संकेतों को रोकना

कुछ परिस्थितियों में, सिग्नल को रिसीवर्स को जोड़ने वाला कोड कई बार चल सकता है। यह आपके रिसीवर फ़ंक्शन को एक से अधिक बार पंजीकृत करने का कारण बन सकता है, और इस प्रकार एकल सिग्नल घटना के लिए कई बार कॉल किया जा सकता है।

यदि यह व्यवहार समस्याग्रस्त है (जैसे कि जब भी कोई मॉडल सहेजा जाता है तो ईमेल भेजने के लिए संकेतों का उपयोग करते हुए), अपने रिसीवर फ़ंक्शन की पहचान करने के लिए dispatch_uid तर्क के रूप में एक अद्वितीय पहचानकर्ता पास करें। यह पहचानकर्ता आम तौर पर एक स्ट्रिंग होगा, हालांकि कोई भी धुलाई योग्य वस्तु पर्याप्त होगी। अंतिम परिणाम यह है कि आपका रिसीवर फंक्शन केवल एक बार प्रत्येक dispatch_uid लिए संकेत के लिए बाध्य होगा। मूल्य:

from django.core.signals import request_finished

request_finished.connect(my_callback, dispatch_uid="my_unique_identifier")

संकेतों को परिभाषित करना और भेजना

आपके एप्लिकेशन सिग्नल इन्फ्रास्ट्रक्चर का लाभ उठा सकते हैं और अपने स्वयं के सिग्नल प्रदान कर सकते हैं।

संकेतों को परिभाषित करना

class Signal(providing_args=list) [source]

सभी संकेत django.dispatch.Signal उदाहरण हैं। Provide_args तर्कों के नामों की एक सूची है जो श्रोताओं को संकेत प्रदान करेगा। यह विशुद्ध रूप से दस्तावेजी है, हालाँकि, ऐसा कुछ भी नहीं है जो यह जाँचता है कि संकेत वास्तव में अपने श्रोताओं को ये तर्क प्रदान करता है।

उदाहरण के लिए:

import django.dispatch

pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])

यह एक pizza_done संकेत देता है जो toppings और size तर्कों के साथ रिसीवर प्रदान करेगा।

याद रखें कि आपको किसी भी समय तर्कों की इस सूची को बदलने की अनुमति है, इसलिए पहली कोशिश में एपीआई अधिकार प्राप्त करना आवश्यक नहीं है।

संकेत भेजना

Django में सिग्नल भेजने के दो तरीके हैं।

Signal.send(sender, **kwargs) [source]
Signal.send_robust(sender, **kwargs) [source]

सिग्नल भेजने के लिए, या तो Signal.send() (सभी अंतर्निहित सिग्नल इसका उपयोग करते हैं) या Signal.send_robust() । आपको sender तर्क प्रदान करना चाहिए (जो कि अधिकांश समय एक वर्ग है) और आपको जितने चाहें उतने अन्य कीवर्ड तर्क प्रदान कर सकते हैं।

उदाहरण के लिए, यहां बताया गया है कि हमारा pizza_done संकेत कैसे भेज सकता है:

class PizzaStore:
    ...

    def send_pizza(self, toppings, size):
        pizza_done.send(sender=self.__class__, toppings=toppings, size=size)
        ...

दोनों send() और send_robust() टपल जोड़े की एक सूची लौटाते हैं [(receiver, response), ... ] , जिसे रिसीवर फ़ंक्शंस की सूची और उनके प्रतिक्रिया मूल्यों का प्रतिनिधित्व करते हैं।

send() send_robust() से भिन्न होता है कि कैसे रिसीवर फ़ंक्शंस द्वारा उठाए गए अपवादों को संभाला जाता है। send() रिसीवर्स द्वारा उठाए गए किसी भी अपवाद को नहीं पकड़ता है; यह केवल त्रुटियों को प्रचारित करने की अनुमति देता है। इस प्रकार सभी प्राप्तकर्ताओं को त्रुटि की स्थिति में सिग्नल की सूचना नहीं दी जा सकती है।

send_robust() पायथन के Exception क्लास से निकली सभी त्रुटियों को पकड़ता है, और यह सुनिश्चित करता है कि सभी रिसीवर सिग्नल से सूचित हो जाएं। यदि कोई त्रुटि होती है, तो त्रुटि उदाहरण टुपल जोड़ी में उस रिसीवर के लिए लौटाया जाता है जिसने त्रुटि को उठाया था।

ट्रेसबैक, __traceback__ पर मौजूद हैं, जो send_robust() कॉल करते समय लौटी त्रुटियों की विशेषता है।

संकेतों को डिस्कनेक्ट कर रहा है

Signal.disconnect(receiver=None, sender=None, dispatch_uid=None) [source]

सिग्नल से किसी रिसीवर को डिस्कनेक्ट करने के लिए, सिग्नल Signal.disconnect() कॉल करें। तर्कों को Signal.connect() रूप में वर्णित किया गया है। यदि रिसीवर डिस्कनेक्ट हो गया है और नहीं तो False

receiver तर्क पंजीकृत रिसीवर को डिस्कनेक्ट करने का संकेत देता है। यह None हो सकता है अगर रिसीवर की पहचान करने के लिए dispatch_uid का उपयोग किया जाता है।