2011-01-15 3 views
11

Sto provando a scrivere una piccola applicazione che riceve i file video e li converte in un formato uniforme dopo che sono stati caricati (quindi aggiunti al database). Ho cercato sul web la soluzione migliore e ho deciso di utilizzare i segnali di Django con Celery. Ma per ora sto cercando di creare un proof-of-concept per vedere se funziona.Il segnale Django - post_init viene richiamato su Salva istanza modello e prima ancora viene creata l'istanza. Perché?

Sto provando ad eseguire un metodo video_repalce() dopo che un nuovo video è stato caricato (quindi, una nuova riga è stata aggiunta al database). Ma il segnale non funziona bene, o non ho capito come funziona l'intero sistema.

sto usando Django 1.2.3 con pre-definiti segnale django.db.models.signals.post_init, che should be called after a model has been instantiated (quindi, una nuova riga è stato aggiunto al database).

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") 

Tuttavia, post_init si chiama non solo quando viene creata una nuova istanza modello, ma anche ...:

  1. Prima che il modello è anche un'istanza. Ciò che intendo è che viene chiamato quando esco dal server per la prima volta, quando non c'è nemmeno una singola riga di dati nel database (quindi, nessun oggetto Modello dovrebbe essere istanziato). L'istanza self.pk è None!
  2. Quando save() -ing un modello. Il codice sopra viene anche eseguito quando ho colpito self.save().

Praticamente, non funziona secondo i documenti.

Cosa sto sbagliando? Ricorda che questa è una dimostrazione di concetto. Intendo spostare il codice su Celery dopo averlo visto funzionare. Ma, se i segnali non funzionano correttamente, Celery non sarà di aiuto - Il segnale verrà sempre inviato nuovamente un paio di volte ogni volta che I save() o aggiorno un video.

Pensi che non dovrei chiamare save() nel metodo replace_video()? Quindi dove dovrei chiamarlo? Quale segnale dovrei scegliere? post_save non è una buona opzione perché viene anche chiamato ogni volta che colpisco save().

+0

Si dice che il segnale viene sempre inviato quando si esegue il server, cosa succede se si apre solo una shell 'shell manage.py' e si importa il modello? –

risposta

12

Sembra che tu abbia un po 'di confusione su cosa significhi istanziare un oggetto. Non ha nulla a che fare con il database. Questo crea un'istanza di un oggetto del modello senza salvarlo nel database, nel qual caso la sua pk sarà None:

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

e questo (indirettamente) crea un'istanza di un oggetto da ottenere dal database:

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

Il segnale post_init verrà inviato in entrambi questi casi, anche se nessuno di questi ha nulla a che fare con il salvataggio nel database.

Se si desidera che qualcosa accada quando si salva, ignorare il metodo save o utilizzare i segnali pre_save o post_save. È possibile controllare se l'oggetto è stato precedentemente salvato, verificando se il suo numero pk è Nessuno.

+0

Ho sempre trovato il metodo 'pk is None 'un po' spaventoso (è possibile impostarlo manualmente), ma suppongo che sia l'unico modo che esiste. – vicvicvic

+0

Alla fine ho usato 'post_save' e ho aggiunto una condizione per verificare se ho bisogno di sostituire il video. Quindi, non sto chiamando 'save()' in modo ricorsivo. –

Problemi correlati