सिग्नल हैंडलर को django प्रोजेक्ट में कहां रहना चाहिए?


143

मैंने अभी एक django प्रोजेक्ट में सिग्नल श्रोताओं को लागू करना शुरू किया है। जबकि मैं समझता हूं कि वे क्या हैं और उनका उपयोग कैसे करें। मुझे यह पता लगाने में मुश्किल समय हो रहा है कि मुझे उन्हें कहां रखना चाहिए। Django साइट के प्रलेखन में यह कहना है:

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

आप सिग्नल हैंडलिंग और पंजीकरण कोड को अपनी पसंद के अनुसार कहीं भी रख सकते हैं। हालाँकि, आपको यह सुनिश्चित करने की आवश्यकता होगी कि यह जिस मॉड्यूल में आयात किया गया है वह जल्दी से चालू हो जाए ताकि किसी भी सिग्नल को भेजने से पहले सिग्नल हैंडलिंग पंजीकृत हो जाए। यह सिग्नल हैंडलर के पंजीकरण को डालने के लिए आपके ऐप के मॉडल्स को एक अच्छी जगह बनाता है।

जबकि इसका एक अच्छा सुझाव है, मेरे मॉडल में गैर मॉडल कक्षाएं या विधियाँ होना केवल मुझे गलत तरीके से परेशान करता है।

तो फिर, सिग्नल हैंडलर के भंडारण और पंजीकरण के लिए सबसे अच्छा अभ्यास / नियम क्या है?

जवाबों:


41

मैं वास्तव में उन्हें खुद मॉडल का क्लासमेथोड बनाना पसंद करता हूं। यह एक वर्ग के भीतर सब कुछ रखता है, और इसका मतलब है कि आपको कुछ भी आयात करने के बारे में चिंता करने की ज़रूरत नहीं है।


2
और आप आमतौर पर सिग्नल से हैंडलर कहां से जोड़ते हैं?
DataGreed

1
@DataGreed: संबंधित मॉडल के निचले भाग पर Oracle।
डैनियल रोजमैन

102
यदि आप उस मॉडल द्वारा उत्सर्जित संकेतों को सुन रहे हैं तो सभी श्रोताओं को लगा देना भी पूरी कवायद को बेकार कर देता है, है ना? संकेतों की बात डिकॉय करना है। क्या श्रोताओं को उस कोड के साथ नहीं रहना चाहिए जो इन दूरस्थ घटनाओं में रुचि रखता है? सवाल यह है कि श्रोताओं को उत्सर्जकों से पहले कैसे सुनिश्चित किया जाए।
जॉन मी

मेरे मामले में मैं मॉडल का एक संकेत सुनना चाहता हूं Fooजो इसका हिस्सा है fooapp। लेकिन सिग्नल रिसीवर एक विस्तार है और एक अलग ऐप (उदाहरण के लिए otherapp) में रहता है।
गुएटली

2
जॉन मी की बात के लिए, यह केवल ओवरराइड बचाने (), आदि से बहुत अलग नहीं है
मैट

246

जब Django 1.7 जारी किया गया था तो यह दस्तावेज़ में जोड़ा गया था:

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

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

Django 1.7 में परिवर्तित: चूंकि तैयार () Django के पिछले संस्करणों में मौजूद नहीं था, आमतौर पर मॉडल मॉड्यूल में सिग्नल पंजीकरण हुआ।

सबसे अच्छा अभ्यास एक सिग्नल सबमॉड्यूल में अपने हैंडलर को हैंडलरस्टॉक में परिभाषित करना है, उदाहरण के लिए एक फ़ाइल जो दिखता है:

yourapp / सिग्नल / हैंडलरशो :

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):
    pass

अपने सिग्नल हैंडलर को पंजीकृत करने के लिए सबसे अच्छी जगह तब तैयार () पद्धति का उपयोग करते हुए, इसे परिभाषित करने वाले ऐप के AppConfig में है । यह इस तरह दिखेगा:

yourapp / apps.py :

from django.apps import AppConfig

class TasksConfig(AppConfig):
    name = 'tasks'
    verbose_name = "Tasks"

    def ready(self):
        import yourproject.yourapp.signals.handlers #noqa

सुनिश्चित करें कि आप अपने AppConfig को अपनी सेटिंग में सीधे या तो अपने सेटिंग्स के INSTALLED_APPS, या __init__अपने ऐप में निर्दिष्ट करके लोड कर रहे हैं । देखें तैयार () दस्तावेज़ देखें अधिक जानकारी के लिए।

नोट: यदि आप अन्य ऐप्स के लिए भी संकेत प्रदान कर रहे हैं, तो उन्हें सुनने के लिए __init__, अपने सिग्नल मॉड्यूल में डालें , जैसे कि दिखने वाली एक फ़ाइल:

yourapp / संकेत / __ init__.py

import django.dispatch

task_generate_pre_save = django.dispatch.Signal(providing_args=["task"])

इसके बाद एक अन्य ऐप आपके सिग्नल को इम्पोर्ट और रजिस्टर करके सुन सकता है, जैसे from yourapp.signals import task_generate_pre_save। अपने हैंडलर से अपने संकेतों को अलग करना चीजों को साफ रखता है।

Django 1.6 के लिए निर्देश:

यदि आप अभी भी Django 1.6 या उससे कम पर अटके हुए हैं, तो आप एक ही काम करेंगे (अपने हैंडलर को yourapp / सिग्नल / हैंडलरस्टॉक में परिभाषित करें) लेकिन AppConfig का उपयोग करने के बजाय, आप __init__.py के माध्यम से हैंडलर लोड करेंगे आपका एप्लिकेशन, जैसे कुछ:

yourapp / __ init__.py

import signals

यह तैयार () विधि का उपयोग करने के रूप में अच्छा नहीं है क्योंकि यह अक्सर परिपत्र आयात मुद्दों का कारण बनता है।


3
जैसा कि डॉक्युमेंटनोन कहता है कि आप तैयार ओवरराइड करते हैं, आप चाहें तो सुपर (रिपोर्ट्सकॉन्फिग, सेल्फ) (।) जैसे कुछ भी कर सकते हैं। अगर किसी भी तरह से (पहले 1.7.0 के रूप में यह खाली है)
डब्ल्यू- w- - 19

3
मुझे लगता है कि यह उत्तर सबसे अच्छा है क्योंकि यह आयात से होने वाले दुष्प्रभावों को संबोधित करने वाला एकमात्र है। मैं यहां सर्वोत्तम प्रथाओं की खोज में आया था, क्योंकि मैं एक आवेदन की सफाई कर रहा हूं, जो इस तरह के दुष्प्रभावों के कारण बिल्कुल टूट गया है। काश अनुप्रयोग django 1.6 पर चल रहा है, और सर्वोत्तम अभ्यास केवल django 1.7 पर काम करते हैं। __init__आयात सिग्नल देने का अस्थायी समाधान मेरे लिए काम नहीं करेगा, इसलिए मुझे आश्चर्य है कि जब तक हम बाद के django संस्करण में अपग्रेड करने के लिए तैयार नहीं होते हैं, तब तक एक और जगह है जिससे मैं सिग्नल आयात कर सकता हूं।
कास्परड

वहाँ from . import handlers(या समान) में नहीं होना चाहिए yourapp/signals/__init__.py?
झब्बू

क्या आपको कहीं हैंडलरस्टॉक मॉड्यूल का आयात नहीं करना चाहिए? मैं यह कोशिश कर रहा हूँ और यह सिग्नल के लिए हैंडलर को परिभाषित नहीं करता है।
एंड्रेस

1
fwiw मुझे yourproject.टास्ककॉन्फ़ क्लास कोड ब्लॉक की अंतिम पंक्ति में ज़रूरत नहीं थी । मुझे यह ठीक इसी संरचना के साथ काम कर रहा है, इसलिए इस qa पर विचार करें :)
ग्रेग कालेका

40

मैं केवल इस पार आया हूं, और जैसा कि मेरे संकेत मॉडल से संबंधित नहीं हैं मैंने सोचा कि मैं अपना समाधान जोड़ूंगा।

मैं लॉग इन / लॉग आउट के आसपास विभिन्न डेटा लॉग कर रहा हूं और हुक करने की आवश्यकता है django.contrib.auth.signals

मैंने सिग्नल हैंडलर को एक signals.pyफ़ाइल में डाल दिया है , और फिर __init__.pyमॉड्यूल फ़ाइल से सिग्नल को आयात किया है , जैसा कि मेरा मानना ​​है कि जैसे ही यह ऐप शुरू होता है, एक printबयान के साथ परीक्षण करना बताता है कि सेटिंग फ़ाइल पढ़ने से पहले ही इसे कॉल किया जाता है।)

# /project/__init__.py
import signals

और संकेतों में

# /project/signals.py
from django.contrib.auth.signals import user_logged_in

def on_logged_in(sender, user, request, **kwargs):
    print 'User logged in as: \'{0}\''.format(user)

user_logged_in.connect(on_logged_in)

मैं Django (/ अजगर) के लिए बहुत नया हूँ इसलिए किसी को भी यह बताने के लिए खुला हूँ कि यह एक भयानक विचार है!


3
यह तर्कसंगत लगता है, लेकिन मैं इसे ऐप के स्तर पर करने का सुझाव दूंगा।
निल्स

2
सावधान, इस तर्क का सबसे अधिक संभावना है कि नकली संकेतों को निकाल दिया जाएगा। user_logged_in.connect(on_logged_in)सबसे अधिक dispatch_uidतर्क में पारित होने की संभावना होनी चाहिए । Docs.djangoproject.com/en/dev/topics/signals/… पर अधिक ।
स्कॉट कोट

इसके लिए धन्यवाद - अच्छा पता है। मैं इस विधि (आईपी / उपयोगकर्ता एजेंट की रिकॉर्डिंग) का उपयोग करके सभी लॉगइन कर रहा हूं, और अब तक कोई डुप्लिकेट नहीं हुआ है - हालांकि इसका मतलब यह नहीं है कि लाइन के नीचे एक छोटा परिवर्तन एक समस्या का कारण नहीं होगा!
ह्यूगो रोडगर-ब्राउन

13

मैं अभी हाल ही में इस लेख को सर्वोत्तम प्रथाओं के बारे में पढ़ता हूं जब यह आपकी परियोजनाओं / अनुप्रयोगों को बिछाने के लिए आता है, और यह सुझाव देता है कि आपके सभी कस्टम डिस्पैचर संकेतों को एक फ़ाइल में जाना चाहिए signals.py। हालाँकि, यह पूरी तरह से आपकी समस्या का समाधान नहीं करता है, क्योंकि आपको अभी भी इन आयातों को कहीं और करने की आवश्यकता है, और इससे पहले कि वे बेहतर आयात करें।

मॉडल सुझाव एक अच्छा है। चूंकि आपने पहले से ही अपनी signals.pyफ़ाइल में सब कुछ परिभाषित किया है , इसलिए इसे फ़ाइल के शीर्ष पर एक पंक्ति से अधिक नहीं लेना चाहिए। यह उस तरह से है जैसे admin.pyफ़ाइल रखी गई है (शीर्ष पर वर्ग परिभाषाओं और तल पर सभी कस्टम व्यवस्थापक वर्गों को पंजीकृत करने के लिए कोड), यदि आप अपने संकेतों को परिभाषित करते हैं तो उन्हें उसी फ़ाइल में कनेक्ट करें।

उम्मीद है की वो मदद करदे! अंतत: यह नीचे आता है कि आप क्या पसंद करते हैं।


1
मैं अपने सिग्नल हैंडलर को एक signals.pyफ़ाइल में रखना चाहता था , लेकिन यह नहीं जानता था कि इसे बाद में कैसे बुलाया जाए। अपनी models.pyफ़ाइल में इसे आयात करके , मुझे एक बहुत साफ समाधान मिला, बिना मेरे मॉडल के "फ़ाइल प्रदूषण" के। धन्यवाद! :)
डेनिलो बार्गेन

10
वहाँ एक क्रॉस-इम्पोर्ट है:
सिग्नलशो

8

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

मैं लंबे समय से संघर्ष कर रहा था, और आखिरकार हमने इसका हल निकाल लिया।

ऐप फ़ोल्डर में एक कनेक्टर मॉड्यूल बनाएं

तो हमारे पास:

app/
    __init__.py
    signals.py
    models.py
    connectors.py

एप्लिकेशन / कनेक्टर्सहोम में, हमने सिग्नल हैंडलर को परिभाषित किया और उन्हें कनेक्ट किया। एक उदाहरण दिया गया है:

from signals import example_signal
from models import ExampleModel
from django.db.models.signals import post_save, post_delete

def hanndler(sender, *args, **kwargs):
    pass

post_save.connect(hander, sender=ExampleModel)

उसके बाद model.py, हम फाइल के अंत में निम्नलिखित पंक्ति जोड़ते हैं:

from app import connector

यहां सब कुछ किया।

इस तरह, हम संकेतों को Oracle में, और सभी हैंडलर को कनेक्टिकट में डाल सकते हैं। मॉडल और सिग्नल में कोई गड़बड़ नहीं।

आशा है कि यह एक और समाधान प्रदान करता है।


1
तो क्या संकेतों में जाता है? आपके उदाहरण से लगता है कि यह सिर्फ कस्टम सिग्नल है। आमतौर पर हम सिर्फ सिग्नल और कनेक्टर को जोड़ते हैं क्योंकि अधिकांश में कस्टम सिग्नल नहीं होंगे।
d

@ जालंधर हां, सभी कस्टम सिग्नल सिग्नलहोम में डाले जाते हैं। हमारे पास कई अनुकूलित सिग्नल हैं। लेकिन अगर आपके पास कई नहीं हैं, तो इस फाइल को छोड़ा जा सकता है।
सैमुअल

उसी तरह का प्रश्न @ जलद
ओललेह

1
ध्यान दें कि यह सब अब पुरानी सलाह है, django तरीका अब appconfig का उपयोग हैंडलर आयात करने के लिए है जहां सिग्नल हैंडलर रहते हैं। और
सिग्नलहोम में

3

मैं उन्हें एक अलग फ़ाइल में रखता हूं signals.py, models.pyसभी मॉडल परिभाषित होने के बाद। मैं उन्हें आयात करता हूं और सिग्नल से मॉडल जोड़ता हूं।

signals.py

#  necessary imports

def send_mail_on_save(<args>):
    # code here 

models.py

# imports
class mymodel(models.Model):
    # model here

# import signals
from signals import send_mail_on_save
# connect them 
post_save.connect(send_mail_on_save,sender=mymodel)

यह मुझे तार्किक पृथक्करण प्रदान करता है, निश्चित रूप से उन्हें मॉडल-थ्रेड में रखने पर कुछ भी गलत नहीं है , लेकिन यह इस तरह से अधिक प्रबंधनीय है।

उम्मीद है की यह मदद करेगा!!


आप "सिग्नल ओरोमो" में सिग्नल हैंडलर लगा रहे हैं, क्या होगा अगर हम इसे "हैंडलरशो" नाम दें
अब्दुल फतह

1
इससे कोई फर्क नहीं पड़ता कि आप फ़ाइल को सिग्नलहोम या हैंडलरॅक के नाम से जानते हैं। यह सिर्फ एक कन्वेंशन है जो नियम नहीं है।
allsyed

3

के बारे में छोटे अनुस्मारक AppConfig। सेट करने के लिए मत भूलना:

# yourapp/__init__.py

default_app_config = 'yourapp.apps.RockNRollConfig'
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.