Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/333.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ssl/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么我可以在访问对象期间访问它';s post_save信号,但不是当我在该信号中触发在另一个进程上调用它的代码时_Python_Django_Django Signals - Fatal编程技术网

Python 为什么我可以在访问对象期间访问它';s post_save信号,但不是当我在该信号中触发在另一个进程上调用它的代码时

Python 为什么我可以在访问对象期间访问它';s post_save信号,但不是当我在该信号中触发在另一个进程上调用它的代码时,python,django,django-signals,Python,Django,Django Signals,好了,我对django的信号有意见 我有一个模型 为了加快页面加载的响应速度,我正在卸载一些必须完成的密集处理,通过调用我们正在运行的第二个本地主机Web服务器,这两个服务器都使用相同的数据库。我看到调用进程可以检索对象,但被调用进程不能。端口80和端口[port]都指向运行在同一数据库上的django进程。 在models.py中 class A(models.Model): stuff... def trigger_on_post_save( sender, instance,

好了,我对django的信号有意见

我有一个模型 为了加快页面加载的响应速度,我正在卸载一些必须完成的密集处理,通过调用我们正在运行的第二个本地主机Web服务器,这两个服务器都使用相同的数据库。我看到调用进程可以检索对象,但被调用进程不能。端口80和端口[port]都指向运行在同一数据库上的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 )
In 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是在保存对象并写入数据库后调用的。这不正确吗?

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

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

  • ,并在提交后发出自定义信号
  • 让第二个进程等待一段时间,等待请求通过

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

    在从django admin创建新模型时也有同样的问题。覆盖手动管理事务的
    ModelAdmin.save\u 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
    

    我们遇到了一个类似的问题,我们最终使用了(注意:这只有在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 )
    

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

    这是一个使用装饰师的好地方。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
    

    我只想补充一点,使用芹菜并不能改变这个问题——我有一个芹菜任务来获取旧数据,因为请求的save()事务尚未提交。您需要在Task.run()中添加延迟,或者-更好-实例化任务“post_commit”而不是“post_save”。Django还没有提供这个信号,但看看Django的默认行为是在每次保存时提交,而不是在请求完成后提交。此外,post_save信号是在commitBTW之后发送的,如果你使用芹菜,你需要用倒计时来调用你的任务,因为如果你不这样做,你的对象还不可用。例如,
    tasks.mytask.apply_async(kwargs={'app_model':app_model'pk':instance.pk'field':'photo'},倒计时=1)
    。或者您可以使用.On 1.6,在发送到芹菜之前先手动提交事务。到目前为止效果很好。示例:
    来自django.db import transaction transaction.commit()tasks.mytask.delay(…)
    @gdakram强制提交是一个简单的解决方案,但如果您正在操作的代码实际上包装在一个更大的事务中(例如保存多个对象),则可能会提前提交事务。小心使用。它不应该是:反向(一些视图url,args(instance.pk)).read()?+1:这是Django 1.9的简洁的“含电池”解决方案。请注意,您甚至可以从“pre_save”信号中使用它,因为它只会在事务提交时触发,因此,例如,您可以在它访问数据库之前根据需要更改某些模型属性。如果您需要支持Django 1.6-1.8,请查看1.9中添加的功能的来源,这种方法不适用于ModelSerializer.create from rest framework。@MarkMishyn不知道这一点,因为我不相信我们当时正在使用DRF。我很想知道为什么它不能与DRF一起工作。@Yoanisigil因为rest框架的ModelSerializer用M2M分两步创建实例,所以当调用
    Model.objects.create
    时,即使使用
    transaction.on\u commit
    ,M2M字段也是空的。您可以在这里检查
    commit\u on\u success
    已在Django>1.8中删除。请参见此以了解替代方案:此解决方案似乎会导致无限循环。如果我在trigger_on_post_save函数中执行instance.save(),则.save()会重新触发@on_transaction_commit,导致递归错误loop@Dev您不必在信号中调用save(),因为它显然会导致重复调用。