IlmHamroh
Python kursi/Django15/16-dars16 daqiqa
Mundarija (22)

21.15-dars: Signal va middleware

21-QISM — DJANGO · 15-dars


1. Kirish va motivatsiya

Django'ning ikki kuchli mexanizmi bor: signal (model hodisalari — model saqlanganda avtomatik amal) va middleware (har so'rov/javobni qayta ishlovchi qatlam). Bular kodni ajratishga yordam beradi: asosiy mantiq bir joyda, yon ta'sir (log, xabar) boshqada — bir-biriga aralashmasdan.

Signal — "hodisaga obuna" (event) tamoyili: model saqlansa (post_save), o'chirilsa (pre_delete) — obuna bo'lgan funksiya avtomatik ishlaydi. Middleware — har so'rov view'ga kirishdan oldin va javob chiqishdan keyin ishlovchi qatlam (autentifikatsiya, log, CORS). Bular Django'ning kengaytiriladigan arxitekturasining asosi.

Real vaziyat. Bir jamoa kurs yaratilganda email yuborish, log yozish, statistika yangilashni har view'da takrorlardi — kurs yaratilgan har joyda shu kod. Ular signal'ga o'tdi: post_save signaliga obuna bo'lgan funksiya — kurs qayerda yaratilsa ham avtomatik ishlaydi. Yana har so'rovni log qilish uchun middleware yozdi (har view'da emas). Kod ajratildi, takror yo'qoldi. Signal/middleware — toza, kengaytiriladigan arxitektura.

Bu darsda signal va middleware'ni — hodisalar va so'rov qatlamini o'rganamiz.

Bu darsda:

  • Signal nima (hodisaga obuna)
  • Model signallari (post_save, pre_delete)
  • @receiver dekoratori
  • Signal argumentlari (created, instance)
  • Middleware nima (so'rov qatlami)
  • Middleware tuzilishi
  • So'rov va javobni qayta ishlash
  • Amaliy: signal va middleware

ℹ Misollarda Django signal va middleware bilan sinaladi.


2. Nazariya — chuqur tushuntirish

2.1. Signal nima

Signal — Django'dagi hodisa tizimi (event): biror narsa sodir bo'lsa, obuna bo'lgan funksiya ishlaydi:

Model saqlanadi → post_save signal → obuna funksiya ishlaydi
Element Ma'no
Signal Hodisa (post_save)
Sender Kim yubordi (model)
Receiver Obuna funksiya

Signal — "nashr-obuna" (publish-subscribe) naqshi: bir joy hodisani e'lon qiladi (model saqlandi), boshqa joylar unga obuna (avtomatik ishlaydi). Bu asosiy kodni yon ta'sirdan (log, email) ajratadi.

2.2. Model signallari

Django model hodisalari uchun tayyor signallar:

Signal Qachon
pre_save Saqlashdan oldin
post_save Saqlashdan keyin
pre_delete O'chirishdan oldin
post_delete O'chirishdan keyin
m2m_changed M2M o'zgarganda
python
from django.db.models.signals import post_save

# Kurs saqlanganda ishlaydi

Model signallari — model hayoti (saqlash, o'chirish) hodisalari. post_save — eng ko'p ishlatiladi (yaratilgandan keyin: email, log). pre_* — oldin (validatsiya, tayyorgarlik).

2.3. @receiver dekoratori

@receiver — funksiyani signal'ga obuna qiladi:

python
from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=Kurs)
def kurs_saqlandi(sender, instance, created, **kwargs):
    if created:
        print(f"Yangi kurs: {instance.nom}")

@receiver(signal, sender=Model) — funksiyani signal'ga bog'laydi. sender — qaysi model (usiz barcha modellar). Funksiya sender, instance (obyekt) va boshqa argumentlarni oladi. Kurs saqlanganda bu funksiya avtomatik ishlaydi.

2.4. Signal argumentlari

Signal receiver'iga argumentlar beriladi:

Argument Ma'no
sender Signal yuborgan model
instance Obyekt (saqlangan/o'chirilgan)
created Yangi yaratildi mi (post_save)
**kwargs Qolgan argumentlar
python
@receiver(post_save, sender=Kurs)
def handler(sender, instance, created, **kwargs):
    if created:                       # yangi yaratildi
        ...
    else:                             # yangilandi
        ...

created (post_saveda) — obyekt yangi (True) yoki yangilandi (False). instance — obyektning o'zi (instance.nom). **kwargs — kelajakdagi argumentlar uchun (har doim qo'shing).

2.5. Signal foydasi va xavfi

Foyda Xavf
Kodni ajratadi Yashiringan mantiq
Takrorni yo'qotadi Kuzatish qiyin
Kengaytiriladigan Ketma-ketlik noaniq

Signal — kuchli, lekin ehtiyot: mantiq "yashiringan" (model saqlansa nima bo'lishi kod'da ko'rinmaydi). Oddiy holatda to'g'ridan chaqirish (funksiya()) aniqroq. Signal — ajratilgan yon ta'sir (log, email, boshqa app) uchun.

2.6. Middleware nima

Middleware — har so'rov/javobni qayta ishlovchi qatlam:

So'rov → Middleware 1 → Middleware 2 → View → Middleware 2 → Middleware 1 → Javob

Middleware — so'rov view'ga kirishdan oldin va javob chiqishdan keyin ishlovchi kod. Har so'rov ular orqali o'tadi (autentifikatsiya, log, CORS, xavfsizlik). Bu 20.7 dagi bog'liqlikka o'xshaydi, lekin butun ilova darajasida (har so'rov).

2.7. Middleware tuzilishi

Middleware — chaqiriladigan klass (yoki funksiya):

python
class LogMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # so'rovdan OLDIN (view'gacha)
        javob = self.get_response(request)     # keyingi qatlam/view
        # javobdan KEYIN
        javob["X-Qayta-Ishlangan"] = "ha"
        return javob

Middleware — __call__(request) metodi: get_response(request)dan oldin (so'rovni qayta ishlash), keyin (javobni qayta ishlash). MIDDLEWARE ro'yxatiga qo'shiladi (tartib muhim). Bu har so'rovga qo'llanadigan umumiy mantiq.

2.8. Middleware ishlatilishi

Middleware Vazifa
Autentifikatsiya request.user o'rnatish
Sessiya Sessiya boshqaruvi
CORS Cross-origin sarlavhalar
Log Har so'rovni log
Xavfsizlik CSRF, XSS himoya

Middleware — butun ilova uchun umumiy mantiq (har so'rov). Django tayyor middleware'lar beradi (auth, sessiya, xavfsizlik). O'z middleware'ingiz (log, maxsus sarlavha) yozish mumkin. Bu 20.7 DI'ning ilova darajasidagi versiyasi.


3. Tez ma'lumotnoma

python
# SIGNAL:
from django.db.models.signals import post_save, pre_delete
from django.dispatch import receiver

@receiver(post_save, sender=Kurs)
def kurs_saqlandi(sender, instance, created, **kwargs):
    if created:
        Log.objects.create(xabar=f"Yangi: {instance.nom}")

# MIDDLEWARE:
class LogMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    def __call__(self, request):
        # oldin
        javob = self.get_response(request)
        # keyin
        return javob
# settings.py: MIDDLEWARE = [..., "app.middleware.LogMiddleware"]

Signallar

pre_save · post_save (created) · pre_delete · post_delete · m2m_changed

4. Batafsil misollar

Misollarda Django signal va middleware bilan sinaladi.

Misol 1 — post_save signal

python
"""post_save signal; @receiver; created (yangi vs yangilandi); instance; avtomatik amal."""

import warnings
warnings.filterwarnings("ignore")

import sys
import tempfile
import types

import django
from django.conf import settings

settings.configure(
    DEBUG=False,
    DATABASES={"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}},
    INSTALLED_APPS=["wisar"],
    DEFAULT_AUTO_FIELD="django.db.models.BigAutoField",
)
_app = types.ModuleType("wisar")
_app.__path__ = [tempfile.gettempdir()]
sys.modules["wisar"] = _app
django.setup()

from django.db import connection, models
from django.db.models.signals import post_save
from django.dispatch import receiver

JURNAL: list[str] = []


class Kurs(models.Model):
    nom = models.CharField(max_length=100)

    class Meta:
        app_label = "wisar"


@receiver(post_save, sender=Kurs)
def kurs_saqlandi(sender, instance, created, **kwargs):
    holat = "yaratildi" if created else "yangilandi"
    JURNAL.append(f"{holat}: {instance.nom}")


def main() -> None:
    with connection.schema_editor() as se:
        se.create_model(Kurs)

    print("=== 1. Yaratish (created=True) ===")
    kurs = Kurs.objects.create(nom="Python")
    print(f"  jurnal: {JURNAL[-1]}")

    print("\n=== 2. Yangilash (created=False) ===")
    kurs.nom = "Python 3.14"
    kurs.save()
    print(f"  jurnal: {JURNAL[-1]}")

    print("\n=== 3. Yana yaratish ===")
    Kurs.objects.create(nom="Go")
    print(f"  jurnal: {JURNAL[-1]}")

    print("\n=== 4. Signal avtomatik ishladi ===")
    print(f"  barcha hodisalar: {JURNAL}")
    print("  ⭐ post_save + @receiver — model saqlanganda avtomatik")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Yaratish (created=True) ===
  jurnal: yaratildi: Python

=== 2. Yangilash (created=False) ===
  jurnal: yangilandi: Python 3.14

=== 3. Yana yaratish ===
  jurnal: yaratildi: Go

=== 4. Signal avtomatik ishladi ===
  barcha hodisalar: ['yaratildi: Python', 'yangilandi: Python 3.14', 'yaratildi: Go']
  ⭐ post_save + @receiver — model saqlanganda avtomatik

Nima ko'rsatdi: 2.1, 2.2, 2.3, 2.4-bo'limlar.

Misol 2 — pre_delete va signal bilan boshqa model

python
"""pre_delete signal; signal ichida boshqa model yaratish (log); ajratilgan yon ta'sir; ketma-ketlik."""

import warnings
warnings.filterwarnings("ignore")

import sys
import tempfile
import types

import django
from django.conf import settings

settings.configure(
    DEBUG=False,
    DATABASES={"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}},
    INSTALLED_APPS=["wisar"],
    DEFAULT_AUTO_FIELD="django.db.models.BigAutoField",
)
_app = types.ModuleType("wisar")
_app.__path__ = [tempfile.gettempdir()]
sys.modules["wisar"] = _app
django.setup()

from django.db import connection, models
from django.db.models.signals import post_save, pre_delete
from django.dispatch import receiver


class Kurs(models.Model):
    nom = models.CharField(max_length=100)

    class Meta:
        app_label = "wisar"


class Audit(models.Model):
    xabar = models.CharField(max_length=200)

    class Meta:
        app_label = "wisar"


@receiver(post_save, sender=Kurs)
def kurs_yaratildi(sender, instance, created, **kwargs):
    if created:
        Audit.objects.create(xabar=f"Kurs yaratildi: {instance.nom}")


@receiver(pre_delete, sender=Kurs)
def kurs_ochirilmoqda(sender, instance, **kwargs):
    Audit.objects.create(xabar=f"Kurs o'chirildi: {instance.nom}")


def main() -> None:
    for m in (Kurs, Audit):
        with connection.schema_editor() as se:
            se.create_model(m)

    print("=== 1. Yaratish → audit yozuvi ===")
    kurs = Kurs.objects.create(nom="Python")
    print(f"  audit yozuvlari: {Audit.objects.count()}")
    print(f"  oxirgi: {Audit.objects.last().xabar}")

    print("\n=== 2. Yana yaratish ===")
    Kurs.objects.create(nom="Go")
    print(f"  audit: {Audit.objects.count()}")

    print("\n=== 3. O'chirish → audit yozuvi ===")
    kurs.delete()
    print(f"  oxirgi audit: {Audit.objects.last().xabar}")

    print("\n=== 4. Ajratilgan yon ta'sir ===")
    print(f"  barcha audit: {list(Audit.objects.values_list('xabar', flat=True))}")
    print("  ⭐ signal — asosiy kodni yon ta'sirdan ajratadi (audit)")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Yaratish → audit yozuvi ===
  audit yozuvlari: 1
  oxirgi: Kurs yaratildi: Python

=== 2. Yana yaratish ===
  audit: 2

=== 3. O'chirish → audit yozuvi ===
  oxirgi audit: Kurs o'chirildi: Python

=== 4. Ajratilgan yon ta'sir ===
  barcha audit: ['Kurs yaratildi: Python', 'Kurs yaratildi: Go', "Kurs o'chirildi: Python"]
  ⭐ signal — asosiy kodni yon ta'sirdan ajratadi (audit)

Nima ko'rsatdi: 2.2, 2.5-bo'limlar.

Misol 3 — Middleware

python
"""middleware (so'rov qatlami); __call__ (oldin/keyin); request/javobni qayta ishlash; har so'rov."""

import warnings
warnings.filterwarnings("ignore")

import sys
import tempfile
import types

import django
from django.conf import settings


class SorovLogMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # so'rovdan OLDIN
        request.META["X_BOSHLANDI"] = "ha"
        javob = self.get_response(request)
        # javobdan KEYIN
        javob["X-Qayta-Ishlangan"] = "middleware"
        return javob


settings.configure(
    DEBUG=False,
    DATABASES={"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}},
    INSTALLED_APPS=["wisar"],
    ROOT_URLCONF=__name__,
    ALLOWED_HOSTS=["*"],
    SECRET_KEY="namuna",
    MIDDLEWARE=[__name__ + ".SorovLogMiddleware"],
    DEFAULT_AUTO_FIELD="django.db.models.BigAutoField",
)
_app = types.ModuleType("wisar")
_app.__path__ = [tempfile.gettempdir()]
sys.modules["wisar"] = _app
django.setup()

from django.http import JsonResponse
from django.urls import path


def view(request):
    return JsonResponse({"boshlandi": request.META.get("X_BOSHLANDI")})


urlpatterns = [path("test/", view)]


def main() -> None:
    from django.test import Client
    client = Client()

    print("=== 1. Middleware so'rovni qayta ishladi (oldin) ===")
    javob = client.get("/test/")
    print(f"  view'da X_BOSHLANDI: {javob.json()['boshlandi']}")

    print("\n=== 2. Middleware javobni qayta ishladi (keyin) ===")
    print(f"  javob sarlavhasi X-Qayta-Ishlangan: {javob['X-Qayta-Ishlangan']}")

    print("\n=== 3. Har so'rov middleware orqali ===")
    javob2 = client.get("/test/")
    print(f"  ikkinchi so'rov ham: {javob2.json()['boshlandi']}")

    print("\n=== 4. So'rov → oldin → view → keyin → javob ===")
    print("  middleware har so'rov/javobni o'raydi")
    print("  ⭐ middleware — har so'rov/javob qatlami (oldin va keyin)")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Middleware so'rovni qayta ishladi (oldin) ===
  view'da X_BOSHLANDI: ha

=== 2. Middleware javobni qayta ishladi (keyin) ===
  javob sarlavhasi X-Qayta-Ishlangan: middleware

=== 3. Har so'rov middleware orqali ===
  ikkinchi so'rov ham: ha

=== 4. So'rov → oldin → view → keyin → javob ===
  middleware har so'rov/javobni o'raydi
  ⭐ middleware — har so'rov/javob qatlami (oldin va keyin)

Nima ko'rsatdi: 2.6, 2.7-bo'limlar.

Misol 4 — Amaliy: signal va middleware birga

Signal (model hodisalari) va middleware (so'rov qatlami) ni birga ishlatami: kurs yaratilganda audit (signal), va har so'rovni log (middleware). Bu — Django kengaytiriladigan arxitekturasining namunasi.

python
"""signal + middleware birga: kurs audit (signal), so'rov log (middleware); ajratilgan yon ta'sirlar."""

import warnings
warnings.filterwarnings("ignore")

import sys
import tempfile
import types

import django
from django.conf import settings

SO_ROVLAR: list[str] = []


class SorovSanaMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        SO_ROVLAR.append(request.path)
        javob = self.get_response(request)
        javob["X-So-rov-Soni"] = str(len(SO_ROVLAR))
        return javob


settings.configure(
    DEBUG=False,
    DATABASES={"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}},
    INSTALLED_APPS=["wisar"],
    ROOT_URLCONF=__name__,
    ALLOWED_HOSTS=["*"],
    SECRET_KEY="namuna",
    MIDDLEWARE=[__name__ + ".SorovSanaMiddleware"],
    DEFAULT_AUTO_FIELD="django.db.models.BigAutoField",
)
_app = types.ModuleType("wisar")
_app.__path__ = [tempfile.gettempdir()]
sys.modules["wisar"] = _app
django.setup()

from django.db import connection, models
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.http import JsonResponse
from django.urls import path

AUDIT: list[str] = []


class Kurs(models.Model):
    nom = models.CharField(max_length=100)

    class Meta:
        app_label = "wisar"


@receiver(post_save, sender=Kurs)
def kurs_audit(sender, instance, created, **kwargs):
    if created:
        AUDIT.append(f"kurs yaratildi: {instance.nom}")


def yarat_view(request):
    kurs = Kurs.objects.create(nom=request.GET.get("nom", "Nomsiz"))
    return JsonResponse({"yaratildi": kurs.nom})


urlpatterns = [path("yarat/", yarat_view)]


def main() -> None:
    with connection.schema_editor() as se:
        se.create_model(Kurs)

    from django.test import Client
    client = Client()

    print("=== 1. So'rov (middleware + view + signal) ===")
    javob = client.get("/yarat/?nom=Python")
    print(f"  javob: {javob.json()}")

    print("\n=== 2. Signal audit yozdi ===")
    print(f"  audit: {AUDIT}")

    print("\n=== 3. Middleware so'rovni logladi ===")
    print(f"  so'rovlar: {SO_ROVLAR}")
    print(f"  javob sarlavha X-So-rov-Soni: {javob['X-So-rov-Soni']}")

    print("\n=== 4. Ikkinchi so'rov ===")
    client.get("/yarat/?nom=Go")
    print(f"  audit: {AUDIT}")
    print(f"  so'rovlar soni: {len(SO_ROVLAR)}")
    print("  ⭐ signal (model hodisasi) + middleware (so'rov qatlami) birga")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. So'rov (middleware + view + signal) ===
  javob: {'yaratildi': 'Python'}

=== 2. Signal audit yozdi ===
  audit: ['kurs yaratildi: Python']

=== 3. Middleware so'rovni logladi ===
  so'rovlar: ['/yarat/']
  javob sarlavha X-So-rov-Soni: 1

=== 4. Ikkinchi so'rov ===
  audit: ['kurs yaratildi: Python', 'kurs yaratildi: Go']
  so'rovlar soni: 2
  ⭐ signal (model hodisasi) + middleware (so'rov qatlami) birga

Nima ko'rsatdi: 2.1–2.8-bo'limlar.


5. To'g'ri va noto'g'ri tushunishlar

Noto'g'ri fikr To'g'risi
"Yon ta'sirni har view'da" Signal (avtomatik)
"Signal — oddiy chaqiriq" Hodisaga obuna (event)
"post_saveda created yo'q" Bor (yangi/yangilandi)
"Signal doim yaxshi" Ehtiyot (yashiringan mantiq)
"Middleware — bir view" Har so'rov (butun ilova)
"Middleware faqat so'rovni" So'rov va javob
"**kwargs keraksiz" Har doim qo'shing
"Middleware tartibi muhim emas" Muhim (ketma-ketlik)

6. Keng tarqalgan xatolar va yechimlari

1. Yon ta'sirni har view'da takrorlash

python
# har view'da email/log/audit                 # ⚠️ takror
@receiver(post_save, sender=Kurs)             # ✅ signal

2. **kwargsni unutish

python
def handler(sender, instance, created):        # ⚠️ kelajakda buziladi
def handler(sender, instance, created, **kwargs):   # ✅

3. Signal'da og'ir ish

python
@receiver(post_save, ...)
def handler(...): sekin_hisob()                # ⚠️ saqlashni sekinlashtiradi
# ✅ og'ir ish — fon vazifasi (20.14)

4. Middleware'da get_response chaqirmaslik

python
def __call__(self, request):
    # javob qaytarmadi                          # ❌ zanjir uzildi
    return self.get_response(request)          # ✅

5. Signal'ni oddiy chaqiriq o'rniga

python
# oddiy holatda signal                          # ⚠️ yashiringan mantiq
funksiya(instance)                              # ✅ to'g'ridan (aniqroq)

6. senderni bermaslik

python
@receiver(post_save)                            # ⚠️ barcha model uchun
@receiver(post_save, sender=Kurs)               # ✅ faqat Kurs

7. Middleware'ni MIDDLEWAREga qo'shmaslik

python
# middleware yozildi, lekin faol emas           # ⚠️
MIDDLEWARE = [..., "app.middleware.LogMiddleware"]   # ✅

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 21.3-dars (o'tilgan): model — signal manbai
  • 20.7-dars (o'tilgan): DI — middleware o'xshashi
  • 20.14-dars (o'tilgan): fon vazifalari — signal'da og'ir ish
  • 12-qism (o'tilgan): hodisa/observer naqshi
  • 21.16-dars: deploy — middleware sozlamalari

8. Eng yaxshi amaliyotlar

  1. Ajratilgan yon ta'sir (audit, email) uchun signal.

  2. @receiver(signal, sender=Model) bilan aniq model.

  3. **kwargsni har doim qo'shing.

  4. Signal'da og'ir ish qilmang (fon vazifasi).

  5. Oddiy holatda to'g'ridan chaqiriq (signal emas).

  6. Middleware'da get_responseni chaqiring.

  7. Middleware'ni MIDDLEWAREga qo'shing (tartib muhim).

  8. Har so'rovga umumiy mantiq uchun middleware.


9. Amaliy topshiriq

Vazifa 1: Bashorat qiling

python
1.  # signal nima?
2.  # post_save qachon?
3.  # @receiver nima?
4.  # created nima?
5.  # instance nima?
6.  # sender nima?
7.  # middleware nima?
8.  # middleware qachon ishlaydi?
9.  # get_response nima?
10. # signal xavfi nima?
11. # **kwargs nega?
12. # signal yoki chaqiriq?
Javoblar
  1. Hodisaga obuna (event) tizimi
  2. Model saqlangandan keyin
  3. Funksiyani signal'ga obuna qiladi
  4. Obyekt yangi (True) yoki yangilandi (False)
  5. Obyektning o'zi (saqlangan/o'chirilgan)
  6. Signal yuborgan model
  7. Har so'rov/javobni qayta ishlovchi qatlam
  8. So'rov (oldin) va javob (keyin)
  9. Keyingi qatlam/view'ni chaqiradi
  10. Yashiringan mantiq (kuzatish qiyin)
  11. Kelajakdagi argumentlar uchun
  12. Ajratilgan yon ta'sir → signal; oddiy → chaqiriq

Vazifa 2: Xatolarni tuzating

python
1.  # har view'da audit                      # signal

2.  def handler(sender, instance, created):  # kwargs

3.  def __call__(self, request):
        # javob qaytarmadi                     # get_response

4.  @receiver(post_save)                      # sender

5.  # middleware faol emas                    # MIDDLEWARE
Javoblar
python
1.  @receiver(post_save, sender=Kurs)

2.  def handler(sender, instance, created, **kwargs):

3.  def __call__(self, request):
        return self.get_response(request)

4.  @receiver(post_save, sender=Kurs)

5.  MIDDLEWARE = [..., "app.middleware.LogMiddleware"]

Vazifa 3: Audit signal

Audit tizimi:

  1. post_save, pre_delete signallari
  2. Har o'zgarishni audit modeliga
  3. created bilan yaratish/yangilash
  4. Standalone test

Vazifa 4: Profil signal

Foydalanuvchi profili:

  1. User post_save (yangi bo'lsa profil yaratish)
  2. created tekshiruvi
  3. Avtomatik profil
  4. Test

Vazifa 5: Log middleware

So'rov log middleware:

  1. Har so'rovni log (URL, metod, vaqt)
  2. Javob sarlavhasi (so'rov ID)
  3. Client bilan test
  4. Bir necha so'rov

Vazifa 6: Signal va middleware birga

To'liq tizim:

  1. Model signal (audit)
  2. Middleware (so'rov log)
  3. View (model o'zgartiradi)
  4. Ikkalasi ishlashini test

Vazifa 7: O'ylash

Signal va middleware yon ta'sirni (log, audit, email) asosiy kod'dan ajratadi: view o'z ishini qiladi (kurs yaratadi), signal/middleware yon ta'sirni (audit, log) alohida qiladi. Bu "vazifalarni ajratish" (separation of concerns) tamoyili — har qism bir vazifaga mas'ul. Asosiy mantiqni yon ta'sirdan ajratishning afzalligi nima, va nima uchun signal'ning "yashiringan" tabiati (kod'da ko'rinmaydi) ehtiyotni talab qiladi?

Javob

Qisqa javob: Signal/middleware yon ta'sirni (audit, log, email) asosiy kod'dan ajratadi: view faqat o'z ishini qiladi (kurs yaratadi), yon ta'sir alohida (signal). Afzalligi: toza kod (view yengil, bir vazifa), takrorsiz (yon ta'sir bir joyda, har view'da emas), kengaytiriladigan (yangi yon ta'sir qo'shish — yangi signal, view'ni o'zgartirmasdan). Lekin signal "yashiringan" — kod'ni o'qib, model saqlansa nima bo'lishi ko'rinmaydi (signal boshqa joyda). Bu kuzatishni qiyinlashtiradi (nima uchun audit yozildi? — signal'ni topish kerak). Shuning uchun signal — ajratilgan, mustaqil yon ta'sir uchun (audit, email), oddiy holatda to'g'ridan chaqiriq aniqroq.

1. Vazifalarni ajratish

Asosiy (view) Yon ta'sir (signal/middleware)
Kurs yaratadi Audit yozadi
So'rovga javob Log qiladi
Bir vazifa Alohida

2. Ajratishning afzalligi

Afzallik Sabab
Toza kod View yengil
Takrorsiz Yon ta'sir bir joyda
Kengaytiriladigan Yangi signal qo'shish
Test Alohida sinaladi

3. Signal "yashiringan" tabiati

Signal kod'da ko'rinmaydi: Kurs.objects.create(...) — audit yozilishi shu qatorda ko'rinmaydi (signal boshqa joyda). Bu:

  • Kuzatish qiyin (nima bo'ldi?)
  • Ketma-ketlik noaniq
  • Debug qiyin

4. Qachon signal, qachon chaqiriq

Signal To'g'ridan chaqiriq
Ajratilgan yon ta'sir Asosiy mantiq
Boshqa app Shu funksiya
Audit, email Aniq ketma-ketlik

5. Muhandislik saboqlari

  1. Yon ta'sirni asosiy kod'dan ajrat (signal)
  2. Ajratish — toza, takrorsiz, kengaytiriladigan
  3. Signal yashiringan — ehtiyot (kuzatish qiyin)
  4. Oddiy holatda to'g'ridan chaqiriq (aniqroq)

6. Xulosa

  1. Signal/middleware — yon ta'sirni ajratadi
  2. Ajratish — toza kod, vazifalar bo'lingan
  3. Signal yashiringan — kuzatish qiyin (ehtiyot)
  4. Ajratilgan yon ta'sir → signal; oddiy → chaqiriq

Nimani mustahkamlaydi: 2.1–2.8-bo'limlar.


Xulosa

Bu darsda Django signal va middleware'ni o'rgandik.

Eng muhim uch fikr:

  1. Signal — hodisaga obuna. Signal — Django'dagi hodisa (event) tizimi: biror narsa sodir bo'lsa, obuna funksiya avtomatik ishlaydi ("nashr-obuna" naqshi). Model signallari: post_save (saqlashdan keyin — eng ko'p, email/log/audit uchun), pre_save, pre_delete, post_delete, m2m_changed. @receiver(signal, sender=Model) — funksiyani signal'ga obuna qiladi. Receiver argumentlari: sender (model), instance (obyekt), created (post_saveda — yangi/yangilandi), **kwargs (har doim qo'shing).

  2. Middleware — so'rov qatlami. Middleware — har so'rov/javobni qayta ishlovchi qatlam: so'rov view'ga kirishdan oldin va javob chiqishdan keyin ishlaydi. __call__(request) metodi — get_response(request)dan oldin (so'rov) va keyin (javob). MIDDLEWARE ro'yxatiga qo'shiladi (tartib muhim). Butun ilova uchun umumiy mantiq: autentifikatsiya, sessiya, CORS, log, xavfsizlik. Django tayyor middleware'lar beradi; o'z middleware'ingiz ham mumkin.

  3. Vazifalarni ajratish. Signal va middleware yon ta'sirni (audit, log, email) asosiy kod'dan ajratadi: view o'z ishini qiladi (kurs yaratadi), signal/middleware yon ta'sirni alohida qiladi — bu "vazifalarni ajratish" (separation of concerns). Afzalligi: toza kod (view yengil), takrorsiz (yon ta'sir bir joyda), kengaytiriladigan. Lekin signal "yashiringan" (kod'da ko'rinmaydi) — kuzatishni qiyinlashtiradi, shuning uchun ehtiyot: signal ajratilgan yon ta'sir uchun, oddiy holatda to'g'ridan chaqiriq aniqroq. Signal'da og'ir ish qilmang (fon vazifasi, 20.14).

Keyingi darsda deploy ni o'rganamiz va 21-qismni yakunlaymiz: Django loyihasini ishlab chiqarishga chiqarish — settings (production), WSGI/ASGI, static fayllar, xavfsizlik va server sozlamalari.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
21.15-dars: Signal va middleware — IlmHamroh