django - Django Rest 框架应用程序中的关注点分离/DI
问题描述
我正在尝试在我的 Django 应用程序中创建更多与端点的关注点分离,但不确定如何实现服务层。我已经阅读了一篇关于这个主题的流行 python 文章,但它似乎没有回答测试问题。
例如,如果我有一个保存用户的请求,并且想在保存用户后发送电子邮件,那么通过覆盖保存来处理这个逻辑是很流行的,如下所示:
**models.py**
class User(AbstractBaseUser, PermissionsMixin):
...
def save(self, *args, **kwargs):
if self._state.adding:
user.activate_user(user=self)
super(User, self).save(*args, **kwargs)
**services.py**
from services import iNotificationService
...
def activate_user(user):
user.active = True
iNotificationService().send_message(user)
在上面的示例中,iNotificationService 将是应用程序可以在运行时选择的接口。如果此用户保存在生产环境中,应用程序将提供类似以下的类
import mandrill
class EmailClient(iNotificationService)
def send_message(user):
message = create_message(user)
mandrill.send_email(message)
进入 services.py 模块,以便发送电子邮件。但如果应用程序在测试环境中运行,测试将通过发送接口实例来模拟 EmailClient,因此实际上不会发送电子邮件:
class iNotificationService(object)
def send_message(user)
pass
我想知道的是如何将实例提供给 services.py 模块,以便 activate_user 知道要发送哪种类型的通知。我唯一的想法是将一些参数传递给 save 方法,以便它知道要使用哪种类型的通知。但我想知道考虑到人们可能使用服务的不同地方,该解决方案的可扩展性如何。
解决方案
如果通知提供程序类的更改仅取决于您正在运行应用程序的环境(测试/开发/生产等)(正如您所提到的),我建议您通过设置为您的应用程序提供通知类。我个人使用这种模式,并且在很多项目中都看到过,发现它非常有用。
假设您有一个包含所有通知提供程序类的通知模块的服务包。像这样。
services
__init__.py
notifications.py
iNotificationService
EmailClient
settings.py
在文件中添加通知提供程序类路径。
设置.py
...
# this value can be changed / overridden based on environment.
# pragmatically or statically.
NOTIFICATION_PROVIDER = 'services.notifications.iNotificationService'
...
服务/__init__.py
from django.conf import settings
from django.utils.module_loading import import_string
def get_notification_provider(*args, **kwargs):
try:
notification_class = import_string(settings.NOTIFICATION_PROVIDER)
except ImportError as e:
raise ImproperlyConfigured('Error loading notification provider: %s' % e)
return notification_class(*args, **kwargs)
现在您可以从服务包中导入get_notification_provider
并在您的应用程序中使用它来根据您的设置获取通知类的实例。您可以根据您的需要/环境在设置中插入不同的提供程序。
推荐阅读
- javascript - 是否可以将删除/放置请求发送到 Azure AD 安全 api 或使用 aadHttpClientFactory 将 jwt 令牌作为字符串获取
- python - 使用opencv的对象计数软件
- r - 将文本距离输出添加到 ggplot2 geom_step() 函数
- node.js - NodeJS keycloak 获取用户信息
- android - 获取空当前位置
- sql - 尝试将 mysql 模型中的表与我的数据库同步,但出现此错误
- java - 我必须做一个“猜下一张牌更高”的游戏。但找不到问题
- python - 在不使用 Dataproc 的情况下将 GCP 与 PySpark 连接
- gurobi - 有没有办法将多个 MIP 启动传递给 Gurobi?
- go - 当我将 go mod 添加到我的项目时,无法运行它,我该如何解决?