Django - 在模型实例save& amp;上调用post_init信号。甚至在创建实例之前。为什么?

时间:2011-01-15 14:55:05

标签: python django signals

我正在尝试编写一个接收视频文件的小应用程序,并在上传后将它们转换为统一格式(因此添加到数据库中)。我已经在网上搜索了最佳解决方案,并决定使用Django的信号Celery。但是现在我正试图创建一个概念验证,看看它是否有效。

我正在尝试在上传新视频后执行video_repalce()方法(因此,新行已添加到数据库中)。但是信号不能正常工作,或者我不明白整个系统是如何工作的。

我正在使用带有预定义信号django.db.models.signals.post_init Django 1.2.3 should be called after a model has been instantiated(因此,新行被添加到数据库中)。

from django.core.files.base import File
from django.db.models.signals import post_init
import os
import os.path
import subprocess

class Project(models.Model):
    video = models.FileField(upload_to="projects/videos")

    def replace_video(self):
        """Replace original video with an updated one."""

        # Video conversion process code goes here,
        # resulting in a new external video file.

        self.video.delete() # Delete the original video.
        self.video.save("newfile.webm", File(open("path/to/newfile.webm") ,"wb"))) # Save the new video instead.

        self.save() # Commit everything to database.

        os.remove("path/to/newfile.webm") # Remove original video copy after it was commited (copied) into the DB.

# ...
# ...

def handle_new_project(sender, **kwargs): 
    """Handels some additional tasks for a new added project. i.e. convert video to uniform format."""

    project = kwargs['instance']
    project.replace_video()

# Call 'Project.replace_video()' every time a new project is added.
post_init.connect(handle_new_project, sender=Project, dispatch_uid="new_project_added")

但是,在创建新模型实例时,post_init不仅称为 ,而且还是......:

  1. 在模型甚至实例化之前。我的意思是,当我第一次执行服务器时调用它,当数据库中甚至没有单行数据时(因此,不应该实例化Model对象)。实例self.pkNone
  2. save() - 模型时。当我点击self.save()
  3. 时,也会执行上面的代码

    实际上,它根据文档不起作用。

    我做错了什么?请记住,这是一个概念验证。我打算在看到它正常工作后将代码移到Celery。但是,如果信号无法正常工作,Celery将无济于事 - 每当我save()或更新视频时,信号都会重复发送几次。

    您认为我不应该在save()方法中调用replace_video()吗?那我应该在哪里打电话呢?我应该选择哪个信号? post_save不是一个好的选择,因为只要我点击save(),它就会被调用。

2 个答案:

答案 0 :(得分:13)

您似乎对实例化对象意味着什么感到困惑。它与数据库没有任何关系。这会实例化一个模型对象而不将其保存到数据库中,在这种情况下,它的pk将为None:

MyObject(field1='foo', field2='bar')

并且(间接地)通过从数据库中获取对象来实例化它:

MyObject.objects.get(field1='baz')

post_init信号将在这两种情况下发送,即使它们都与保存到数据库无关。

如果您希望在保存时发生某些事情,请覆盖save方法本身,或使用pre_savepost_save信号。您可以通过验证其pk是否为无来检查该对象之前是否已保存。

答案 1 :(得分:0)

我知道这个问题很老,但我有一个类似的问题,简单的解决方案就是使用 post_save 信号并检查是否创建

@receiver(post_save, sender=YourSender) 
   def when_init(sender, instance, created, **kwargs):
      if created:
         ...