Xiang Wang @ 2017-05-24 16:32:47
注册一个post_save
后,就会在receivers里面添加对应的key和函数. 如果下次sender来了,就根据_make_id
来判断是否要执行. 这会导致dispatch无法处理proxy的model. 想解决?12年前就提出来了,没采纳
def _make_id(target):
if hasattr(target, "__func__"):
return (id(target.__self__), id(target.__function__))
return id(target)
class Signal:
def send(self, sender, **named):
return [
(receiver, receiver(signal=self, sender=sender, **named)
for receiver in self._live_receivers(sender)
]
def _live_receivers(self, sender):
senderkey = _make_id(sender)
for (receiverkey, r_senderkey), receiver in self.receivers:
if r_senderkey == NONE_ID or r_senderkey = senderkey:
receivers.append(receiver)
- preventing duplicate signals
每次绑定的时候,同样的函数只会绑定一次。多个函数会按照绑定的顺序依次执行。 如果你希望一个函数绑定2次,需要添加
dispatch_uid
参数
from django.core.signals import request_finished
request_finished.connect(my_callback, dispatch_uid="my_unique_identifier")
import django.dispatch
pizza_done = django.dispatch.Signal()
pizza_done.connect(function, sender)
pizza_done.send(sender=self.__class__, toppings=toppings, size=size)
def my_callback(sender, **kwargs):
log.info("Request finished!")
def my_signal(sender, *args, **kwargs):
print(kwargs['instance'])
print("calling my_signal")
from django.core.signals import request_finished
request_finished.connect(my_callback)
from django.db.models.signals import pre_init
pre_init.connect(my_signal, sender=TestSignal)
再用django-rest-framework的ModelSerializer的时候, 因为ModelSerializer的create, 是先创建model,然后设置manytomany的, 所以会导致如果通过post_save来创建, 会导致拿不到关联的manytomany的情况
def create(self, validated_data):
for field in info.relations.items():
many_to_many[field_name] = validated_data.pop(field_name)
instance = create(**validated_data)
for field_name, value in many_to_many.items():
getattr(instance, field_name).set(value)
- 参数:
- sender: class的类
- instance: 对象
- created: 是否是刚创建的
update_fields
:- 这个是Model.save的时候传入的. 不传就是None了
- 如果是update_or_create,更新时有update_fields
- 如果有外键关联到这个model,那这个外键被删除的时候,触发的联合删除也会触发,并且是先有依赖的外键的model被删除,这个instance本身是最后被删除的
- 参数:
- sender
- instance, 注意此时 instance.id 还是可以获取的
- using
批量删除的时候每条数据都会触发信号, 但是DELETE语句是只有一句(用的id__in)。所以会导致第一个model的post_delete里面去查询返回的数字是0
M2Mchanged有点复杂,因为他分为正向和反向的情况,可能是user.books.add(book) 也可能是 book.user_set.remove(user)
每次保存reverse只会触发一个
每次新增pre_add, post_add都会触发一次
直接set也会给每个触发pre_add,post_add,pre_remove,post_remove。但是不变的不会触发
无法拿到被添加的child,因为只有pk_set
- 示例
from django.db.models.signals import m2m_changed
m2m_changed.connect(function, sender=ManyModel.texts.through)
- 参数
- sender
- instance
- action:
pre_add|post_add|pre_remove|post_remove|pre_clear|post_clear
- reverse
- model
- pk_set
- using
- Model_signals
- pre_init
- post_init
- post_save
- pre_delete
- class_prepared
- Management signals
- Request/response signals
- Test signals
- database wrappers