传递参数django信号-后保存/前保存

传递参数django信号-后保存/前保存,django,signals,argument-passing,Django,Signals,Argument Passing,我正在Django 1.6中开发一个通知应用程序,我想将其他参数传递给Django信号,例如post\u save。我试着使用部分工具,但没有运气 from functools import partial post_save.connect( receiver=partial(notify, fragment_name="categories_index"), sender=nt.get_model(), dispatch

我正在Django 1.6中开发一个通知应用程序,我想将其他参数传递给Django信号,例如
post\u save
。我试着使用部分工具,但没有运气

from functools import partial
post_save.connect(
    receiver=partial(notify,
        fragment_name="categories_index"),
            sender=nt.get_model(),
            dispatch_uid=nt.sender
    )
notify
函数有一个关键字参数
fragment\u name
,我想在信号中作为默认值传递它


有什么建议吗?

这里定义了Django中负责信号的代码。看看它是如何检查接收器的?我怀疑你的问题就在那里。也许您想要的是一个包装器函数,它接受信号需要的参数,但也设置fragment_name的值

def fragment_receiver(sender, **kwargs)
    return notify(sender, fragment_name="categories_index", **kwargs)

您可以在模型的自定义保存方法中定义其他参数,如下所示:

class MyModel(models.Model):
    ....

    def save(self, *args, **kwargs):
        super(MyModel, self).save(*args, **kwargs)
        self.my_extra_param = 'hello world'
并通过post_save signal receiver中的实例访问此附加参数:

@receiver(post_save, sender=MyModel)
def process_my_param(sender, instance, *args, **kwargs):
    my_extra_param = instance.my_extra_param

如果预定义的信号不适用,则始终可以定义自己的信号

import django.dispatch

custom_post_save = django.dispatch.Signal(providing_args=[
    "sender", "instance", "created", "raw", "using", "update_fields", "fragment_name"
])
然后在您的模型中,您只需覆盖
save()
方法:

from django.db import router

class YourModel(Model):

    # Your fields and methods

    def save(self, force_insert=False, force_update=False, using=None,
         update_fields=None):
         custom_signal_kwargs = {
             "sender": self.__class__,
             "instance": self,
             "created": self.pk is None,
             "raw": False, # As docs say, it's True only for fixture loading
             "using": using or router.db_for_write(self.__class__, instance=self),
             "update_fields": update_fields,
             "fragment_name": "categories_index" # The thing you want
         }
         super(YourModel, self).save(force_insert=False, force_update=False, using=None,
             update_fields=None)
         custom_post_save.send(**custom_signal_kwargs) # Send custom signal

现在,您只需将此自定义信号连接到您的
notify(…)
接收器,它将在kwargs中获得
fragment\u name

您尝试使用partial的操作无效,因为默认情况下,这些接收器是使用弱引用连接的

根据报告:

Django默认情况下将信号处理程序存储为弱引用,因此如果处理程序是本地函数,则可能会对其进行垃圾收集。为了防止出现这种情况,在调用信号的connect()时,pass weak=False

Include weak=False,此部分将不会被垃圾收集

receiver(post_save, sender=aSenderClass, weak=False)(extra_args(fragment_name="meep")(my_post_save))
我的原始答案如下,并采取了一种不使用局部搜索的方法

您可以在连接post_save接收器之前装饰post save功能

from django.dispatch import receiver
from django.db.models.signals import pre_save, post_save, post_delete

def extra_args(fragment_name, *args, **kwargs):
    def inner1(f, *args, **kwargs):
        def inner2(sender, instance, **kwargs):
            f(sender, instance, fragment_name=fragment_name, **kwargs)
        return inner2
    return inner1

@receiver(post_save, sender=ExampleModel)
@extra_args(fragment_name="categories_index")
def my_post_save(sender, instance, fragment_name, **kwargs):
    print "fragment_name : ", fragment_name
    #rest of post save...
extra_args中的extra inner用于

如果您希望以编程方式执行此操作,其工作方式相同,但请注意,您需要包括
weak=False
,以使包装函数不会被垃圾收集

receiver(post_save, sender=aSenderClass, weak=False)(extra_args(fragment_name="meep")(my_post_save))
或者不包装,但调用post_save.connect,就像您最初尝试使用partial

post_save.connect(extra_args(fragment_name="meepConnect")(my_post_save), sender=Author, weak=False)

我尝试了尤金·索尔达托夫的答案,但这让我意识到答案可能更简单:

你可以有这样的东西:

obj = MyModel.objects.first()
obj.my_extra_param = "hello world"
obj.save() # this will trigger the signal call
然后让接收器像尤金的回答一样,它仍然可以工作

@receiver(post_save, sender=MyModel)
def process_my_param(sender, instance, *args, **kwargs):
    my_extra_param = instance.my_extra_param
无需创建易于出现错误的自定义保存方法


这就是它目前在Django3.0中的工作方式。我还没有尝试过以前的版本。

但是包装器将如何为fragment\u name发送不同的值?在注册post_save时,我需要传递额外的参数,以便在信号处理程序中访问它。。你能详细说明一下你的方法吗?嗨,丹,你的方法看起来很可靠而且合乎逻辑。虽然我试图实现它,但django信号并没有接收到它,你们知道我做错了什么吗?这是我的startup.py脚本,它在django load上执行一次嘿,看一下代码,你是对的。我经历了一些奇怪的行为,认为这只是我的壳。似乎如果您添加了weak=False,那么如果所讨论的模型是Django的用户模型(我不控制它的save函数),它就会工作。我也不能使用这种技术,因为我的
post\u save
处理程序会立即触发。我在胡思乱想。这看起来是个很好的解决办法!我想知道,如果我们使用
weak=False
,垃圾收集会发生什么情况?在这种情况下,使用getattr()访问post save接收器中的附加参数(而不是直接访问它)的目的是什么?您是对的,不必调用getattr,参数可以直接访问。我已经编辑了答案,谢谢。这个答案是错误的。如果要工作,则需要在调用超级保存方法之前执行
self.my_extra_param='hello world'