2

编辑:

我添加了 [MVC] 和 [design-patterns] 标签来扩大这个问题的受众,因为它更像是一个通用的编程问题,而不是与 Python 或 SQLalchemy 直接相关的问题。它适用于所有具有业务逻辑和 ORM 的应用程序。
基本问题是将业务逻辑保留在单独的模块中,还是将其添加到我们的 ORM 提供的类中更好:

我们有一个烧瓶/sqlalchemy 项目,我们必须为其设置一个结构来工作。关于如何设置有两个有效的意见,在项目真正开始之前,我们想下定决心之一他们。
如果你们中的任何人能给我们一些关于这两者中哪一个更有意义以及为什么以及优点/缺点是什么的见解,我们将不胜感激。


我的示例是需要批量发送和/或显示给单个用户的 HTML 信件。信件可以有部分显示发票和/或收件人的用户的文章列表。


方法 1:
将代码分成 3 层 - 第 1 层:Web 界面,第 2 层:处理字母,第 3 层:来自 ORM(sqlalchemy)的模型。
该网站将在第二层的一个类中调用服务器端方法,第二层将遍历需要获取此信函的用户,并且它将具有生成 HTML 并替换信函中的一些通用字段的内部方法,当前用户的信息。它还具有生成发票或要放在信中的文章列表的内部方法。

在这种方法中,第 3 层仅用于从数据库中获取数据,可能还有一些与数据库相关的逻辑,例如从用户的名字和姓氏生成全名。第二层执行大部分工作

方法2: 将代码拆分为相同的三层,但仅通过第二层中的用户集合执行循环。

生成 HTML、发票和文章列表的方法都作为方法添加到 ORM 提供的第 3 层中的模型定义中。第二层执行循环,但实际功能包含在第三层的模型类中

我们得出的结论是,这两种方法都可以奏效,并且各有利弊:

方法一:

  • 将业务逻辑与数据库访问完全分离
  • 防止导入 ORM 模型同时导入许多我们可能不需要的方法/功能,同时使模型类的代码更紧凑。
  • 在模拟 ORM 模型进行测试时可能更容易使用

方法二:

  • 似乎符合 Django 在 Python 中做事的方式
  • 允许对方法的简单访问:当模型实例存在时,可以立即调用它执行的任何函数。(在我的例子中:当我有一个可用的字母实例时,我可以直接调用一个方法来生成该字母的 HTML)
  • 您可以传递实例,手头有所有适当的方法。
4

1 回答 1

1

通常,您将MVC模式用于此类内容,但大多数 Python 中的 Web 框架都删除了“控制器”部分,因为他们认为这是一个不必要的组件。在我的发展过程中,我意识到这在某种程度上是正确的:没有它我也可以生活。这会给你留下两层:视图和模型。

问题是现在将业务逻辑放在哪里。从实际意义上讲,有两种方法可以做到这一点,至少有两种方法让我遇到了将逻辑放在哪里的问题:

  • 创建处理逻辑的特殊内部视图方法,这可能在多个视图中都需要,例如_process_list_data
  • 创建与模型相关的函数,但不直接绑定到相应模型模块内的单个实例,例如check_login.

详细说明:我将第一个用于严格显示相关的方法,即它们以某种方式关注处理数据以用于显示目的。我上面的示例,_process_list_data位于视图类中(按目的对方法进行分组),但也可以是模块中的普通函数。它接收一些参数,例如数据列表并以某种方式对其进行格式化(例如,它可能会添加额外的视图参数,以便模板可以有更少的逻辑)。然后它将数据集返回给原始视图函数,该函数可以将其传递或进一步处理。

第二个用于大多数其他逻辑,我不想直接查看代码以便于测试。我的例子是check_login:它是一个不直接绑定到显示输出的函数,因为它的目的是检查用户登录凭据并决定返回用户或报告登录失败(通过抛出异常,返回False或返回None) . 但是,此功能也不直接与模型相关联,因此它不能存在于 ORM 类中(它可能是staticmethod对象的一个User​​)。相反,它只是模块内的一个函数(请记住,这是 Python,您应该使用最简单的方法,并且函数可以用来做某事)

总结一下:在视图中显示逻辑,模型中的所有其他内容,因为大多数逻辑都以某种方式与特定模型相关联。如果不是,则为这种逻辑创建一个新模块或包。这可能是一个单独的模块,甚至是一个包。例如,我经常util为辅助函数创建一个模块/包,它们不直接与任何视图、模型或其他函数相关联,例如一个格式化从模板调用但包含太多 python 的日期的函数可能会很难看在模板中定义。

现在我们将这个逻辑带到您的任务中:处理/创建字母。由于我不知道具体需要做什么处理,所以只能根据自己的假设给出一般性的建议。

假设您有一些数据并想将其放入一封信中。因此,例如,您有一个列表articles以及costumer购买这些文章的人。在这种情况下,您已经拥有数据。在将其传递给模板之前可能需要做的唯一一件事就是重新格式化它,以便模板可以轻松使用它。例如,可能希望订购购买的物品,例如按数量、价格或物品编号。这是独立于模型的东西,订单现在只与显示相关(您可以在数据库查询中指定订单,但假设您没有)。在这种情况下,这是您的视图将执行的操作,因此您的模板已准备好格式化以显示的数据。

现在假设您想要获取数据来创建一个特定的字母,例如用户随时间购买的文章列表,以及购买日期和其他详细信息。这将是模型的工作,例如创建查询、获取数据并确保它具有此特定任务所需的所有属性。

假设在这两种情况下,您都可以检索产品的价格,并且该价格由基值和基于其他属性的一些百分比确定:这作为模型方法是有意义的,因为它在单个产品或订单实例上运行. 然后,您将模型传递给模板并在其中调用 price 方法。但是您不妨以这样的方式重新格式化它,即调用已经在视图中进行,并且模板只获取元组或字典。这将更容易将相同的数据作为 API 传递出去(见下文),但它可能不一定是最简单/最好的方式。

这个决定的一个好规则是问自己如果我要在标准视图之外提供 JSON API,我需要如何修改我的代码以尽可能 DRY?. 如果一开始理论还不够,请为模板构建一些 API,然后查看需要在哪些地方更改 API,这在视图本身旁边是有意义的。你可能永远不会使用这个 API,所以它不需要完美,但它可以帮助你弄清楚如何构建你的代码。但是,正如您在上面看到的,这并不一定意味着您应该以只返回可以转换为 JSON 的内容的方式对数据进行预处理,而是您可能希望为 API 制作一些 JSON 特定格式看法。

所以我比我预期的要长一点,但我想为你提供一些例子,因为这是我开始并通过反复试验发现这些事情时错过的。

于 2013-09-20T10:29:53.140 回答