15

所有,我对 django 信号有疑问。

我有一个模型 为了加快页面加载的响应速度,我正在卸载一些必须完成的密集处理,通过调用我们正在运行的第二个本地主机网络服务器,两者都使用相同的数据库。我看到调用进程可以检索对象的行为,但被调用进程不能。端口 80 和端口 [port] 都指向在同一个数据库上运行的 django 进程。

在模型.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 是在保存对象并写入数据库后调用的。这是不正确的吗?

4

4 回答 4

15

我们遇到了类似的问题,最终使用了on_commit 回调注意:这仅适用于 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 )

这里的想法是您将在事务提交调用您的端点,因此事务中涉及的实例将已经保存;)。

于 2016-05-13T15:53:45.253 回答
13

我相信 post_save 在保存发生后触发,但在事务提交到数据库之前触发。默认情况下,Django 仅在请求完成后才提交对数据库的更改。

您的问题的两种可能的解决方案:

  1. 手动管理您的事务,并在您提交后触发自定义信号。
  2. 让您的第二个过程等待一段时间以使请求通过。

不过老实说,您的整个设置似乎有点讨厌。您可能应该研究Celery的异步任务队列。

于 2011-12-16T04:53:50.557 回答
5

这是使用装饰器的好地方。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
于 2017-12-29T19:18:29.637 回答
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
于 2015-12-28T10:24:08.510 回答