大(ish)django应用程序架构

时间:2015-04-09 12:09:33

标签: python django

如何正确构建更大的django网站,以保持可测试性和可维护性?

在最好的django精神(我希望)中,我们开始时并没有过多关注我们网站不同部分之间的脱钩。我们确实将它分成不同的应用程序,但这些应用程序通过共同使用模型类和直接方法调用而直接相互依赖。

这变得非常纠结。例如,我们的一个操作/服务如下所示:

def do_apply_for_flat(user, flat, bid_amount):
    assert can_apply(user, flat)
    application = Application.objects.create(
        user=user, flat=flat, amount=bid_amount,
        status=Application.STATUS_ACTIVE)

    events.logger.application_added(application)
    mails.send_applicant_application_added(application)
    mails.send_lessor_application_received(application)
    return application

该功能不仅执行实际的业务流程,而且还处理事件记录并向相关用户发送邮件。我不认为这种方法本质上存在错误。然而,正确地推理代码甚至测试应用程序变得越来越困难,因为它越来越难以在智能和编程上分离部分。

所以,我的问题是,大男孩如何构建他们的应用程序:

  1. 可以单独测试应用程序的不同部分
  2. 仅通过启用特定测试所需的部件来快速进行测试
  3. 代码耦合减少
  4. 我对这个问题的看法是在单个django应用程序可能发布或订阅的时候引入一个集中式信号集线器(只是一个单个python文件中的一些django信号)。上面的示例函数将发布一个application_added事件,邮件和事件应用程序将监听该事件。然后,为了进行有效的测试,我会断开我不需要的部分。这也大大增加了解耦,因为服务根本不需要知道发送邮件。

    但是,我不确定,因此对这类问题的公认实践非常感兴趣。

3 个答案:

答案 0 :(得分:2)

对于测试,您应该模拟您的依赖项。例如,应在视图的单元测试期间模拟日志记录和邮件组件。我通常会使用python-mock,这样可以独立于日志记录和邮件组件测试您的视图,反之亦然。断言您的视图正在调用正确的服务调用并模拟服务调用的返回值/副作用。

进行测试时,您还应该避免触摸数据库。相反,尝试尽可能多地使用内存对象,而不是Application.objects.create(),将save()推迟到调用者,这样您就可以测试服务,而无需在数据库中实际拥有应用程序。或者,修补save()方法,因此它实际上不会保存,但这更加乏味。

答案 1 :(得分:1)

将应用的某些部分转移到不同的微服务中。这将使您的应用的某些部分专注于正确地做一两件事(例如事件记录,电子邮件)。代码耦合也减少了,站点的不同部分也可以单独测试。

  

微服务架构风格涉及将单个应用程序开发为通常通过API进行通信的较小服务的集合。

您可能需要使用像Flask这样的小型框架。

<强>资源:

有关微服务的更多信息,请点击此处:

http://martinfowler.com/articles/microservices.html
http://aurelavramescu.blogspot.com/2014/06/user-microservice-python-way.html

答案 2 :(得分:0)

首先,尝试将您的大任务降级为较小的类。用通常的方法调用或Django信号连接它们。

如果您认为子任务足够独立,您可以在同一个项目中将它们实现为多个Django应用程序。请参阅Django tutorial,其中描述了应用程序和项目之间的关系。