Где разместить логику изменения состояния одной сущности другой сущностью в Django REST Framework?
Представьте себе простое приложение, в котором пользователь может публиковать некоторые запросы (например, ему нужна помощь, еда), а другие пользователи могут через чат дать ответ на этот запрос. Вот мои упрощенные модели:
class UserRequest(models.Model):
ACTIVE = 'active'
INACTIVE = 'inactive'
STATUS_CHOICES = [
(ACTIVE, 'Active'),
(INACTIVE, 'Inactive'),
]
user = models.ForeignKey(User, on_delete=models.CASCADE)
request_text = models.TextField()
status = models.CharField(max_length=8, choices=STATUS_CHOICES, default=INACTIVE)
class RequestChat(models.Model):
user_request = models.ForeignKey(UserRequest, on_delete=models.CASCADE)
class ChatMessage(models.Model):
text = models.TextField()
chat = models.ForeignKey(RequestChat, on_delete=models.CASCADE)
Мне нужно реализовать такую функциональность:
Когда создано хотя бы одно сообщение в чате (записано в чат) - статус связанного запроса должен быть изменен с INACTIVE на ACTIVE.
Нужно ли поместить эту логику в метод save() модели ChatMessage или обработать ее с помощью сигнала Django? Или, возможно, есть другой способ сделать это? Кроме того, не могли бы вы порекомендовать какие-либо ресурсы, например, книги, статьи или видео, которые содержат руководство по этой теме?
Как и во всем, что касается архитектуры программного обеспечения: это зависит.
Тема, о которой вы спрашиваете, - проектирование агрегатов. Существует множество материалов. Я думаю, что в книге Вернона Implementing Domain Driven Design есть хороший пример по агрегированному проектированию. Мне кажется, я также нашел полезной эту статью, состоящую из 3 частей, посвященных агрегатному проектированию.
Ну, это не должно быть в методе сохранения. Метод сохранения относится к персистентным методам и не должен знать бизнес-правила о том, когда UserRequest становится активным или нет.
Должен быть некий объект домена, который знает, когда UserRequest становится АКТИВНЫМ. Этим доменным объектом может быть сам UserRequest, то есть UserRequest - это корневой агрегат, а ChatMessage - сущность внутри этого агрегата. При извлечении UserRequest извлекаются все ChatMessage. Добавление нового чат-сообщения осуществляется через корневой агрегат (userRequest.addChatMessage). Когда сообщение чата отправлено, вы можете изменить его статус на активный. Недостатком этого способа является то, что загрузка всех сообщений чата может быть неэффективной, а также то, что он создает много непредвиденных ситуаций в зависимости от того, какие операции разрешено выполнять пользователям (например: поскольку все сообщения чата изменяются через запрос, для сохранения последовательности в любой момент времени можно выполнить только одно изменение).
Другая альтернатива - сделать их разными агрегатами и использовать конечную согласованность. Когда ChatMessage сохраняется, он испускает событие, которое модуль UserRequest может прослушать и изменить статус на активный. В модуле UserRequest должна быть служба Domain, которая знает правила о том, когда запрос становится активным.
Оба подхода подходят, все зависит от особенностей вашей системы и бизнеса.