Berdasarkan dokumentasi Django yang saya baca, nampaknya signals.py
dalam folder app adalah tempat yang baik untuk memulai, tetapi masalah yang saya hadapi adalah ketika saya membuat sinyal untuk pre_save
dan saya mencoba untuk mengimpor kelas dari model itu bertentangan dengan import
dalam model saya.
# 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]
Kode ini tidak akan berjalan karena saya mengimpor Comm_Queue
di dalam signals.py
dan saya juga mengimpor sinyal di dalamnya models.py
.
Adakah yang bisa memberi nasihat tentang bagaimana saya bisa mengatasi masalah ini?
Salam
django
django-signals
Mo J. Mughrabi
sumber
sumber
Jawaban:
Jawaban asli, untuk Django <1.7:
Anda dapat mendaftarkan sinyal dengan mengimpor
signals.py
di file aplikasi__init__.py
:# __init__.py import signals
Ini akan memungkinkan untuk mengimpor
models.py
darisignals.py
tanpa kesalahan impor melingkar.Satu masalah dengan pendekatan ini adalah bahwa ini mengacaukan hasil cakupan jika Anda menggunakan coverage.py.
Diskusi terkait
Edit: Untuk Django> = 1.7:
Sejak AppConfig diperkenalkan, cara yang disarankan untuk mengimpor sinyal adalah dalam
init()
fungsinya. Lihat jawaban Eric Marcos untuk lebih jelasnya.sumber
AppRegistryNotReady("Apps aren't loaded yet.")
Jika Anda menggunakan Django <= 1.6 Saya akan merekomendasikan solusi Kamagatos: cukup impor sinyal Anda di akhir modul model Anda.
Untuk versi Django (> = 1.7) yang akan datang, cara yang disarankan adalah dengan mengimpor modul sinyal Anda dalam fungsi config ready () aplikasi Anda :
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'
sumber
doesn't declare an explicit app_label
..Untuk mengatasi masalah Anda, Anda hanya perlu mengimpor signal.py setelah definisi model Anda. Itu saja.
sumber
Saya juga menempatkan sinyal di file signal.py dan juga memiliki cuplikan kode ini yang memuat semua sinyal:
# 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)))
Ini untuk proyek, saya tidak yakin apakah ini berfungsi di tingkat aplikasi.
sumber
Dalam versi Django lama akan baik-baik saja untuk meletakkan sinyal di
__init__.py
atau mungkin dimodels.py
(walaupun pada model akhir akan menjadi cara yang besar untuk selera saya).Dengan Django 1.9, lebih baik menurut saya, untuk menempatkan sinyal pada sebuah
signals.py
berkas dan mengimpornya denganapps.py
, di mana mereka akan dimuat setelah memuat model.apps.py:
from django.apps import AppConfig class PollsConfig(AppConfig): name = 'polls' def ready(self): from . import signals # NOQA
Anda juga dapat membagi sinyal Anda di
signals.py
danhandlers.py
di folder lain dalam model Anda yang dinamaisignals
juga, tetapi bagi saya itu hanya sekedar rekayasa. Lihatlah Sinyal Penempatansumber
Saya menduga Anda melakukannya sehingga sinyal Anda terdaftar, sehingga mereka ditemukan di suatu tempat. Saya hanya meletakkan sinyal saya di file models.py seperti biasa.
sumber
Ini hanya berlaku jika Anda memiliki sinyal di tempat terpisah
signals.py
fileSepenuhnya setuju dengan jawaban @EricMarcos tetapi harus dinyatakan bahwa dokumen django secara eksplisit menyarankan untuk tidak menggunakan variabel default_app_config (meskipun tidak salah). Untuk versi saat ini, cara yang benar adalah:
my_app / apps.py
from django.apps import AppConfig class MyAppConfig(AppConfig): name = 'my_app' def ready(self): import my_app.signals
settings.py
(Pastikan Anda tidak hanya memiliki nama aplikasi Anda di aplikasi yang diinstal tetapi juga jalur relatif ke AppConfig Anda)
INSTALLED_APPS = [ 'my_app.apps.MyAppConfig', # ... ]
sumber
Alternatifnya adalah mengimpor fungsi panggilan balik dari
signals.py
dan menghubungkannyamodels.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: Mengimpor
YourModel
disignals.py
akan membuat rekursi; menggunakansender
, sebagai gantinya.Ps2: Menyimpan instance lagi dalam fungsi callback akan membuat rekursi. Anda dapat membuat argumen kontrol dalam
.save
metode untuk mengontrolnya.sumber