Signal.py dosyamı bir Django projesinde saklamak için doğru yer


88

Django'nun okuduğum belgelerine dayanarak signals.py, uygulama klasöründe başlamak için iyi bir yer gibi görünüyor , ancak karşılaştığım sorun şu ki, için sinyaller oluşturduğumda pre_saveve sınıfı modelden içe aktarmaya çalıştığımda, importbenim modelimde.

# 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]

Bu kod çalışmayacak çünkü Comm_Queueiçeriye aktarıyorum signals.pyve içerideki sinyalleri de içeri aktarıyorum models.py.

Bu sorunun üstesinden nasıl gelebileceğime dair herhangi biri tavsiyede bulunabilir mi?

Saygılarımızla


Yanıtlar:


65

Orijinal cevap, Django <1.7 için:

Sinyalleri signals.py, uygulamanın __init__.pydosyasına aktararak kaydedebilirsiniz:

# __init__.py
import signals

Bu almak sağlayacak models.pyden signals.pydairesel ithalat hatasız.

Bu yaklaşımla ilgili bir sorun, kapsama alanı.py kullanıyorsanız kapsam sonuçlarını bozmasıdır.

İlgili tartışma

Düzenleme: Django> = 1.7 için:

AppConfig tanıtıldığından beri, sinyalleri içe aktarmanın önerilen yolu init()işlevindedir. Daha fazla ayrıntı için Eric Marcos'un cevabına bakın.


6
Django 1.9'daki sinyalleri kullanarak aşağıdaki yöntemi kullanın (django tarafından önerilen). bu yöntem vererek işe yaramıyorAppRegistryNotReady("Apps aren't loaded yet.")
s0nskar

1
Eric Marcos'un cevabı kabul edilen cevap olmalı: Django> = 1.7'den beri stackoverflow.com/a/21612050/3202958 , uygulama yapılandırmasını kullanarak
Nrzonline

1
Kabul. Yanıtı Eric
Marco'nun

197

Django <= 1.6 kullanıyorsanız Kamagatos çözümünü öneririm: sinyallerinizi modeller modülünüzün sonuna aktarmanız yeterlidir.

Django'nun (> = 1.7) gelecekteki sürümleri için önerilen yol, sinyaller modülünüzü uygulamanızın config ready () işlevine içe aktarmaktır :

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
Ayrıca 1.7 belgelerinde, bazen hazır olmanın birden çok kez çağrılabileceğini ve bu nedenle yinelenen sinyalleri önlemek için sinyal bağlayıcı çağrınıza benzersiz bir tanımlayıcı ekleyin: request_finished.connect (my_callback, dispatch_uid = "my_unique_identifier") dispatch_uid genellikle bir dizedir ancak herhangi bir hashable nesne olabilir. docs.djangoproject.com/en/1.7/topics/signals/…
Emeka

13
Kabul edilen cevap bu olmalı! Yukarıdaki kabul edilen yanıt, uwsgi'yi kullanarak konuşlandırılırken bir hata veriyor
Patrick

2
Hm, django 2 ile benim için çalışmıyor. Modeli doğrudan hazır olarak içe aktarırsam - her şey yolunda. Modeli sinyallerde içe aktarırsam ve sinyalleri hazır olarak içe aktarırsam bir hata alıyorum doesn't declare an explicit app_label..
Aldarund

@Aldarun INSTALLED_APPS içine 'my_app.apps.MyAppConfig' koymayı deneyebilirsiniz.
Ramil Aglyautdinov

26

Sorununuzu çözmek için, model tanımınızdan sonra signal.py'yi içe aktarmanız yeterlidir. Bu kadar.


2
Bu açık arayla en kolay olanı ve döngüsel bir bağımlılık olmadan bunun işe yarayacağı hakkında hiçbir fikrim yoktu. Teşekkürler!
bradenm

2
Parlak. Bunun gibi cevabımdan daha iyi. Nasıl olduğunu gerçekten anlamasam da döngüsel bir içe
aktarmaya

çözümü Eclipse'de etkinleştirilmiş autopep8 eklentisiyle çalışmıyor.
ramusus

5

Ayrıca sinyalleri sinyaller.py dosyasına koyuyorum ve ayrıca tüm sinyalleri yükleyen şu kod parçacığına sahibim:

# 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)))

Bu proje için, uygulama düzeyinde çalışıp çalışmadığından emin değilim.


Bu, diğer modellere uyduğu sürece en sevdiğim çözümdür (görevler.py gibi)
dalore

1
Bununla ilgili bir sorun bulundu,
urls.py'yi başlatırsanız

evet, cevabım biraz modası geçmiş, görünen o ki bugünlerde django'nun AppConfig sınıfı var. Django'yu en son kullandığımda 1.3 versiyonuydu. Etrafını araştırmayı öneriyorum.
aisbaa

1
Hala 1.6'yız ve bu yüzden tüm sinyallerimizi modellere taşımak zorunda kaldım, aksi takdirde kereviz ve yönetim komutları alınmadı
dalore

5

Eski Django sürümlerinde, sinyalleri üzerine __init__.pyveya belki içine yerleştirmek iyi olurdu models.py(ancak sonunda modeller zevkime göre çok büyük olacak).

Django 1.9 ile, bence sinyalleri bir signals.pydosyaya apps.pyyerleştirmek ve modeli yükledikten sonra yüklenecekleri yere aktarmak daha iyidir .

apps.py:

from django.apps import AppConfig


class PollsConfig(AppConfig):
    name = 'polls'

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

Ayrıca sinyallerinizi modelinizin içinde başka bir klasöre signals.pyve handlers.pybaşka bir klasöre bölebilirsiniz signals, ancak benim için bu sadece mühendislikten ibaret. Sinyal Yerleştirme'ye bir göz atın


3

Bunu yaptığınızı tahmin ediyorum, böylece sinyalleriniz kaydedilir, böylece bir yerde bulunabilirler. Sinyallerimi normal olarak bir models.py dosyasına koyuyorum.


evet, sinyali model dosyasının içine taşıdığımda sorunu çözüyor. Ancak model.py dosyam tüm sınıflar, yöneticiler ve model kurallarıyla oldukça büyük.
Mo J. Mughrabi

1
Yöneticiler benim deneyimlerime göre biraz daha kolay. Managers.py ftw.
Issac Kelly

3

Eğer ayrı da sinyalleri varsa bu geçerlidir signals.pydosyası

@EricMarcos'un cevabına tamamen katılıyorum, ancak django belgelerinin açıkça default_app_config değişkenini kullanmamayı tavsiye ettiği belirtilmelidir (yanlış olmasa da). Mevcut sürümler için doğru yol şu şekilde olacaktır:

my_app / apps.py

from django.apps import AppConfig

class MyAppConfig(AppConfig):
    name = 'my_app'

    def ready(self):
        import my_app.signals

settings.py

(Yüklü uygulamalarda yalnızca uygulamanızın adının değil, bunun yerine AppConfig'inizin göreli yolunun bulunduğundan emin olun)

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

1

Bir alternatif, geri arama işlevlerini içinden içe aktarmak signals.pyve bunları şuraya bağlamaktır models.py:

signal.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: İçe YourModeliçinde signals.pybir yineleme oluşturmak olacaktır; kullanmak senderyerine,.

Ps2: Örneği geri çağrı işlevinde tekrar kaydetmek bir özyineleme oluşturacaktır. .saveYöntemde onu kontrol etmek için bir kontrol argümanı oluşturabilirsiniz .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.