Как спроектировать внешние события и модели Django?Python

Программы на Python
Ответить
Anonymous
 Как спроектировать внешние события и модели Django?

Сообщение Anonymous »

Я создаю серверное приложение Django, и в нем есть несколько разных моделей. Одной из этих моделей является Driver, и при вызове конечной точки create-driver я хочу сделать следующее:
  • создать драйвер в базе данных
  • создать учетную запись пользователя для водителя в моем каталоге B2C
  • отправить электронное письмо водителю при успешном создании
  • отправить уведомление администраторам об успешном создании
Операции 1 и 2 должны либо завершиться успешно, либо завершиться неудачей вместе (атомарная транзакция).
Изначально я обрабатывал операции 1 и 2 в Метод сохранения модели драйвера выглядит следующим образом:

Код: Выделить всё

Class Driver(models.Model):
#...

def save(self, *args, **kwargs):
if self.pk is None:
# Creating a new driver
if self.b2c_id is None:
graph_client = MicrosoftGraph()
try:
with transaction.atomic():
user_info = B2CUserInfoSchema(
display_name=f"{self.first_name} {self.last_name}",
first_name=self.first_name,
last_name=self.last_name,
email=self.email,
phone_number=self.phone,
custom_attributes={
"Role": UserRole.DRIVER.value,
},
)
res = graph_client.create_user(user_info) # create B2C user
self.b2c_id = res.id
super().save(*args, **kwargs) # create driver in database
except Exception as e:
raise e
else:
# Updating an existing driver
super().save(*args, **kwargs)```
Это работало отлично, но мне не нравилось смешивать здесь обязанности и добавлять логику создания пользователей B2C в метод сохранения моего драйвера. Мне нравится, чтобы метод save был простым и ориентирован на создание записи в базе данных.
Я попробовал обновить архитектуру и начал использовать для этого контроллеры и диспетчеры событий. Моя архитектура сейчас такая:

Код: Выделить всё

class Driver(models.Model):
# ...

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.domain_events = []

def save(self, *args, **kwargs):
if self.pk is None:
self.domain_events.append(EntityEvent(self, EntityEventType.CREATE))
else:
self.domain_events.append(EntityEvent(self, EntityEventType.UPDATE))
super().save(*args, **kwargs)

class EntityEventType(Enum):
CREATE = "create"
UPDATE = "update"

class EntityEvent:
def __init__(self, db_entity: models.Model, event_type: EntityEventType):
self.db_entity = db_entity
self.event_type = event_type

class EntityEventDispatcher:
def __init__(self, b2c_entity_service: B2CEntityService):
self._b2c_entity_service = b2c_entity_service

def dispatch(self, events: list[EntityEvent]):
for event in events:
match event.event_type:
case EntityEventType.CREATE:
self._b2c_entity_service.create_entity(event.db_entity)
case EntityEventType.UPDATE:
self._b2c_entity_service.update_entity(event.db_entity)

class EntityController:
def __init__(self, db_entity: models.Model):
self._db_entity = db_entity
self._event_dispatcher = EntityEventDispatcher(
B2CEntityFactory.from_entity_type(type(db_entity))
)

def _dispatch_events(self):
self._event_dispatcher.dispatch(self._db_entity.domain_events)

@transaction.atomic
def create_entity(self):
self._db_entity.save()
self._dispatch_events()
return self._db_entity

@transaction.atomic
def update_entity(self):
self._db_entity.save()
self._dispatch_events()
return self._db_entity

@transaction.atomic
def delete_entity(self):
self._db_entity.delete()
self._dispatch_events()
return self._db_entity

class DriverController(EntityController):
def __init__(self, driver: Driver):
super().__init__(driver)
Как видите, сейчас я использую диспетчеры и контроллеры и разделяю логику. Как я сейчас создаю драйверы, показано ниже:

Код: Выделить всё

def create_driver(request):
data = json.loads(request.body)
driver_controller = DriverController(Driver(**data))
driver = driver_controller.create_entity()
Очевидно, что при втором подходе было добавлено больше кода и создано несколько классов, но преимущество, которое я получил, заключалось в разделении логики между моделями базы данных и внешними зависимостями.
Теперь я смогу легко добавлять свои внешние зависимости, такие как отправка электронных писем и уведомлений, просто добавляя события в свой DriverController и отправляя их моему диспетчеру для обработки событий.
/>Мне хотелось бы знать, действительно ли это это правильный подход, или я слишком усложняю свое решение. Каковы плюсы и минусы этого подхода?
Спасибо

Подробнее здесь: https://stackoverflow.com/questions/793 ... ngo-models
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»