2011-01-15 6 views
11

Próbuję napisać małą aplikację, która odbiera pliki wideo, i przekonwertować je do jednolitego formatu po ich przesłaniu (w ten sposób dodane do bazy danych). Przeszukałem internet, szukając najlepszego rozwiązania tego problemu, i postanowiłem wykorzystać sygnały Django z Celery. Ale na razie próbuję stworzyć proof-of-concept, aby sprawdzić, czy to działa.Django - sygnał post_init jest wywoływany w momencie zapisu instancji modelu i przed utworzeniem instancji. Czemu?

Próbuję wykonać metodę video_repalce() po przesłaniu nowego filmu wideo (w ten sposób do bazy danych został dodany nowy wiersz). Ale sygnał nie działa poprawnie lub nie rozumiem, jak działa cały system.

mi stosując Django 1.2.3 wstępnie zdefiniowane sygnału django.db.models.signals.post_init, który should be called after a model has been instantiated (a więc, nowy rekord został dodany do bazy danych).

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

Jednak post_init nazywa nie tylko kiedy nowa instancja modelu jest tworzony, ale także ...:

  1. Przed model jest nawet instancja. Mam na myśli to, że jest wywoływana, gdy pierwszy raz exeucte serwera, gdy nie ma nawet jeden wiersz danych w bazie danych (tak, nie powinny być tworzone instancję obiektów Model). Wersja self.pk to None!
  2. Po wykonaniu modelu save(). Powyższy kod jest również wykonywany po trafieniu na self.save().

Praktycznie nie działa zgodnie z dokumentami.

Co robię źle? Pamiętaj, że jest to dowód koncepcji. Zamierzam przenieść kod do Celery po tym, jak widzę, że działa. Ale jeśli sygnały nie działają poprawnie, Celery nie pomoże - sygnał zawsze będzie ponownie wysyłany kilka razy, gdy tylko save() lub zaktualizuje wideo.

Czy uważasz, że nie powinienem zadzwonić pod numer save() w metodzie replace_video()? Więc gdzie mam to nazwać? Który sygnał powinienem wybrać? post_save nie jest dobrą opcją, ponieważ jest również wywoływana za każdym razem, gdy uderzę save().

+0

Wspominasz, że sygnał jest wysyłany zawsze po uruchomieniu serwera, co się stanie, jeśli po prostu otworzysz powłokę 'manage.py shell 'i zaimportujesz model? –

Odpowiedz

12

Wydaje się, że masz trochę zamieszania w kwestii tego, co to znaczy wytworzyć obiekt. Nie ma nic wspólnego z bazą danych. To wystąpienie obiektu modelu bez zapisywania go do bazy danych, w którym to przypadku jego pk będzie None:

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

a to (pośrednio) instancję obiektu poprzez uzyskanie go z bazy danych:

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

Sygnał post_init zostanie wysłany w obu tych przypadkach, nawet jeśli żaden z nich nie ma nic wspólnego z zapisaniem w bazie danych.

Jeśli chcesz coś się wydarzy po zapisaniu, albo się zastąpić metodę save lub użyć sygnałów pre_save lub post_save. Możesz tam sprawdzić, czy obiekt został wcześniej zapisany, sprawdzając, czy jego wartość to pk Brak.

+0

Zawsze uważałem, że metoda 'pk is None' jest trochę przerażająca (można ją ustawić ręcznie), ale domyślam się, że jest to jedyny sposób. – vicvicvic

+0

W końcu użyłem 'post_save' i dodano warunek, aby sprawdzić, czy muszę zastąpić wideo. Dlatego nie nazywam rekursywnie 'save()'. –