Django Rest Framework вызывает пользовательскую функцию при создании модели
Предположим, я хочу делать некоторые дополнительные действия всякий раз, когда создается модель в моем Django App:
models.py:
class MyModel(models.Model):
name = models.CharField(max_length=255)
def do_some_extra_stuff(self):
// whatever...
return "I did some extra stuff"
Предположим, что дополнительный материал - это какая-то долго выполняющаяся асинхронная задача.
Я использую Django Rest Framework и имею стандартные ModelSerializer
и ViewSet
.
Мой вопрос в том, где лучше всего разместить вызов do_some_extra_stuff
? Я могу предложить следующие варианты:
- В методе serializer.create
- В методе viewset.create
- В методе model.save
- В сигнале post_save
Я склоняюсь к #1 или #2, потому что я хочу, чтобы этот fn вызывался только при взаимодействии обычных пользователей с API - не при использовании Django Admin или shell.
Этот вопрос, вероятно, будет закрыт, потому что он основан на мнении, поэтому вот мое мнение по этому поводу!
Фоновые задачи
Используйте Celery или Django-RQ.
Celery "лучше", но Django-RQ (и самого RQ) почти всегда достаточно, если у вас есть хорошее логирование и отчет об ошибках. Обычно мы имеем дело не с переводами банковских счетов.
#2 - Viewset Based
Я считаю, что сериализаторы должны только сериализовать и проверять. Из-за этого любая пользовательская логика сохранения должна идти в ViewSet
- впереди, видна в момент использования, и имеет доступ ко всему без всяких ухищрений контекста сериализатора.
class MyViewSet(ModelViewSet):
def perform_create(self, serializer):
# pass a value into save(), which passes it to model.create()
serializer.save(org_id=self.request.user.secret_org_id)
# use the serializer instance that was created to enqueue a bg task
my_background_task.delay(item_pk=serializer.instance.pk)
Это просто предпочтение. Совершенно нормально поместить его в сериализатор, если так вы обычно выполняете другие задачи. Единственная цель - последовательность.
Это может иметь больше смысла, если вы представите себе использование 1 сериализатора для каждого действия - list
, create
и update
.
Другие методы
#3 В методе model.save
model.save()
не вызывается в некоторых редких случаях, и это не то место, где я ожидаю увидеть логику, запускающую другие задачи. Там работают некоторые очистители полей модели. Опять же, это предпочтение, но использование этого метода с DRF кажется необычным, в отличие от использования чистого django и использования админки сайта.
#4 В сигнале post_save
Мне кажется, что сигналы после сохранения находятся слишком далеко от модели, а также не вызываются в некоторых редких случаях (в основном, как и в #3). Я бы предпочел быть явным в таких вещах, поэтому я держу их близко к тому месту, где я ожидаю их увидеть. Мы используем сигналы post_save для других вещей, но они страдают от невозможности увидеть контекст, и в них трудно передать дополнительные параметры.