← Back to Django Course | Chapter 12: Signals & Middleware | Lesson 2 of 8

post_save नामक Signal

post_save Django का एक bell बजाना है ठीक उसके बाद जब कुछ database में save हो जाता है, ताकि आप इस पर react कर सकें।
Syntax
markup
from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=ModelName)
def handler_name(sender, instance, created, **kwargs):
    if created:
        # run only on first insert

post_save को क्या Trigger करता है?

post_save save() database में लिखना खत्म करने के ठीक बाद fire होता है। Django इसे sender (model class), instance (saved object), और created (एक नई row के लिए True) pass करता है।

उदाहरण: What Triggers post_save?

post_save fires right after save() finishes writing to the database. Django passes it sender (the model class), instance (the saved object), and created (True for a new row).

markup
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Profile

@receiver(post_save, sender=Profile)
def profile_saved(sender, instance, created, **kwargs):
    print(f"Profile {instance.pk} saved, created={created}")
{# Django-only code -- models.py/views.py/urls.py/settings.py snippets, or template markup using Django template tags/variables -- can't run standalone via Judge0 or the browser preview, since it needs a real Django project. Only this course's pure-Python examples (example_lang == 'python', no Django imports) are actually runnable, so those still get the button below. #}

created Flag उपयोग करना

एक बहुत common pattern यह है कि setup logic सिर्फ पहली बार एक row insert होने पर चलाएं, जैसे हर बार एक नया User बनने पर एक related Profile auto-create करना।

उदाहरण: Using the created Flag

A very common pattern is to run setup logic only the first time a row is inserted, such as auto-creating a related Profile whenever a new User is created.

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

@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)
{# Django-only code -- models.py/views.py/urls.py/settings.py snippets, or template markup using Django template tags/variables -- can't run standalone via Judge0 or the browser preview, since it needs a real Django project. Only this course's pure-Python examples (example_lang == 'python', no Django imports) are actually runnable, so those still get the button below. #}

Infinite Save Loops से बचना

एक post_save receiver के अंदर उसी model के लिए instance.save() फिर से call करना post_save को फिर से trigger करता है, जो हमेशा के लिए loop हो सकता है। इसके बजाय QuerySet.update() उपयोग करें, क्योंकि यह signal फिर से fire नहीं करता।

Warning: अपने ही post_save receiver के अंदर कभी unguarded instance.save() call न करें।

उदाहरण: Avoiding Infinite Save Loops

Calling instance.save() again inside a post_save receiver for the same model re-triggers post_save, which can loop forever. Use QuerySet.update() instead, since it doesn't re-fire the signal.

markup
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Article

@receiver(post_save, sender=Article)
def set_slug(sender, instance, created, **kwargs):
    if created and not instance.slug:
        Article.objects.filter(pk=instance.pk).update(slug=f"article-{instance.pk}")
{# Django-only code -- models.py/views.py/urls.py/settings.py snippets, or template markup using Django template tags/variables -- can't run standalone via Judge0 or the browser preview, since it needs a real Django project. Only this course's pure-Python examples (example_lang == 'python', no Django imports) are actually runnable, so those still get the button below. #}

sender के साथ Scoping करना

Connect करते समय sender= pass करना एक receiver को एक model तक सीमित करता है। वही receiver function कई senders से connected हो सकता है अगर आपको shared behavior चाहिए।

उदाहरण: Scoping with sender

Passing sender= when connecting limits a receiver to one model. The same receiver function can be connected to multiple senders if you want shared behavior.

markup
from django.db.models.signals import post_save
from .models import Article, Profile

def log_change(sender, instance, **kwargs):
    print(f"{sender.__name__} #{instance.pk} changed")

post_save.connect(log_change, sender=Article)
post_save.connect(log_change, sender=Profile)
{# Django-only code -- models.py/views.py/urls.py/settings.py snippets, or template markup using Django template tags/variables -- can't run standalone via Judge0 or the browser preview, since it needs a real Django project. Only this course's pure-Python examples (example_lang == 'python', no Django imports) are actually runnable, so those still get the button below. #}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
आम गलतियां
  1. created flag जांचना भूल जाना और हर update पर भी 'new object' logic चलाना।
  2. उसी model पर उसके post_save receiver के अंदर बिना guard instance.save() फिर से call करके infinite loops cause करना।
  3. एक receiver connect करना लेकिन इसे शामिल करने वाला module कभी import न करना, इसलिए यह चुपचाप कभी नहीं चलता।
चैप्टर सारांश
  • post_save एक model instance के save() method पूरा होने के तुरंत बाद fire होता है।
  • created boolean आपको बताता है कि यह एक INSERT था या एक UPDATE।
  • एक receiver को एक specific model तक scope करने के लिए sender=Model उपयोग करें।
  • Recursion रोकने के लिए उसी instance को इसके अपने post_save receiver के अंदर फिर से save करने से बचें।

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.