How to pass kwargs from save to post_save signal

Question:

I’m wiring up a custom post_save signal and noticed that I can’t seem to find an easy way to pass a set of kwargs.

During the save itself (inside a custom form)

def save(self, commit=True):
    user = super(CustomFormThing, self).save(commit=False)
    #set some other attrs on user here ...
    if commit:
        user.save()

    return user

Then inside my custom post_save hook I have the following (but never get any kwargs)

@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
    some_id = kwargs.get('some', None)
    other_id = kwargs.get('other', None)

    if created:
        #do something with the kwargs above...

How might I pass kwargs from the save to the post_save event?

Asked By: Toran Billups

||

Answers:

I don’t think there’s a way to pass a separate set of kwargs. What args do you want in addition to the User attributes? You can access the User attributes in the signal handler on the instance argument. instance will be the User object that just got saved.

If there are other things you want to pass along, I suppose you could try to use the instance arg as a carrier pigeon:

def save(self, commit=True):
    user = super(CustomFormThing, self).save(commit=False)
    user.foo = 'bar'
    if commit:
        user.save()
    ...

Then in the handler:

def create_profile(sender, instance, created, **kwargs):
    myfoo = instance.foo

But the above is untested, and I’m not sure it will even work.

Answered By: alan

Built-in signals are sent by Django, so you can’t control their kwargs.

You can:

  1. Define and send your own signals.
  2. Store additional info in model instance. Like this

    def save(self, commit=True):
        user = super(CustomFormThing, self).save(commit=False)
        #set some other attrs on user here ...
        user._some = 'some'
        user._other = 'other'
        if commit:
            user.save()
    
        return user
    
    @receiver(post_save, sender=User)
    def create_profile(sender, instance, created, **kwargs):
        some_id = getattr(instance, '_some', None)
        other_id = getattr(instance, '_other', None)
    
        if created:
            #do something with the kwargs above...
    
Answered By: DrTyrsa

We can pass additional arguments as below:

def save(self, commit=True):
    user = super(CustomFormThing, self).save(commit=False)
    #set some other attrs on user here ...
    if commit:
        user.save(signal_kwargs={'_some': 'some', '_other': 'other'})

    return user

And you can get it from the post save method like:

@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
    some_id = kwargs.get('some', None)
    other_id = kwargs.get('other', None)
    if created:
        #do something with the kwargs above...
Answered By: nikeshPyDev
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.