2011-01-15 4 views
11

ビデオファイルを受け取り、アップロードされた後(つまり、データベースに追加された)、一様なフォーマットに変換する小さなアプリケーションを作成しようとしています。私はこのための最良の解決策をWebで検索し、CeleryでDjangoの信号を使用することに決めました。しかし、今のところ私はそれが動作するかどうかを確かめるために概念の証明を作成しようとしています。Django - post_initシグナルは、インスタンスインスタンスが保存される前に、モデルインスタンスsaveで呼び出されます。どうして?

新しいビデオがアップロードされた後(つまり、新しい行がデータベースに追加された後)、video_repalce()メソッドを実行しようとしています。しかし、信号が正しく機能しない、または私はシステム全体の仕組みが理解できませんでした。

Iは(したがって、新しい行がデータベースに追加された)がshould be called after a model has been instantiated、事前定義された信号django.db.models.signals.post_initジャンゴ1.2.3を使用しています。

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. 前に。つまり、データベースにデータが1行もない(つまり、モデルオブジェクトをインスタンス化する必要はありません)場合、初めてサーバーを実行するときに呼び出されます。インスタンスのself.pkNoneです!
  2. save() - 機種を指定した場合。上記のコードは、私がself.save()を押すと実行されます。

実際には、ドキュメントに従って動作しません。

私は間違っていますか?これは概念実証であることを忘れないでください。私はそれが働いていることを確認した後にコードをCeleryに移動するつもりです。しかし、信号が正常に機能しない場合、Celeryは助けになりません - 私はsave()またはビデオを更新する度に、信号は常に数回再送されます。

save()replace_video()の方法で呼び出すべきではないと思いますか?だから私はそれをどこに呼びますか?どの信号を選ぶべきですか? post_saveは、私がsave()を押すたびに呼び出されるため、良い選択肢ではありません。

+0

サーバを実行するときにシグナルが常に送信されることを言いますが、シェル 'manage.py shell'を開いてモデルをインポートするとどうなりますか? –

答えて

12

オブジェクトのインスタンス化の意味を少し混乱させるようです。データベースとは何の関係もありません。

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

と、これは(間接的に)データベースから取得することによって、オブジェクトをインスタンス化します:

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

そのPKはNoneになります。その場合にはこれは、それをデータベースに保存せずにモデルオブジェクトをインスタンス化しますpost_initシグナルは、どちらの場合もデータベースに保存することと関係なく、どちらの場合でも送信されます。

保存時に何か起こりたい場合は、saveメソッド自体を上書きするか、pre_saveまたはpost_saveシグナルを使用してください。そのオブジェクトが以前に保存されているかどうかは、pkがNoneであることを確認することで確認できます。

+0

私はいつも 'pk is None'メソッドが少し怖いことを発見しましたが(手動で設定することも可能ですが)、唯一の方法だと思います。 – vicvicvic

+0

私は最終的に 'post_save'を使用し、ビデオを置き換える必要があるかどうかを確認する条件を追加しました。したがって、私は 'save()'を再帰的に呼び出すつもりはありません。 –

関連する問題