如何设置3层Web应用程序项目

时间:2013-09-19 08:58:14

标签: python design-patterns model-view-controller orm sqlalchemy

编辑:

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

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


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


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

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

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

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

我们得出结论,两种方法都可行,并且两者都有利有弊:

方法1:

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

方法2:

  • 似乎与Django在Python中的工作方式一致
  • 允许简单访问方法:当存在模型实例时,任何函数都可以 可以立即调用perform。 (在我的例子中:当我有一个可用的字母实例时,我可以直接在其上调用一个为该字母生成HTML的方法)
  • 你可以传递实例,掌握所有适当的方法。

1 个答案:

答案 0 :(得分:1)

通常,您使用MVC模式来处理这类内容,但是python中的大多数Web框架已经删除了" Controller"因为他们认为这是一个不必要的组成部分。在我的发展中,我已经意识到,这有点真实:我可以没有它。这将为您留下两层:视图和模型。

问题是现在放置业务逻辑的位置。从实际意义上讲,有两种方法可以做到这一点,至少有两种方式可以解决逻辑:

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

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

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

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

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

我们假设您有一些数据并希望将其写入信件中。例如,您有一个articlescostumer的列表,他们购买了这些文章。在这种情况下,您已经拥有了数据。在将其传递给模板之前可能需要完成的唯一事情是重新格式化模板以便模板可以轻松使用它。例如,可能希望订购所购买的物品,例如通过金额,价格或物品编号。这是独立于模型的东西,现在订单只显示相关(您可以指定数据库查询中已有的订单,但让我们假设您没有)。在这种情况下,这是您的视图将执行的操作,因此您的模板已准备好格式化的数据以供显示。

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

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

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

所以我比我想要的时间更长,但我想向你提供一些例子,因为这是我开始时错过的,并通过反复试验找出了这些东西。