Skip to content

Django Sinyalleri Nasıl Oluşturulur \( Django Signals \)

Django Sinyalleri Nasıl Oluşturulur \( Django Signals \)

Nedir

Sinyaller’ler kısacası bir model ve istekler \( request, response \) ile yapılan bir işlem sırasında bunu yakalamanız ve ona göre işlem yapmanızı sağlar, örneğin yeni bir user modeliniz var ve yeni bir kullanıcı kaydı olduğunda sizin user modelinizede kayıt olsun istiyorsunuz bunu sinyalleri kullanarak yapabilirsiniz.

Bütün signal olaylarının olmasını sağlayan django’nun kaynak kodlarındaki ilgili bölümler;

Django Sinyali Oluşturma

django/dispatch/dispatcher.py

Aşağıdaka Django sinyal kullanımını görüyoruz, bu kodları yukarıda verdiğim kaynak adreslerinden aldım.

"""
A decorator for connecting receivers to signals. Used by passing in the
signal (or list of signals) and keyword arguments to connect::
"""
@receiver(post_save, sender=MyModel)
def signal_receiver(sender, **kwargs):
    pass
@receiver([post_save, post_delete], sender=MyModel)
def signals_receiver(sender, **kwargs):
    pass

burdaki receiver dekorator’u nü aşağıda inceleyelim.

def receiver(signal, **kwargs):
    def _decorator(func):
        if isinstance(signal, (list, tuple)):
            for s in signal:
                s.connect(func, **kwargs)
        else:
            signal.connect(func, **kwargs)
        return func
    return

Yukarıdaki kodlarda gördüğümüz gibi eğer verdiğimiz signal parametresi yanı @receiver(post_save, sender=MyModel) bu kısımdaki post_save bir signal’dir ve ilk parametre bir liste değilse direk bunun alında bulunan connect fonksiyonuna fonksiyonumuzu ve aldığı parametreleri vererek çalıştırıyor \( yukarıdaki kodlardan signal.connect(func, **kwargs) bu kısım \) eğer liste girilirse @receiver([post_save, post_delete], sender=MyModel) bunun gibi her bir signal’in altındaki connect fonksiyonunu çalıştırıp ( yukarıdaki kodlardan

for s in signal:
    s.connect(func, **kwargs)

bu kısım ) fonksiyonu ve verilen parametreleri \( (func, **kwargs) bu kısım \) veriyor en sonundada fonksiyonumuzu return ediyor, işte bu şekilde sinyaller yakalanmış ve çalıştırılmış oluyor.

Bu alt başlıkta django’da bulunan built-in signal leri kullanarak modeller için yeni sinyaller kodlayacağız.

Built-in sinyallerinin kodları django/db/models/signals.py; built-in gömülü olarak çevrilebilir sanırım, django ile birlikte gelen sinyallerdir denilebilir.

kaynak kodlarındada gördüğümüz üzere model sinyallerinin isimler ve aldıkları parametreler;

  • django.db.models.signals.pre_init: (sender, *args, **kwargs)
  • django.db.models.signals.post_init: (sender, instance)
  • django.db.models.signals.pre_save: (sender, instance, raw, using, update_fields)
  • django.db.models.signals.post_save: (sender, instance, created, raw, using, update_fields) Modellerin save methodu çalıştıktan hemen sonra çalışan bir sinyaldir.
  • django.db.models.signals.pre_delete: (sender, instance, using)
  • django.db.models.signals.post_delete: (sender, instance, using)
  • django.db.models.signals.m2m_changed: (sender, instance, action, reverse, model, pk_set, using)
  • django.db.models.signals.pre_migrate: (sender, app_config, verbosity, interactive, using, apps, plan)
  • django.db.models.signals.post_migrate: (sender, app_config, verbosity, interactive, using, apps, plan)
from django.contrib.auth.models import User
from django.db.models.signals import post_save

def save_profile(sender, instance, **kwargs):
    instance.profile.save()

post_save.connect(save_profile, sender=User)

Yukarıdaki kodlarda bir sinyalin oluşturulma kodlarını görüyorsunuz, django sinyali oluşturmak için bir diğer yöntem de @receiver decorator’ünü kullanmaktır çünkü yukarıda vermiş olduğum @receiver decorator’ün kodlarına baktığınızda signal.connect(func, **kwargs) bu şekilde işlem yaptığını görürsünüz, gördüğünüz gibi ilk yöntem ile aynı, yani bunun ile post_save.connect(save_profile, sender=User) yukarıda anlattığım receive decorator’ü de bu şekilde yapıyordu.

from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=User)
def save_profile(sender, instance, **kwargs):
    instance.profile.save()

Projede Kullanımı

Projelerde signaller kullanılacak ise eğer bunun için en güzel yöntem uygulama klasörünüzün hemen altında signals adında bir klasör oluşturmak daha sonra signal fonksiyonlarınızı burada açacağınız python dosyalarını içine yazmak ve aşağıdaki adımları uygulamaktır. Uygulama tamamen yüklendikten sonra kodladığımız signalleri çağırırsak yüklenmiş olur, bunuda apps.py‘yi kullanarak yapabiliriz.

Aşağıdaki adımları yaptıktan sonra işlemlerimiz tamamlanmış olacaktır.

/myapp/init.py

default_app_config = "myapp.apps.MyAppNameConfig"

/myapp/signals/init.py

bu dosyanızda signals klasörü altında kaçtane python dosyası oluşturduysanız ve kaç tane signals fonksiyonları oluşturduysanız onları import etmelisiniz ki apps.py de çağırdığımızda onlar yüklensin.

mysignal adında bir python dosyam ve içinde signals fonksiyonlarım olsun hepsini aşağıdaki gibi import ederim

from .mysignal import *

/myapp/apps.py

#django
from django.apps import AppConfig

class MyAppNameConfig(AppConfig):
    name = 'MyAppNameConfig'

    def ready(self): # MyAppName isimli uygulamam hazır olduğunda
        from myapp.signals import *
        #bu satır bütün yazdıgım signalleri import edecek

Request/Response Sinyalleri \( Signals \)

django/core/signals.py

  • django.core.signals.request_started:

(sender, environ)

  • django.core.signals.request_finished:

(sender, environ)

  • django.core.signals.got_request_exception:

(sender, environ)

Yeni Django Sinyali Nasıl Oluşturulur.

Nedir?

Yukarıda Request/Response Sinalleri \( Signals \) ve Models sinyalleri dışında kendi sinyallerimizi oluşturma olayıdır.

Nasıl Yapılır?

En yukarıda verdiğim kaynak kodları linkleri bunu anlamamız için yeterli, ancak ben size başka bir projeden örnek vererek anlatacağım.

django-contrib-comments projesi kendi amaçları doğrultusunda yeni sinyal üretmiş ve bunu kullanıma sunmuş bir bakalım.

Sinyal dosyası /django_comments/signals.py burda gördüğümüz gibi önce from django.dispatch import Signal diyerek Signal sınıfını import etmiş ve 3 tane yeni signal tanımlamış bunlar, comment_will_be_posted, comment_was_posted ve comment_was_flagged bu sinyallerin alacağı parametreler kodlarda görünüyor comment_was_posted = Signal(providing_args=["comment", "request"]) bu sinyalimiz comment ve request parametresini alıyormuş, birde varsayılan olarak sender parametremiz var.

Şimdi sıra geldi işlem gerçekleştiğinde yukarıda kodladığımız sinyali kullanarak sinyal göndermekte, onuda proje view içerisine gerçekleştirmiş.

en yukarda from django_comments import signals signals modülünü import etmiş ve hemen burda /views/comments.py#L123 save() methodundan sonra \( çünkü sinyal ismi comment_was_posted \( yorum yapıldı \)) olduğu için.

signals.comment_was_posted.send(
    sender=comment.__class__,
    comment=comment,
    request=request
)

yazarak sinyal göndermiş oldu, sizde amaçlarınıza yönelik bu şekilde sinyaller oluşturabilirsiniz.


Last update: January 1, 2022
Created: January 1, 2022