所有,我有django信号的问题。
我有一个模特
为了加快页面加载的响应速度,我正在卸载必须完成的一些密集处理,通过调用我们正在运行的第二个localhost网络服务器,两者都使用相同的数据库。我看到调用进程可以检索对象的行为,但被调用的进程不能。端口80和端口[端口]都指向运行在同一数据库中的django进程。
在models.py
class A(models.Model):
stuff...
def trigger_on_post_save( sender, instance, create, raw, **keywords):
#This line works
A.objects.get( pk=instance.pk )
#then we call this
urlopen( r'http://127.0.0.1:[port]' +
reverse(some_view_url, args(instance_pk) ).read()
post_save.connect( trigger_on_post_save, A )
在views.py
中def some_view_function( request, a_pk ):
#This line raises an object_not_found exception
A.objects.get( pk=a_pk )
此外,在urlopen调用引发异常后,该对象在数据库中不存在。据我所知,在保存对象后调用了post_save,并将其写入数据库。这是不正确的吗?
答案 0 :(得分:16)
我们遇到了类似的问题,我们最终使用了on_commit callback(注意:这只适用于Django> = 1.9)。所以,你可以这样做:
from django.db import transaction
class A(models.Model):
stuff...
def trigger_on_post_save( sender, instance, create, raw, **keywords):
def on_commit():
urlopen(r'http://127.0.0.1:[port]' +
reverse(some_view_url, args(instance_pk) ).read()
transaction.on_commit(on_commit)
post_save.connect( trigger_on_post_save, A )
这里的想法是,在提交事务之后,您将调用端点,因此事务中涉及的实例将被保存;)。
答案 1 :(得分:13)
我相信post_save会在保存发生后触发,但会在事务提交到数据库之前触发。默认情况下,Django仅在请求完成后提交对数据库的更改。
解决问题的两种可能方法:
说实话,你的整个设置似乎有点讨厌。您应该查看Celery的异步任务排队。
答案 2 :(得分:2)
这是使用装饰器的好地方。 yoanis-gil的回答略有扩展:
from django.db import transaction
from django.db.models.signals import post_save
def on_transaction_commit(func):
def inner(*args, **kwargs):
transaction.on_commit(lambda: func(*args, **kwargs))
return inner
@receiver(post_save, sender=A)
@on_transaction_commit
def trigger_on_post_save(sender, **kwargs):
# Do things here
答案 3 :(得分:1)
从django admin创建新模型时遇到同样的问题。重写ModelAdmin.save_model
方法来手动管理交易。
def save_model(self, request, obj, form, change):
from django.db import transaction
with transaction.commit_on_success():
super(ModelAdmin, self).save_model(request, obj, form, change)
# write your code here