sysom1/environment/1_sdk/sysom_utils/README.md

218 lines
7.8 KiB
Markdown
Raw Permalink 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.

# SysOM 框架 SDK
## 1. 框架基础能力
## 2. `fastapi_helper`
`fastapi_helper` 对使用 fastapi 编写微服务的一些常用操作进行了封装,可以提供如下开箱即用的能力:
- 查询辅助(支持分页、排序、按字段过滤等等)
- 响应辅助(支持快速返回标准 JSON 格式的响应数据)
### 2.1 查询辅助
由于 fastapi 框架下面并没有类似 Django REST Framework 这种开箱即用的支持分页、排序、过滤的封装,因此想要快速实现支持分页、排序、过滤的数据查询代码需要不少额外的工作,因此本节设计了 `BaseQueryParams` 辅助查询类,可以用于快速实现列表查询。使用示例如下:
#### 2.1.1 基础使用
```python
#######################################################################################
# model.py
#######################################################################################
from sqlalchemy import Column, Integer, String, DateTime
from sqlalchemy.sql import func
from app.database import Base
class Person(Base):
__tablename__ = "sys_person"
id = Column(Integer, primary_key=True)
name = Column(String(254), unique=True)
age = Column(Integer)
created_at = Column(DateTime(timezone=True), server_default=func.now())
#######################################################################################
# schemas.py
#######################################################################################
from pydantic import BaseModel
from datetime import datetime
class Person(BaseModel):
id: int
name: str
age: int
created_at: datetime
class Config:
orm_mode = True
#######################################################################################
# query.py
#######################################################################################
from typing import Optional
from app import models
from sysom_utils import BaseQueryParams
class QueryParams(BaseQueryParams):
# 1. 指定要查询的模型(数据库模型)
__modelclass__ = models.Person
# 2. 定义排序字段(这边定义按创建时间降序,如果期望按时间升序,直接使用 "created_at" 即可)
sort: str = "-created_at"
# 3. 定义支持用于过滤的参数
# - 支持在query参数里面使用 name=A 过滤名字为A的用户;
# - 需要过滤出多个用户可以用逗号连接,比如 name=A,B
# - Optional 表示这个过滤字段是可选的,不传不过滤
name: Optional[str] = None
# - 支持在query参数里面使用 age=18 过滤年龄为18的用户;
# - 需要过滤出多个年龄的用户可以用逗号连接,比如 name=18,28
# - Optional 表示这个过滤字段是可选的,不传不过滤
age: Optional[str] = None
#######################################################################################
# crud.py
#######################################################################################
from typing import Optional, List
from sqlalchemy.orm import Session
from app import models, schemas, query
def get_person_list(db: Session, query_params: query.PersonQueryParams) -> List[models.Person]:
return (
query_params.get_query_exp(db)
.all()
)
#######################################################################################
# routes/person.py
#######################################################################################
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
from app.query import PersonQueryParams
from app.database import get_db
from app.crud import get_person_list
from app.schemas import Person
from sysom_utils import StandardListResponse
router = APIRouter()
@router.get("/list")
async def get_persons(
query_params: PersonQueryParams = Depends(), db: Session = Depends(get_db)
):
person_list = get_person_list(db, query_params)
return StandardListResponse(person_list, schema_class=Person)
```
#### 2.1.1 查询列表的同时获取条目总数
查询数据列表时,通常会设置过滤条件、排序、分页,获取总的数据数量应该是过滤之后的数量,此时可以通过如下方式同时获取到数据列表和总数:
```python
#######################################################################################
# crud.py
#######################################################################################
from typing import Optional, List, Tuple
from sqlalchemy.orm import Session
from app import models, schemas, query
def get_person_list(db: Session, query_params: query.PersonQueryParams) -> Tuple[List[models.Person], int]:
query_builder = query_params.get_query_builder(db)
# 1. Get total count after apply filter
query_builder.apply_filter()
total_count = len(query_builder.build().all())
# 2. Get alert list after apply sorter and paging
alert_list = query_builder.apply_sorter().apply_paging().build().all()
return alert_list, total_count
```
### 2.2 响应辅助
`sysom_utils` 设计了 `StandardReponse``StandardListResponse` 分别代表对象类型的响应数据和列表类型的响应数据,建议使用这两个响应对象封装 JSON 格式的响应数据。
#### 2.2.1 StandardReponse 使用示例
```python
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
from app.database import get_db
from app.crud import get_person_by_name
from app.schemas import Person
from sysom_utils import StandardResponse
router = APIRouter()
@router.get("/get")
async def get_specific_person(
person_name: str, db: Session = Depends(get_db)
):
person = get_person_by_name(db, person_name)
return StandardResponse(person, schema_class=Person)
#######################################################################################
# 响应数据的格式如下
# {
# "code": 200, => 状态码200 表示成功500表示服务端错误
# "message": "", => 错误信息,如果请求不成功这边可以存放错误
# "data": { => 字典类型的响应数据
# "id": 1,
# "name": "test",
# "age": 18
# }
# }
#
# 成功响应实例 => StandardResponse.success(data=person, schema_class=Person) 或者 StandardResponse(code=200, data=person, schema_class=Person)
# 错误响应实例 => StandardResponse.error(message="Username not exists") 或者 StandardResponse(code=500, message="Username not exists")
#######################################################################################
```
#### 2.2.1 StandardListReponse 使用示例
```python
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
from app.query import PersonQueryParams
from app.database import get_db
from app.crud import get_person_list
from app.schemas import Person
from sysom_utils import StandardListResponse
router = APIRouter()
@router.get("/list")
async def get_persons(
query_params: PersonQueryParams = Depends(), db: Session = Depends(get_db)
):
person_list = get_person_list(db, query_params)
return StandardListResponse(person_list, schema_class=Person)
#######################################################################################
# 响应数据的格式如下
# {
# "code": 200, => 状态码200 表示成功500表示服务端错误
# "message": "", => 错误信息,如果请求不成功这边可以存放错误
# "data": [ => 列表类型的响应数据
# {
# "id": 1,
# "name": "test",
# "age": 18
# }
# ]
# }
#
# 成功响应实例 => StandardResponse.success(data=person_list, schema_class=Person) 或者 StandardResponse(code=200, data=person_list, schema_class=Person)
# 错误响应实例 => StandardResponse.error(message="Username not exists") 或者 StandardResponse(code=500, message="Username not exists")
#######################################################################################
```