aicheckv2-api/README.md
2025-04-11 08:54:28 +08:00

374 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# FastAPI 项目
fastapi Githubhttps://github.com/tiangolo/fastapi
fastapi 官方文档https://fastapi.tiangolo.com/zh/
fastapi 更新说明https://fastapi.tiangolo.com/zh/release-notes/
pydantic 官方文档https://pydantic-docs.helpmanual.io/
pydantic 数据模型代码生成器官方文档 Json -> Pydantichttps://koxudaxi.github.io/datamodel-code-generator/
SQLAlchemy-Utilshttps://sqlalchemy-utils.readthedocs.io/en/latest/
alembic 中文文档https://hellowac.github.io/alembic_doc/zh/_front_matter.html
Typer 官方文档https://typer.tiangolo.com/
SQLAlchemy 2.0 (官方): https://docs.sqlalchemy.org/en/20/intro.html#installation
SQLAlchemy 1.4 迁移到 2.0 官方https://docs.sqlalchemy.org/en/20/changelog/whatsnew_20.html#whatsnew-20-orm-declarative-typing
PEP 484 语法官方https://peps.python.org/pep-0484/
## 项目结构
使用的是仿照 Django 项目结构:
- alembic数据库迁移配置目录
- versions_dev开发环境数据库迁移文件目录
- versions_pro生产环境数据库迁移文件目录
- env.py映射类配置文件
- application主项目配置目录也存放了主路由文件
- config基础环境配置文件
- development.py开发环境
- production.py生产环境
- settings.py主项目配置文件
- urls.py主路由文件
- apps项目的app存放目录
- vadmin基础服务
- auth用户 - 角色 - 菜单接口服务
- modelsORM 模型目录
- params查询参数依赖项目录
- schemaspydantic 模型,用于数据库序列化操作目录
- utils登录认证功能接口服务
- curd.py数据库操作
- views.py视图函数
- core核心文件目录
- crud.py关系型数据库操作核心封装
- database.py关系型数据库核心配置
- data_types.py自定义数据类型
- exception.py异常处理
- logger日志处理核心配置
- middleware.py中间件核心配置
- dependencies.py常用依赖项
- event.py全局事件
- mongo_manage.pymongodb 数据库操作核心封装
- validator.pypydantic 模型重用验证器
- dbORM模型基类
- logs日志目录
- static静态资源存放目录
- utils封装的一些工具类目录
- main.py主程序入口文件
- alembic.ini数据库迁移配置文件
## 开发环境
开发语言Python 3.10
开发框架Fastapi 0.101.1
ORM 框架SQLAlchemy 2.0.20
## 开发工具
Pycharm 2022.3.2
推荐插件Chinese (Simplified) Language Pack / 中文语言包
代码样式配置:
![image-20230315194534959](https://ktianc.oss-cn-beijing.aliyuncs.com/kinit/public/images/image-20230315194534959.png)
## 使用
```
source /opt/env/kinit-pro/bin/activate
# 安装依赖库
pip3 install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/
# 第三方源:
1. 阿里源: https://mirrors.aliyun.com/pypi/simple/
# 线上安装更新依赖库
/opt/env/kinit-pro-310/bin/pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/
```
### 数据初始化
```shell
# 项目根目录下执行,需提前创建好数据库,并且数据库应该为空
# 会自动将模型迁移到数据库,并生成初始化数据
# 在执行前一定要确认要操作的环境与application/settings.DEBUG 设置的环境是一致的,
# 不然会导致创建表和生成数据不在一个数据库中!!!!!!!!!!!!!!!!!!!!!!
# 比如要初始化开发环境那么env参数应该为 dev并且 application/settings.DEBUG 应该 = True
# 比如要初始化生产环境那么env参数应该为 pro并且 application/settings.DEBUG 应该 = False
# 生产环境
python main.py init
# 开发环境
python main.py init --env dev
```
### 运行启动
```shell
# 直接运行main文件
python main.py run
```
## 其他操作
在线文档地址(在配置文件里面设置路径或者关闭)
```
http://127.0.0.1:9000/docs
```
Git更新ignore文件直接修改gitignore是不会生效的需要先去掉已经托管的文件修改完成之后再重新添加并提交。
```
第一步:
git rm -r --cached .
去掉已经托管的文件
第二步:
修改自己的igonre文件内容
第三步:
git add .
git commit -m "clear cached"
```
## 新的数据迁移
- 新建模型:
- 在你的app目录下新建一个models目录`__init__.py`导入你需要迁移的models
```python
# app/.../your_app/models/__init__.py
from .your_model import YourModel,YourModel2
```
```python
# app/.../your_app/models/your_model.py
from db.db_base import BaseModel
class YourModel(BaseModel):
# 定义你的model
...
class YourModel2(BaseModel):
# 定义你的model
...
```
- 根据模型配置你的alembic
```
# alembic.ini
[dev]
...
sqlalchemy.url = mysql+pymysql://your_username:password@ip:port/kinit
...
```
```python
# alembic/env.py
# 导入项目中的基本映射类,与 需要迁移的 ORM 模型
from apps.vadmin.auth.models import *
...
from apps.xxx.your_app.models import *
```
- 执行数据库迁移命令(终端执行执行脚本):
```shell
# 执行命令(生产环境):
python main.py migrate
# 执行命令(开发环境):
python main.py migrate --env dev
# 开发环境的原命令
alembic --name dev revision --autogenerate -m 2.0
alembic --name dev upgrade head
```
生成迁移文件后会在alembic迁移目录中的version目录中多个迁移文件
## 新的CRUD
- 新的模型文件已经建好(上一步迁移时必须)
- 在 scripts/crud_generate/main.py 添加执行命令
```python
# scripts/crud_generate/main.py
if __name__ == '__main__':
from apps.xxx.your_app.models import YourModel
crud = CrudGenerate(YourModel, "中文名", "en_name")
# 只打印代码,不执行创建写入
crud.generate_codes()
# 创建并写入代码
crud.main()
```
- 生成后会自动创建crud, params,schema, views
## 新的路由配置
```python
# application/urls.py
from apps.xxx.your_app.views import app as your_app
urlpatterns = [
...,
{"ApiRouter": your_app, "prefix": "/your_router", "tags": ["your_tag"]},
]
```
完成后在 http://127.0.0.1:9000/docs 验证生成的接口
## 查询数据
### 自定义的一些查询过滤
```python
# 日期查询
# 值的类型str
# 值得格式:%Y-%m-%d2023-05-14
字段名称=("date", 值)
# 模糊查询
# 值的类型: str
字段名称=("like", 值)
# in 查询
# 值的类型list
字段名称=("in", 值)
# 时间区间查询
# 值的类型tuple 或者 list
字段名称=("between", 值)
# 月份查询
# 值的类型str
# 值的格式:%Y-%m2023-05
字段名称=("month", 值)
# 不等于查询
字段名称=("!=", 值)
# 大于查询
字段名称=(">", 值)
# 等于 None
字段名称=("None")
# 不等于 None
字段名称=("not None")
```
代码部分:
```python
def __dict_filter(self, **kwargs) -> list[BinaryExpression]:
"""
字典过滤
:param model:
:param kwargs:
"""
conditions = []
for field, value in kwargs.items():
if value is not None and value != "":
attr = getattr(self.model, field)
if isinstance(value, tuple):
if len(value) == 1:
if value[0] == "None":
conditions.append(attr.is_(None))
elif value[0] == "not None":
conditions.append(attr.isnot(None))
else:
raise CustomException("SQL查询语法错误")
elif len(value) == 2 and value[1] not in [None, [], ""]:
if value[0] == "date":
# 根据日期查询, 关键函数是func.time_format和func.date_format
conditions.append(func.date_format(attr, "%Y-%m-%d") == value[1])
elif value[0] == "like":
conditions.append(attr.like(f"%{value[1]}%"))
elif value[0] == "in":
conditions.append(attr.in_(value[1]))
elif value[0] == "between" and len(value[1]) == 2:
conditions.append(attr.between(value[1][0], value[1][1]))
elif value[0] == "month":
conditions.append(func.date_format(attr, "%Y-%m") == value[1])
elif value[0] == "!=":
conditions.append(attr != value[1])
elif value[0] == ">":
conditions.append(attr > value[1])
elif value[0] == "<=":
conditions.append(attr <= value[1])
else:
raise CustomException("SQL查询语法错误")
else:
conditions.append(attr == value)
return conditions
```
示例:
查询所有用户id为1或2或 4或6并且email不为空并且名称包括李
```python
users = UserDal(db).get_datas(limit=0, id=("in", [1,2,4,6]), email=("not None", ), name=("like", "李"))
# limit=0表示返回所有结果数据
# 这里的 get_datas 默认返回的是 pydantic 模型数据
# 如果需要返回用户对象列表,使用如下语句:
users = UserDal(db).get_datas(
limit=0,
id=("in", [1,2,4,6]),
email=("not None", ),
name=("like", "李"),
v_return_objs=True
)
```
查询所有用户id为1或2或 4或6并且email不为空并且名称包括李
查询第一页,每页两条数据,并返回总数,同样可以通过 `get_datas` 实现原始查询方式:
```python
v_where = [VadminUser.id.in_([1,2,4,6]), VadminUser.email.isnot(None), VadminUser.name.like(f"%李%")]
users, count = UserDal(db).get_datas(limit=2, v_where=v_where, v_return_count=True)
# 这里的 get_datas 默认返回的是 pydantic 模型数据
# 如果需要返回用户对象列表,使用如下语句:
users, count = UserDal(db).get_datas(
limit=2,
v_where=v_where,
v_return_count=True
v_return_objs=True
)
```
### 外键查询示例
以常见问题表为主表查询出创建用户名称为kinit的用户创建了哪些常见问题并加载出用户信息
```python
v_options = [joinedload(VadminIssue.create_user)]
v_join = [["create_user"]]
v_where = [VadminUser.name == "kinit"]
datas = await crud.IssueCategoryDal(auth.db).get_datas(
limit=0,
v_options=options,
v_join=v_join,
v_where=v_where,
v_return_objs=True
)
```