V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
metavoidx
V2EX  ›  Python

写了一个 Python 后端元框架: UtilMeta

  •  1
     
  •   metavoidx ·
    voidZXL · 311 天前 · 2394 次点击
    这是一个创建于 311 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近开源了一个我写了几年的后端元框架:UtilMeta ,它可以基于 Python 的类型注解标准高效开发 RESTful 接口和实现 CRUD (支持 Django ORM ),能够自动解析请求参数与生成 OpenAPI 文档,产出的代码简洁清晰,并且支持使用主流 Python 框架( Django, Flask, Fastapi, Starlette, Sanic, Tornado 等)作为运行时实现或渐进式整合

    Github: https://github.com/utilmeta/utilmeta-py

    官网: https://utilmeta.com/zh

    欢迎大家来体验~(觉得项目不错也可以赏个 star 🥰) 有任何问题也可联系我。我的全网 ID 和微信号都是 voidZXL

    5 条回复    2024-02-26 18:26:04 +08:00
    tikazyq
        1
    tikazyq  
       311 天前
    FastAPI 用 Pydantic 也可以生成 Redoc 类似 OpenAPI 文档的,感觉你这个框架更多的是为了兼容 Django 、Flask 之类的老项目吧?
    metavoidx
        2
    metavoidx  
    OP
       311 天前
    @tikazyq 感谢回复~ FastAPI 确实可以生成 OpenAPI 文档(这大概已经是现代 API 框架的标配了),但它自身对 RESTful CRUD 的能力支持有限,比较依赖生态,比如实现一个 Realworld 博客项目,UtilMeta 的实现( https://github.com/utilmeta/utilmeta-py-realworld-example-app )只需要 600+ 行代码,FastAPI 的实现( https://github.com/nsidnev/fastapi-realworld-example-app )需要 2500+ 行代码

    所以我写 UtilMeta 一方面是方便现有的 Django, Flask 等项目进行平滑迁移,另一方面新项目也可以快速用它开发 RESTful 接口(目前全面支持 Django ORM 语法,后续也会支持其他主流 ORM 库),后面也会上线一个对应 API 管理平台( https://utilmeta.com/zh )实现 Python 后端项目的接口调试,日志查询等监控管理功能,所以会把 UtilMeta 做成了一个兼容 Python 主流框架的元框架
    tangkikodo
        3
    tangkikodo  
       307 天前
    hi, 我是 pydantic-resolve 作者(也是那篇 composition oriented development pattern 的作者) , 在声明式描述数据这点上我很赞同你的观点, 我观点上的一些分歧在于是否应该和 ORM 关联的紧密,下面是我的解释。

    首先,既然用申明方式来生成数据, 目的肯定是为了更加优雅的组合数据

    一般来说, 后端生成一个前端直接可用的视图数据包括几个步骤。
    1. 数据获取
    2. 数据组装 (utilmeta 把 1 ,2 两个环节一次性解决了)
    3. 面向业务进行转换 这么几个步骤。

    (一般情况下 2 ,3 可能会混在一起)

    我选择使用 dataloader 的原因是:

    通过 ORM 获取关联数据的手段之一,这个行为如果用通用的描述来说的话, 类似于:

    def batch_query(keys, filters) 然后把查询结果绑定回每一条父记录。

    这样在一对多查找的时候,既能使用外键, 还能指定额外过滤条件
    https://github.com/allmonday/composition-oriented-development-pattern/blob/master/src/router/sample_2/readme-cn.md

    ( ORM relationship 上添加额外条件的查询写起来通常都会比较繁杂)

    也就是说,loader 的内部实现可能是一段查询, 也可能是一个 rpc , 也可能是缓存查询 等等

    这样做的好处是隔离了具体实现, 假如我要做服务拆分的话, 就能将封装的查询,转成一个 rpc 调用了。

    关于 3 , 数据转换, 这也是直接从 ORM 拼装数据可能存在的一个小问题, 如果视图数据需要对视图数据的中间, 或者底层的数据做些转换, 聚合计算之类的功能, 很多时候就不得不拆开来遍历计算了。

    pydantic-resolve 的思路是选择使用 post_method 来在每层提供一个 after resolved hook 来操作数据。 用来处理层级聚合, 字段转换会比较方便, 也符合声明式的风格。
    https://github.com/allmonday/composition-oriented-development-pattern/blob/master/src/router/sample_4/readme-cn.md

    说了一些拙见,框架本身是服务于特定目的,

    utilmeta 这样的申明式方法带来了很好的灵活性和使用便利。

    而且被你详细的文档和丰富的 example 给震撼到了!

    祝蒸蒸日上
    metavoidx
        4
    metavoidx  
    OP
       305 天前
    @tangkikodo 非常感谢支持,文档确实肝了挺长时间的哈哈~ 之前就在 Github 上看到过你的分享,印象深刻,我们优化和解决问题的大方向是一致的,不过我确实把 orm.Schema 类从设计上直接和一个 ORM model 进行绑定了,目前支持了 Django 的 model ,未来也会支持 SQLAlchemy 等其他主流 ORM 库的 model ,我其实是实现了一个 ORM adaptor ,把常用的查询操作进行抽象,然后提供给 orm.Schema 调用的
    https://github.com/utilmeta/utilmeta-py/tree/main/utilmeta/core/orm/backends

    这样确实没有办法完美覆盖 100% 的情况,但也足以简单轻松地应对 95% 的 CRUD 情况了,因为大部分用户也只是在一些主流的 ORM 模型上编写 RESTful 接口,只要把普通字段,关系对象(外键,多对,级联),表达式(计数/求和/平均等)这些常用的字段进行(带一定配置参数的)标准化实现就可以适用于绝大多数场景了,剩下的复杂场景可以一事一议,让用户自行在函数中编写查询逻辑组合拼接,因为任何框架都不可能处理所有问题,所以肯定要留出这样的自由度

    “如果视图数据需要对视图数据的中间, 或者底层的数据做些转换, 聚合计算之类的功能”:
    因为 orm.Schema 的方法调用的数据也并非一定是最终的 API 返回结果,用户可以把它作为一个期望明确的 “标准化” 数据源,通过声明返回自己需要的任意结构的合法数据,之后可以在函数中或者 Schema 类的 @property 属性中进行聚合计算和后处理工作
    https://docs.utilmeta.com/py/zh/guide/schema-query/#property

    因为我是尽可能希望用 Python 的原生语法和规范来定义声明式语法,尽量减少专有概念或语法的引入,不太希望规定太多的参数或者方法名,也是希望能减轻用户的学习成本和心智负担,一眼就能看明白框架代码的含义和作用

    当然这也只是我设计哲学上的拙见

    祝好~ 望多交流
    tangkikodo
        5
    tangkikodo  
       305 天前
    @metavoidx
    同意的, 我其实因为是个 sqlalchemy 苦手, 感觉配置 relationship 之类的太繁琐了,就刻意从这层脱身出来 囧
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   985 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 20:00 · PVG 04:00 · LAX 12:00 · JFK 15:00
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.