Django - сигнал post_init вызывается при сохранении экземпляра модели и даже до того, как экземпляр будет создан. Зачем? - PullRequest
11 голосов
/ 15 января 2011

Я пытаюсь написать небольшое приложение, которое получает видеофайлы, и конвертировать их в единый формат после того, как они были загружены (таким образом, добавлены в базу данных). Я искал в Интернете лучшее решение для этого и решил использовать сигналы Django с Celery . Но сейчас я пытаюсь создать концептуальное подтверждение, чтобы увидеть, работает ли оно.

Я пытаюсь выполнить метод video_repalce() после загрузки нового видео (таким образом, новая строка была добавлена ​​в базу данных). Но сигнал работает неправильно, или я не понял, как работает вся система.

Я использую Django 1.2.3 с предопределенным сигналом django.db.models.signals.post_init, который должен вызываться после вызова модели (таким образом , новая строка была добавлена ​​в базу данных).

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.pk равен None!
  2. Когда save() - это модель. Код выше также выполняется, когда я нажимаю self.save().

Практически, это не работает в соответствии с документами.

Что я делаю не так? Помните, что это подтверждение концепции. Я собираюсь переместить код в Сельдерей после того, как увижу, что он работает. Но, если сигналы не работают правильно, Сельдерей не поможет - сигнал всегда будет повторно отправляться пару раз, когда я save() или обновляю видео.

Как вы думаете, я не должен вызывать save() внутри replace_video() метода? Так, где я должен назвать это? Какой сигнал выбрать? post_save не очень хороший вариант, потому что он также вызывается всякий раз, когда я нажимаю save().

1 Ответ

13 голосов
/ 15 января 2011

Вы, кажется, немного запутались из-за того, что означает создание объекта. Это не имеет ничего общего с базой данных. Это создает экземпляр объекта модели без сохранения его в базе данных, в этом случае его pk будет None:

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

и это (косвенно) создает объект, получая его из базы данных:

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

Сигнал post_init будет отправлен в обоих этих случаях, даже если ни один из них не имеет никакого отношения к сохранению в базе данных.

Если вы хотите, чтобы что-то происходило при сохранении, либо переопределите сам метод save, либо используйте сигналы pre_save или post_save. Вы можете проверить, был ли объект сохранен ранее, проверив, имеет ли pk значение Нет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...