最近做的这个项目大量使用了 python 及其相关的生态,因此自然而然选择了我的 DjangoStarter 作为后端框架
之前 v2 版本是用 RestFramework 做接口的,后面我试用了一次 django-ninja 之后就喜欢这种类似 FastApi 的写接口方式
正所谓天下苦 drf 久矣,在新的 v3 版本框架中,我决定直接把整个 RestFramework 替换成 ninja
目前大部分功能都完成了,代码在主项目的 v3-alpha 分支里,等开发完成我会合并到 master 里 (现在基本可用了)
另外还做了很多新功能和改进,接下来会介绍一下
这个开发脚手架,最开始还是叫 DjangoRails ,名字模仿的 Ruby on Rails
后面经过重构才改成 DjangoStarter
这个脚手架起源于2020年开始的项目,当时使用 Django + RestFramework 作为后端框架,为了满足安全部门的要求,又做了很多魔改,再加上其他一些配置啥的,慢慢的就积累出了 DjangoStarter ~
这里贴一下项目介绍吧~
DjangoStarter v3 是下一代 Django 项目快速开发模板,专为提升开发效率和性能而设计。
结合了 Django 的丰富功能和 Django-Ninja 的性能、灵活、简洁特性,v3 版本旨在为开发者提供一个更加强大、简洁和高速的开发体验。
通过这个全新的框架版本,开发者能够迅速搭建起符合现代 web 应用标准的项目基础架构。
OK,终于说回正题
这次重构v3版本最主要的原因是把 RestFramework 替换成 ninja
然后也做了一些新的功能
比如:
目前大概就这些吧
后面有用到什么新的再一步步加入
一直没有好好介绍一下 DjangoStarter 框架的具体实现
代码生成这块其实也不复杂,包名是 django_starter.contrib.code_generator
主要就两个部分
src/django_starter/contrib/code_generator/analyzer.py
src/django_starter/contrib/code_generator/generator.py
分析器使用 django.apps.apps
提供的 get_app_config
和 get_models
来扫描已注册的所有 App
然后搭配反射(或者在 Python 中应该叫自省 inspect)来获取各个字段的信息,把搜集到的信息保存到我定义的几个对象中
然后在生成器部分,根据特定的规则,使用 jinja2 模板进行渲染~
注意要把字段的 primary_key
, is_relation
这些属性拿出来,后面有用。如果是关系字段(如外键)的话,还需要把 target_field
拿出来。
大概思路就是这样,其中有很多细节的地方,本文的篇幅受限,后续我写篇文章来介绍吧。
使用 ninja 来写 API
不同于之前的 RestFramework ,ninja 用的是装饰器来定义路径,这个对于不喜欢 Django 配置式路由的人来说很友好
项目结构我也做了一些调整
以 demo 应用为例
每个 model 都在 apis 下单独创建一个 package,单独有 apis.py 和 schemas.py 代码,这样不会把所有代码逻辑混在一起
PS:后续如果我转向使用 FastApi,也可以用这个思路来组织项目
demo
├─ tests
│ ├─ __init__.py
│ ├─ test_music_album.py
│ ├─ test_music.py
│ ├─ test_movie.py
│ └─ test_actor.py
├─ migrations
│ ├─ __init__.py
│ └─ 0001_initial.py
├─ apis
│ ├─ music_album
│ │ ├─ __init__.py
│ │ ├─ schemas.py
│ │ └─ apis.py
│ ├─ music
│ │ ├─ __init__.py
│ │ ├─ schemas.py
│ │ └─ apis.py
│ ├─ movie
│ │ ├─ __init__.py
│ │ ├─ schemas.py
│ │ └─ apis.py
│ ├─ actor
│ │ ├─ __init__.py
│ │ ├─ schemas.py
│ │ └─ apis.py
│ └─ __init__.py
├─ __init__.py
├─ views.py
├─ models.py
├─ apps.py
└─ admin.py
要说的话,ninja 这种比较新的库,还是有一点点坑的地方的
NinjaAPI
对象配置 urls_namespace
,下面的各级 router 都不能配置 urls_namespace
,我只能对下面的接口用 url_name='demo/movie/list'
这种形式的命名这个可以叫 seed data ,也可以叫 mock data
在开发测试中很有用,不用手动去添加各种数据
包名是 django_starter.contrib.seed
一开始我是找到了一个叫 django-seed 的库,可以实现种子数据的生成
不过这个包已经年久失修,好几年没更新了
我试了一下,运行起来居然还依赖 PostgreSql 的库?!
就离谱,不应该和数据库无关的吗……
算了,我自己写得了,又不难
Python 生态就是好,Faker 库用来生成随机假数据很好用
主要代码在 src/django_starter/contrib/seed/seeder.py
文件里
就是根据不同的字段类型,使用不同的假数据方法
其中外键字段会比较坑,需要做一些特殊处理
related_model = field.related_model
# Ensure there is at least one instance of the related model
related_instance = related_model.objects.order_by('?').first()
if not related_instance:
related_instance = related_model.objects.create(**self.seed(related_model))
# Set the foreign key ID field
fake_data[field.attname] = related_instance.pk
早就对 Django 的配置 settings.py 不爽了
项目一大,这个文件就乱七八糟又臭又长
而且还不支持多环境切换,得自己写一堆逻辑去判断不同环境
之前版本中,我是把几个主要的配置拆分成不同文件,然后在 settings.py
里引用
现在我用上了 django-split-settings 这个包,瞬间舒服了
来看看现在的 config 目录
config
├─ settings
│ ├─ environments
│ │ ├─ __init__.py
│ │ ├─ testing.py
│ │ ├─ production.py
│ │ ├─ local.py.template
│ │ └─ development.py
│ ├─ components
│ │ ├─ __init__.py
│ │ ├─ simpleui.py
│ │ ├─ rq.py
│ │ ├─ ninja.py
│ │ ├─ logging.py
│ │ ├─ django_starter.py
│ │ ├─ database.py
│ │ ├─ csp.py
│ │ ├─ cors.py
│ │ ├─ common.py
│ │ ├─ captcha.py
│ │ └─ caches.py
│ └─ __init__.py
├─ __init__.py
├─ wsgi.py
├─ urls_root.py
├─ urls.py
├─ env_init.py
├─ asgi.py
└─ apis.py
可以看到现在 settings 变成了一个 package
各种配置拆分出来分散到 components 下面
然后不同的环境又放到 environments 下面,可以覆盖前面定义的配置
很好的解决了之前的几个痛点
原本就直接使用 pip ,搭配 requirements.txt 来管理依赖
这个方式的优缺点我就不多说了
这次换成 pdm ,总算有点现代包管理器的感觉了
PS:其实我之前还用过 poetry ,不过偶尔会遇到一些奇奇怪怪的问题,弃了~
大概就这些吧,后面有什么新的想法我再来更新
还有其中几个关键的更新我可能会单独写文章来详细介绍~