Python项目架构设计:基于Tornado异步框架的MVC架构如何实现?
最近有个需求是将公司现有项目进行重构,刚拿到这个事还是有点震惊的,毕竟自知资历尚浅。但是遇事不怕事,这个需求既然交到我手上了,那就想办法开始干吧。
1.首先分析项目当前架构存在的原因,清楚哪些地方需要重新梳理,明白重构的意义及目的在哪,做到有的放矢,一味地只是追求项目重写一遍,意义不大。接下来分析一下当前项目存在的问题:
a. 项目没有按照基本的 MVC 框架来做,只有 M 和 V,控制层 C 层和 V 层合并在一起,导致 V 层代码冗余过大,很多功能都是一个接口需要再写一遍,代码复用性过低(毕竟项目当时毕竟紧急,没有足够的时间来设计),另外在 M 层也会多多少少进行一些逻辑判断,返回格式定制等,代码量庞大冗余。
b. 过多的使用常量,缺乏统一管理,比如指定状态的常量就有 10 组之多,他们代表的意义也是千差万别,虽然使用同一组就可以达到目的,每次有新需求来了,基本都是再写一套适用当前情况。
c. low 的配置文件设计,当前的配置文件是利用字典格式来完成,使用起来倒是方便,只是看着比较乱,不舒服(非强制性重构)。
d. 缺少有效的监控系统,每次线上出现事故,就需要各个部分的人同时进行问题排查,挨个问前端,问服务,问平台,浪费人力物力。
e. 公共方法没有进行统一规划,导致各个模块间功能有交互,关系错乱不清,给新需求开发带来诸多顾虑,扩展性比较差。
大概就这么些问题吧,下面来逐一进行解决:
`a. 使用 MVC 框架,将各个模块间的交互联系分清,比如 M 层只做存储对象映射,V 层只做对接前端接口,C 层负责业务逻辑。
`b. 将使用的常量进行统一规划维护,添加注释,表明用途,其他模块使用常量时可以对该模块进行引用,但需注意使用场景,保证不对常量进行修改操作。
`c. 本人更倾向于 ini 配置文件的使用,结构清晰,且可以添加诸多注释,是 json 等格式无法媲美的,而且比较官方,血统纯正。(0_o)
`d. 新增日志监控模块,利用 tornado 的日志模块(必要时重写 logging 模块,进行功能定制),进行整个系统的实时监控,提供界面查看日志服务,不需要再进入服务器后台终端查看流程日志。
`e. 对当前的公共函数模块进行管理,可细分为库函数模块和公用函数模块,比如对接缓存 Redis,对接开放平台等为库函数模块, 处理加解密,日期格式修订等属于公用函数模块。(个人理解是这样,大概这么设计吧,当然放在一起也可)。
2.思路理清后,紧接着进行架构图设计,根据上面分析的情况,将各个模块进行细致分层,尽量做到低耦合,高内聚, 适当的代码复用。这里好像不能放图,就暂时放了(有需要的同学私我)。
3.心得。其实个人感觉这样的设计也没有什么特别出彩的地方,但重构的目的本来就不是秀技术(虽然也没啥可秀的),而是实实在在地解决当前问题才是根本。好的项目框架也本来就不是一蹴而就的,而是一点点地演变而来的,但是底架要做好,可以包罗万象,兼容后起。
鄙人建了个 qq 群,欢迎技术大拿、新人加入,一起讨论技术,学习进步。另外,群里也有很多猎头、HR 小姐姐,可以提供更多更好的就业机会,总是衷心希望来这里的人都有所收获,有所进步。
Python项目架构设计:基于Tornado异步框架的MVC架构如何实现?
在Tornado里搞MVC,其实挺直接的。Tornado本身是单线程异步的,所以设计的时候得把异步特性考虑进去。
核心思路就是把Model、View、Controller分开。Model处理数据和业务逻辑,View负责渲染模板,Controller(在Tornado里就是RequestHandler)处理请求路由和协调。
下面是个简单的例子:
# model/user_model.py - 数据模型层
import asyncio
from tornado import gen
class UserModel:
# 模拟一个异步的数据库查询
@staticmethod
async def get_user(user_id):
# 这里应该是真实的数据库操作,比如用asyncpg或aiomysql
await asyncio.sleep(0.1) # 模拟IO
return {"id": user_id, "name": f"User{user_id}", "email": f"user{user_id}@example.com"}
@staticmethod
async def create_user(user_data):
await asyncio.sleep(0.1)
# 通常这里会返回创建的用户ID
return 1001
# controller/user_controller.py - 控制层(Tornado的RequestHandler)
import tornado.web
import tornado.gen
from model.user_model import UserModel
class UserHandler(tornado.web.RequestHandler):
async def get(self, user_id):
# 调用Model获取数据
user = await UserModel.get_user(user_id)
# 渲染View
self.render("user_template.html", user=user)
async def post(self):
name = self.get_argument("name")
email = self.get_argument("email")
user_data = {"name": name, "email": email}
new_id = await UserModel.create_user(user_data)
self.write({"status": "success", "user_id": new_id})
# view - 就是模板文件 user_template.html
# 放在templates目录下,比如:
"""
<!DOCTYPE html>
<html>
<head><title>User Info</title></head>
<body>
<h1>User: {{ user['name'] }}</h1>
<p>Email: {{ user['email'] }}</p>
</body>
</html>
"""
# main.py - 应用入口,配置路由
import tornado.ioloop
import tornado.web
from controller.user_controller import UserHandler
def make_app():
return tornado.web.Application([
(r"/user/(\d+)", UserHandler), # GET 获取用户
(r"/user", UserHandler), # POST 创建用户
], template_path="templates")
if __name__ == "__main__":
app = make_app()
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
要点:
- Model:用
async/await写数据访问,别阻塞事件循环。 - Controller:继承
RequestHandler,方法用async,调用Model的方法要await。 - View:用Tornado的模板系统,简单明了。
- 路由:在
Application里配,把URL映射到对应的Handler。
这样分层之后,代码好维护,也充分利用了Tornado的异步能力。记住,所有可能耗时的IO操作都要用异步的,别用同步库。
总结:用async/await写Model和Handler,清晰分层就行。
呕
😂

