एक Django परियोजना में मेरे संकेतों को रखने के लिए सही जगह


88

Django के दस्तावेज़ीकरण के आधार पर मैं पढ़ रहा था, ऐसा लगता है जैसे signals.pyऐप फ़ोल्डर के साथ शुरू करने के लिए एक अच्छी जगह है, लेकिन मुझे जो समस्या आ रही है वह यह है कि जब मैं सिग्नल बनाता pre_saveहूं और मैं मॉडल से वर्ग आयात करने का प्रयास करता हूं तो यह संघर्ष करता है importमेरे मॉडल में

# models.py

from django.contrib.auth.models import User
from django.db import models
from django.utils.translation import gettext as _
from signals import *

class Comm_Queue(CommunicatorAbstract):
    queue_statuses = (
        ('P', _('Pending')),
        ('S', _('Sent')),
        ('E', _('Error')),
        ('R', _('Rejected')),
    )
    status          = models.CharField(max_length=10, db_index=True, default='P')
    is_html         = models.BooleanField(default=False)
    language        = models.CharField(max_length=6, choices=settings.LANGUAGES)
    sender_email    = models.EmailField()
    recipient_email = models.EmailField()
    subject         = models.CharField(max_length=100)
    content         = models.TextField()

# signals.py

from django.conf import settings
from django.db.models.signals import pre_save
from django.dispatch import receiver
from models import Comm_Queue

@receiver(pre_save, sender=Comm_Queue)
def get_sender_email_from_settings(sender, **kwargs):
    obj=kwargs['instance']
    if not obj.sender_email:
        obj.sender_email='%s' % settings.ADMINS[0][1]

यह कोड नहीं चलेगा क्योंकि मैं Comm_Queueअंदर signals.pyआयात करता हूं और मैं संकेतों को अंदर आयात करता हूं models.py

किसी को कैसे मैं इस मुद्दे पर आ सकता है पर सलाह कर सकते हैं?

सादर


जवाबों:


65

Django <1.7 के लिए मूल उत्तर:

आप signals.pyएप्लिकेशन की __init__.pyफ़ाइल में आयात करके संकेतों को पंजीकृत कर सकते हैं :

# __init__.py
import signals

यह आयात करने की अनुमति देगा models.pyसे signals.pyपरिपत्र आयात त्रुटियों के बिना।

इस दृष्टिकोण के साथ एक समस्या यह है कि यह कवरेज परिणामों को गड़बड़ कर देता है यदि आप कवरेज ऑरेकल का उपयोग कर रहे हैं।

संबंधित चर्चा

संपादित करें: Django के लिए = = 1.7:

चूंकि AppConfig पेश किया गया था, इसलिए संकेत आयात करने का अनुशंसित तरीका इसके init()कार्य में है। देखें एरिक मार्कोस 'जवाब अधिक जानकारी के लिए।


6
Django 1.9 में संकेतों का उपयोग करते हुए, नीचे विधि (django द्वारा अनुशंसित) का उपयोग करें। यह विधि काम नहीं कर रही हैAppRegistryNotReady("Apps aren't loaded yet.")
s0nskar

1
एरिक मार्कोस उनके उत्तर को स्वीकृत उत्तर होना चाहिए: stackoverflow.com/a/21612050/3202958 जब से Django> = 1.7, एप्लिकेशन कॉन्फिग का उपयोग करके
Nrzonline

1
माना। मैं एरिक मार्कोस के जवाब को Django
1.7+ के

195

यदि आप Django <= 1.6 का उपयोग कर रहे हैं, तो मैं कामगाटोस समाधान की सिफारिश करूंगा: बस अपने मॉडल मॉड्यूल के अंत में अपने संकेतों को आयात करें।

Django (> = 1.7) के भविष्य के संस्करणों के लिए, अनुशंसित तरीका यह है कि आप अपने ऐप के कॉन्फ़िगरेशन तैयार () फ़ंक्शन में अपने सिग्नल मॉड्यूल को आयात करें :

my_app/apps.py

from django.apps import AppConfig

class MyAppConfig(AppConfig):
    name = 'my_app'

    def ready(self):
        import my_app.signals

my_app/__init__.py

default_app_config = 'my_app.apps.MyAppConfig'

7
वे 1.7 प्रलेखन में भी उल्लेख करते हैं कि कभी-कभी तैयार होने को कई बार कहा जा सकता है और इसलिए डुप्लिकेट संकेतों से बचने के लिए, अपने सिग्नल कनेक्टर कॉल में एक अद्वितीय पहचानकर्ता संलग्न करें: request_finished.connect (my_callback, dispatch_uid = "myunun_identifier") जहां डिस्पैच_युड आमतौर पर एक स्ट्रिंग है लेकिन कोई भी हैशटेबल ऑब्जेक्ट हो सकता है। docs.djangoproject.com/en/1.7/topics/signals/…
Emeka

13
यह स्वीकृत उत्तर होना चाहिए! ऊपर दिए गए स्वीकार किए गए उत्तर को उर्सगी का उपयोग करते समय एक त्रुटि फेंकता है
पैट्रिक

2
हम्म, django के साथ मेरे लिए काम नहीं करता है। 2. अगर मैं सीधे तैयार मॉडल आयात करता हूं - सब ठीक है। अगर मैं सिग्नल में मॉडल इम्पोर्ट करता हूँ और रेडी में सिग्नल को इम्पोर्ट करता हूँ तो मुझे एक एरर मिल रहा है doesn't declare an explicit app_label..
Aldarund

@Aldarun आप INSTALLED.APPS के अंदर 'my_app.apps.MyAppConfig' डालने की कोशिश कर सकते हैं।
रामिल अग्लीओतदीनोव

26

अपनी समस्या को हल करने के लिए आपको अपने मॉडल की परिभाषा के बाद सिर्फ सिग्नल थिंकपैड को आयात करना होगा। बस इतना ही।


2
यह अब तक सबसे आसान है, और मुझे नहीं पता था कि यह चक्रीय निर्भरता के बिना काम करेगा। धन्यवाद!
ब्रैडेनम

2
प्रतिभाशाली। यह मेरे जवाब से बेहतर है। हालांकि मुझे वास्तव में समझ नहीं आया कि यह कैसे एक परिपत्र आयात का कारण नहीं बनता है ...
20

समाधान सक्षम ऑटोपेप 8 प्लगइन के साथ काम नहीं करता है।
रामसुस

5

मैंने सिग्नलों को भी Oracle.py फ़ाइल में रखा है और यह कोड स्निपेट भी है जो सभी संकेतों को लोड करता है:

# import this in url.py file !

import logging

from importlib import import_module

from django.conf import settings

logger = logging.getLogger(__name__)

signal_modules = {}

for app in settings.INSTALLED_APPS:
    signals_module = '%s.signals' % app
    try:
        logger.debug('loading "%s" ..' % signals_module)
        signal_modules[app] = import_module(signals_module)
    except ImportError as e:
        logger.warning(
            'failed to import "%s", reason: %s' % (signals_module, str(e)))

यह परियोजना के लिए है, मुझे यकीन नहीं है कि यह ऐप स्तर पर काम करता है।


यह मेरा अब तक का सबसे पसंदीदा समाधान है क्योंकि यह अन्य पैटर्न (जैसे टास्क-थ्रीडी)
dalore

1
इस के साथ एक समस्या मिली, अगर आप शेल शुरू करते हैं तो urls.py आयात नहीं होता है और आपके सिग्नल संलग्न नहीं होंगे
d23

हां, मेरा जवाब एक तरह से पुराना है, ऐसा लगता है कि django में इन दिनों AppConfig क्लास है। पिछली बार मैंने django का उपयोग किया था यह संस्करण 1.3 था। इसके आसपास जांच करने का सुझाव दिया।
अइसबा

1
हम अभी भी 1.6 हैं और इसलिए मुझे अपने सभी सिग्नलहोम को मॉडल में स्थानांतरित करना था अन्यथा अजवाइन और प्रबंधन कमांड को उठाया नहीं गया था
dalore

5

पुराने Django के संस्करणों में __init__.pyया शायद models.py(हालांकि अंत मॉडल बड़े पैमाने पर अपने स्वाद के लिए होगा) पर संकेतों को लगाने के लिए ठीक होगा ।

Django 1.9 के साथ, यह बेहतर है कि मुझे लगता है, एक signals.pyफ़ाइल पर संकेतों को रखने और उन्हें आयात करने के लिए apps.py, जहां वे मॉडल लोड करने के बाद लोड होने जा रहे हैं।

apps.py:

from django.apps import AppConfig


class PollsConfig(AppConfig):
    name = 'polls'

    def ready(self):
        from . import signals  # NOQA

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


3

मैं अनुमान लगा रहा हूं कि आप ऐसा कर रहे हैं ताकि आपके सिग्नल पंजीकृत हों, ताकि वे कहीं न कहीं मिल जाएं। मैं सामान्य रूप से एक मॉडल-थ्रू फ़ाइल में अपना सिग्नल ठीक से डाल देता हूँ।


हाँ, जब मैं मॉडल फ़ाइल के अंदर सिग्नल को स्थानांतरित करता हूं तो यह समस्या हल करता है। लेकिन सभी वर्गों, प्रबंधकों और मॉडल नियमों के साथ मेरी मॉडल-थ्रेड फ़ाइल बहुत बड़ी है।
मो। जे। मुग्राबी

1
मेरे अनुभव को खींचने के लिए प्रबंधक थोड़े सहज हैं। प्रबंधक
इस्साक केली

3

यह केवल तभी लागू होता है जब आपके पास एक अलग signals.pyफ़ाइल में आपके सिग्नल होते हैं

@EricMarcos के उत्तर से पूरी तरह सहमत हैं लेकिन यह कहा जाना चाहिए कि django डॉक्स डिफ़ॉल्ट रूप से default_app_config वैरिएबल का उपयोग नहीं करने की सलाह देता है (हालांकि यह गलत नहीं है)। वर्तमान संस्करणों के लिए, सही तरीका होगा:

my_app / apps.py

from django.apps import AppConfig

class MyAppConfig(AppConfig):
    name = 'my_app'

    def ready(self):
        import my_app.signals

settings.py

(सुनिश्चित करें कि आपके पास इंस्टॉल किए गए ऐप्स में सिर्फ आपका ऐप का नाम नहीं है, बल्कि आपके AppConfig के सापेक्ष पथ है)

INSTALLED_APPS = [
    'my_app.apps.MyAppConfig',
    # ...
]

1

कॉलबैक फ़ंक्शंस आयात करने signals.pyऔर उन्हें कनेक्ट करने के लिए एक विकल्प है models.py:

signals.py

def pre_save_callback_function(sender, instance, **kwargs):
    # Do stuff here

model.py

# Your imports here
from django.db.models.signals import pre_save
from yourapp.signals import pre_save_callback_function

class YourModel:
    # Model stuff here
pre_save.connect(pre_save_callback_function, sender=YourModel)

Ps: आयात करने YourModelसे signals.pyपुनरावृत्ति पैदा होगी; senderइसके बजाय, का उपयोग करें ।

Ps2: कॉलबैक फ़ंक्शन में फिर से इंस्टेंस को सहेजना एक पुनरावृत्ति पैदा करेगा। आप .saveइसे नियंत्रित करने के लिए विधि में एक नियंत्रण तर्क बना सकते हैं ।

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