refactor:依赖包升级,fastapi升级到最新版本0.100, pydantic升级到2.0版本,多处代码有重构
This commit is contained in:
parent
188fb8de0b
commit
01c28dace4
@ -11,7 +11,7 @@ from fastapi.security import OAuth2PasswordBearer
|
||||
"""
|
||||
系统版本
|
||||
"""
|
||||
VERSION = "1.9.3"
|
||||
VERSION = "1.10.0"
|
||||
|
||||
"""安全警告: 不要在生产中打开调试运行!"""
|
||||
DEBUG = True
|
||||
|
@ -6,7 +6,7 @@
|
||||
# @IDE : PyCharm
|
||||
# @desc : 增删改查
|
||||
|
||||
from typing import List, Any
|
||||
from typing import Any
|
||||
from aioredis import Redis
|
||||
from fastapi import UploadFile
|
||||
from sqlalchemy.orm import joinedload
|
||||
@ -61,7 +61,7 @@ class UserDal(DalBase):
|
||||
password = data.telephone[5:12] if settings.DEFAULT_PASSWORD == "0" else settings.DEFAULT_PASSWORD
|
||||
data.password = self.model.get_password_hash(password)
|
||||
data.avatar = data.avatar if data.avatar else settings.DEFAULT_AVATAR
|
||||
obj = self.model(**data.dict(exclude={'role_ids'}))
|
||||
obj = self.model(**data.model_dump(exclude={'role_ids'}))
|
||||
if data.role_ids:
|
||||
roles = await RoleDal(self.db).get_datas(limit=0, id=("in", data.role_ids), v_return_objs=True)
|
||||
for role in roles:
|
||||
@ -206,7 +206,7 @@ class UserDal(DalBase):
|
||||
"error_url": im.generate_error_url()
|
||||
}
|
||||
|
||||
async def init_password(self, ids: List[int]):
|
||||
async def init_password(self, ids: list[int]):
|
||||
"""
|
||||
初始化所选用户密码
|
||||
将用户密码改为系统默认密码,并将初始化密码状态改为false
|
||||
@ -226,7 +226,7 @@ class UserDal(DalBase):
|
||||
await self.db.flush()
|
||||
return result
|
||||
|
||||
async def init_password_send_sms(self, ids: List[int], rd: Redis):
|
||||
async def init_password_send_sms(self, ids: list[int], rd: Redis):
|
||||
"""
|
||||
初始化所选用户密码并发送通知短信
|
||||
将用户密码改为系统默认密码,并将初始化密码状态改为false
|
||||
@ -248,7 +248,7 @@ class UserDal(DalBase):
|
||||
user["send_sms_msg"] = e.msg
|
||||
return result
|
||||
|
||||
async def init_password_send_email(self, ids: List[int], rd: Redis):
|
||||
async def init_password_send_email(self, ids: list[int], rd: Redis):
|
||||
"""
|
||||
初始化所选用户密码并发送通知邮件
|
||||
将用户密码改为系统默认密码,并将初始化密码状态改为false
|
||||
@ -301,7 +301,7 @@ class UserDal(DalBase):
|
||||
await self.flush(user)
|
||||
return True
|
||||
|
||||
async def delete_datas(self, ids: List[int], v_soft: bool = False, **kwargs):
|
||||
async def delete_datas(self, ids: list[int], v_soft: bool = False, **kwargs):
|
||||
"""
|
||||
删除多个用户,软删除
|
||||
删除后清空所关联的角色
|
||||
@ -330,7 +330,7 @@ class RoleDal(DalBase):
|
||||
v_schema: Any = None
|
||||
):
|
||||
"""创建数据"""
|
||||
obj = self.model(**data.dict(exclude={'menu_ids'}))
|
||||
obj = self.model(**data.model_dump(exclude={'menu_ids'}))
|
||||
menus = await MenuDal(db=self.db).get_datas(limit=0, id=("in", data.menu_ids), v_return_objs=True)
|
||||
if data.menu_ids:
|
||||
for menu in menus:
|
||||
@ -370,9 +370,9 @@ class RoleDal(DalBase):
|
||||
"""获取选择数据,全部数据"""
|
||||
sql = select(self.model)
|
||||
queryset = await self.db.execute(sql)
|
||||
return [schemas.RoleSelectOut.from_orm(i).dict() for i in queryset.scalars().all()]
|
||||
return [schemas.RoleSelectOut.model_validate(i).model_dump() for i in queryset.scalars().all()]
|
||||
|
||||
async def delete_datas(self, ids: List[int], v_soft: bool = False, **kwargs):
|
||||
async def delete_datas(self, ids: list[int], v_soft: bool = False, **kwargs):
|
||||
"""
|
||||
删除多个角色,硬删除
|
||||
如果存在用户关联则无法删除
|
||||
@ -442,7 +442,7 @@ class MenuDal(DalBase):
|
||||
menus = self.generate_router_tree(datas, roots)
|
||||
return self.menus_order(menus)
|
||||
|
||||
def generate_router_tree(self, menus: List[models.VadminMenu], nodes: filter, name: str = "") -> list:
|
||||
def generate_router_tree(self, menus: list[models.VadminMenu], nodes: filter, name: str = "") -> list:
|
||||
"""
|
||||
生成路由树
|
||||
|
||||
@ -452,16 +452,16 @@ class MenuDal(DalBase):
|
||||
"""
|
||||
data = []
|
||||
for root in nodes:
|
||||
router = schemas.RouterOut.from_orm(root)
|
||||
router = schemas.RouterOut.model_validate(root)
|
||||
router.name = name + "".join(name.capitalize() for name in router.path.split("/"))
|
||||
router.meta = schemas.Meta(title=root.title, icon=root.icon, hidden=root.hidden, alwaysShow=root.alwaysShow)
|
||||
if root.menu_type == "0":
|
||||
sons = filter(lambda i: i.parent_id == root.id, menus)
|
||||
router.children = self.generate_router_tree(menus, sons, router.name)
|
||||
data.append(router.dict())
|
||||
data.append(router.model_dump())
|
||||
return data
|
||||
|
||||
def generate_tree_list(self, menus: List[models.VadminMenu], nodes: filter) -> list:
|
||||
def generate_tree_list(self, menus: list[models.VadminMenu], nodes: filter) -> list:
|
||||
"""
|
||||
生成菜单树列表
|
||||
|
||||
@ -470,14 +470,14 @@ class MenuDal(DalBase):
|
||||
"""
|
||||
data = []
|
||||
for root in nodes:
|
||||
router = schemas.TreeListOut.from_orm(root)
|
||||
router = schemas.TreeListOut.model_validate(root)
|
||||
if root.menu_type == "0" or root.menu_type == "1":
|
||||
sons = filter(lambda i: i.parent_id == root.id, menus)
|
||||
router.children = self.generate_tree_list(menus, sons)
|
||||
data.append(router.dict())
|
||||
data.append(router.model_dump())
|
||||
return data
|
||||
|
||||
def generate_tree_options(self, menus: List[models.VadminMenu], nodes: filter) -> list:
|
||||
def generate_tree_options(self, menus: list[models.VadminMenu], nodes: filter) -> list:
|
||||
"""
|
||||
生成菜单树选择项
|
||||
|
||||
@ -504,7 +504,7 @@ class MenuDal(DalBase):
|
||||
item[children] = sorted(item[children], key=lambda menu: menu[order])
|
||||
return result
|
||||
|
||||
async def delete_datas(self, ids: List[int], v_soft: bool = False, **kwargs):
|
||||
async def delete_datas(self, ids: list[int], v_soft: bool = False, **kwargs):
|
||||
"""
|
||||
删除多个菜单
|
||||
如果存在角色关联则无法删除
|
||||
|
@ -17,7 +17,14 @@ class RoleParams(QueryParams):
|
||||
"""
|
||||
列表分页
|
||||
"""
|
||||
def __init__(self, name: str = None, role_key: str = None, disabled: bool = None, params: Paging = Depends()):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str | None = None,
|
||||
role_key: str | None = None,
|
||||
disabled: bool | None = None,
|
||||
params: Paging = Depends()
|
||||
):
|
||||
super().__init__(params)
|
||||
self.name = ("like", name)
|
||||
self.role_key = ("like", role_key)
|
||||
|
@ -20,11 +20,11 @@ class UserParams(QueryParams):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str = None,
|
||||
telephone: str = None,
|
||||
email: str = None,
|
||||
is_active: bool | str = None,
|
||||
is_staff: bool | str = None,
|
||||
name: str | None = None,
|
||||
telephone: str | None = None,
|
||||
email: str | None = None,
|
||||
is_active: bool | None = None,
|
||||
is_staff: bool | None = None,
|
||||
params: Paging = Depends()
|
||||
):
|
||||
super().__init__(params)
|
||||
|
@ -6,72 +6,60 @@
|
||||
# @IDE : PyCharm
|
||||
# @desc : pydantic 模型,用于数据库序列化操作
|
||||
|
||||
# pydantic 验证数据:https://blog.csdn.net/qq_44291044/article/details/104693526
|
||||
|
||||
|
||||
from typing import Optional, List
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from core.data_types import DatetimeStr
|
||||
|
||||
|
||||
class Menu(BaseModel):
|
||||
title: str
|
||||
icon: Optional[str] = None
|
||||
component: Optional[str] = None
|
||||
redirect: Optional[str] = None
|
||||
path: Optional[str] = None
|
||||
icon: str | None = None
|
||||
component: str | None = None
|
||||
redirect: str | None = None
|
||||
path: str | None = None
|
||||
disabled: bool = False
|
||||
hidden: bool = False
|
||||
order: Optional[int] = None
|
||||
perms: Optional[str] = None
|
||||
parent_id: Optional[int] = None
|
||||
order: int | None = None
|
||||
perms: str | None = None
|
||||
parent_id: int | None = None
|
||||
menu_type: str
|
||||
alwaysShow: Optional[bool] = True
|
||||
alwaysShow: bool | None = True
|
||||
|
||||
|
||||
class MenuSimpleOut(Menu):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: int
|
||||
create_datetime: DatetimeStr
|
||||
update_datetime: DatetimeStr
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
||||
|
||||
class Meta(BaseModel):
|
||||
title: str
|
||||
icon: Optional[str] = None
|
||||
icon: str | None = None
|
||||
hidden: bool = False
|
||||
noCache: Optional[bool] = False
|
||||
breadcrumb: Optional[bool] = True
|
||||
affix: Optional[bool] = False
|
||||
noTagsView: Optional[bool] = False
|
||||
canTo: Optional[bool] = False
|
||||
alwaysShow: Optional[bool] = True
|
||||
noCache: bool | None = False
|
||||
breadcrumb: bool | None = True
|
||||
affix: bool | None = False
|
||||
noTagsView: bool | None = False
|
||||
canTo: bool | None = False
|
||||
alwaysShow: bool | None = True
|
||||
|
||||
|
||||
# 路由展示
|
||||
class RouterOut(BaseModel):
|
||||
name: Optional[str] = None
|
||||
component: Optional[str] = None
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
name: str | None = None
|
||||
component: str | None = None
|
||||
path: str
|
||||
redirect: Optional[str] = None
|
||||
meta: Optional[Meta] = None
|
||||
order: Optional[int] = None
|
||||
children: List['RouterOut'] = []
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
||||
|
||||
RouterOut.update_forward_refs()
|
||||
redirect: str | None = None
|
||||
meta: Meta | None = None
|
||||
order: int | None = None
|
||||
children: list[dict] = []
|
||||
|
||||
|
||||
class TreeListOut(MenuSimpleOut):
|
||||
children: List['TreeListOut'] = []
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
||||
|
||||
RouterOut.update_forward_refs()
|
||||
children: list[dict] = []
|
||||
|
@ -6,11 +6,8 @@
|
||||
# @IDE : PyCharm
|
||||
# @desc : pydantic 模型,用于数据库序列化操作
|
||||
|
||||
# pydantic 验证数据:https://blog.csdn.net/qq_44291044/article/details/104693526
|
||||
|
||||
|
||||
from typing import Optional, List
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from core.data_types import DatetimeStr
|
||||
from .menu import MenuSimpleOut
|
||||
|
||||
@ -18,36 +15,34 @@ from .menu import MenuSimpleOut
|
||||
class Role(BaseModel):
|
||||
name: str
|
||||
disabled: bool = False
|
||||
order: Optional[int] = None
|
||||
desc: Optional[str] = None
|
||||
order: int | None = None
|
||||
desc: str | None = None
|
||||
role_key: str
|
||||
is_admin: bool = False
|
||||
|
||||
|
||||
class RoleSimpleOut(Role):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: int
|
||||
create_datetime: DatetimeStr
|
||||
update_datetime: DatetimeStr
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
||||
|
||||
class RoleOut(RoleSimpleOut):
|
||||
menus: Optional[List[MenuSimpleOut]] = []
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
menus: list[MenuSimpleOut] = []
|
||||
|
||||
|
||||
class RoleIn(Role):
|
||||
menu_ids: Optional[List[int]] = []
|
||||
menu_ids: list[int] = []
|
||||
|
||||
|
||||
class RoleSelectOut(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: int
|
||||
name: str
|
||||
disabled: bool
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
@ -6,33 +6,32 @@
|
||||
# @IDE : PyCharm
|
||||
# @desc : pydantic 模型,用于数据库序列化操作
|
||||
|
||||
# pydantic 验证数据:https://blog.csdn.net/qq_44291044/article/details/104693526
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, field_validator
|
||||
from pydantic_core.core_schema import FieldValidationInfo
|
||||
|
||||
from typing import List, Optional
|
||||
from pydantic import BaseModel, root_validator
|
||||
from core.data_types import Telephone, DatetimeStr, Email
|
||||
from .role import RoleSimpleOut
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
name: Optional[str] = None
|
||||
name: str | None = None
|
||||
telephone: Telephone
|
||||
email: Optional[Email] = None
|
||||
nickname: Optional[str] = None
|
||||
avatar: Optional[str] = None
|
||||
is_active: Optional[bool] = True
|
||||
is_staff: Optional[bool] = True
|
||||
gender: Optional[str] = "0"
|
||||
is_wx_server_openid: Optional[bool] = False
|
||||
email: Email | None = None
|
||||
nickname: str | None = None
|
||||
avatar: str | None = None
|
||||
is_active: bool | None = True
|
||||
is_staff: bool | None = True
|
||||
gender: str | None = "0"
|
||||
is_wx_server_openid: bool | None = False
|
||||
|
||||
|
||||
class UserIn(User):
|
||||
"""
|
||||
创建用户
|
||||
"""
|
||||
role_ids: Optional[List[int]] = []
|
||||
password: Optional[str] = ""
|
||||
role_ids: list[int] = []
|
||||
password: str | None = ""
|
||||
|
||||
|
||||
class UserUpdateBaseInfo(BaseModel):
|
||||
@ -41,53 +40,50 @@ class UserUpdateBaseInfo(BaseModel):
|
||||
"""
|
||||
name: str
|
||||
telephone: Telephone
|
||||
email: Optional[Email] = None
|
||||
nickname: Optional[str] = None
|
||||
gender: Optional[str] = "0"
|
||||
email: Email | None = None
|
||||
nickname: str | None = None
|
||||
gender: str | None = "0"
|
||||
|
||||
|
||||
class UserUpdate(User):
|
||||
"""
|
||||
更新用户详细信息
|
||||
"""
|
||||
name: Optional[str] = None
|
||||
name: str | None = None
|
||||
telephone: Telephone
|
||||
email: Optional[Email] = None
|
||||
nickname: Optional[str] = None
|
||||
avatar: Optional[str] = None
|
||||
is_active: Optional[bool] = True
|
||||
is_staff: Optional[bool] = False
|
||||
gender: Optional[str] = "0"
|
||||
role_ids: Optional[List[int]] = []
|
||||
email: Email | None = None
|
||||
nickname: str | None = None
|
||||
avatar: str | None = None
|
||||
is_active: bool | None = True
|
||||
is_staff: bool | None = False
|
||||
gender: str | None = "0"
|
||||
role_ids: list[int] = []
|
||||
|
||||
|
||||
class UserSimpleOut(User):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: int
|
||||
update_datetime: DatetimeStr
|
||||
create_datetime: DatetimeStr
|
||||
|
||||
is_reset_password: Optional[bool] = None
|
||||
last_login: Optional[DatetimeStr] = None
|
||||
last_ip: Optional[str] = None
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
is_reset_password: bool | None = None
|
||||
last_login: DatetimeStr | None = None
|
||||
last_ip: str | None = None
|
||||
|
||||
|
||||
class UserOut(UserSimpleOut):
|
||||
roles: Optional[List[RoleSimpleOut]] = []
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
roles: list[RoleSimpleOut] = []
|
||||
|
||||
|
||||
class ResetPwd(BaseModel):
|
||||
password: str
|
||||
password_two: str
|
||||
|
||||
@root_validator
|
||||
def check_passwords_match(cls, values):
|
||||
pw1, pw2 = values.get('password'), values.get('password_two')
|
||||
if pw1 is not None and pw2 is not None and pw1 != pw2:
|
||||
@field_validator('password_two')
|
||||
def check_passwords_match(cls, v, info: FieldValidationInfo):
|
||||
if 'password' in info.data and v != info.data['password']:
|
||||
raise ValueError('两次密码不一致!')
|
||||
return values
|
||||
return v
|
||||
|
@ -5,7 +5,6 @@
|
||||
# @IDE : PyCharm
|
||||
# @desc : 获取认证后的信息工具
|
||||
|
||||
from typing import List, Optional
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import joinedload
|
||||
from apps.vadmin.auth.crud import UserDal
|
||||
@ -76,7 +75,7 @@ class FullAdminAuth(AuthValidation):
|
||||
如果有权限,那么会验证该用户是否包括权限列表中的其中一个权限
|
||||
"""
|
||||
|
||||
def __init__(self, permissions: Optional[List[str]] = None):
|
||||
def __init__(self, permissions: list[str] | None = None):
|
||||
if permissions:
|
||||
self.permissions = set(permissions)
|
||||
else:
|
||||
|
@ -21,6 +21,7 @@ class Auth(BaseModel):
|
||||
db: AsyncSession
|
||||
|
||||
class Config:
|
||||
# 接收任意类型
|
||||
arbitrary_types_allowed = True
|
||||
|
||||
|
||||
@ -49,7 +50,6 @@ class AuthValidation:
|
||||
status_code=status.HTTP_403_FORBIDDEN
|
||||
)
|
||||
try:
|
||||
# TODO token解析失败问题解决
|
||||
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
|
||||
telephone: str = payload.get("sub")
|
||||
exp: int = payload.get("exp")
|
||||
|
@ -7,7 +7,7 @@
|
||||
# @desc : 登录验证装饰器
|
||||
|
||||
from fastapi import Request
|
||||
from pydantic import BaseModel, validator
|
||||
from pydantic import BaseModel, validator, field_validator
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from application.settings import DEFAULT_AUTH_ERROR_MAX_NUMBER, DEMO
|
||||
from apps.vadmin.auth import crud, schemas
|
||||
@ -23,21 +23,21 @@ class LoginForm(BaseModel):
|
||||
method: str = '0' # 认证方式,0:密码登录,1:短信登录,2:微信一键登录
|
||||
platform: str = '0' # 登录平台,0:PC端管理系统,1:移动端管理系统
|
||||
|
||||
# validators
|
||||
_normalize_telephone = validator('telephone', allow_reuse=True)(vali_telephone)
|
||||
# 重用验证器:https://docs.pydantic.dev/dev-v2/usage/validators/#reuse-validators
|
||||
normalize_telephone = field_validator('telephone')(vali_telephone)
|
||||
|
||||
|
||||
class WXLoginForm(BaseModel):
|
||||
telephone: Optional[str] = None
|
||||
telephone: str | None = None
|
||||
code: str
|
||||
method: str = '2' # 认证方式,0:密码登录,1:短信登录,2:微信一键登录
|
||||
platform: str = '1' # 登录平台,0:PC端管理系统,1:移动端管理系统
|
||||
|
||||
|
||||
class LoginResult(BaseModel):
|
||||
status: Optional[bool] = False
|
||||
user: Optional[schemas.UserOut] = None
|
||||
msg: Optional[str] = None
|
||||
status: bool | None = False
|
||||
user: schemas.UserOut | None = None
|
||||
msg: str | None = None
|
||||
|
||||
class Config:
|
||||
arbitrary_types_allowed = True
|
||||
@ -85,6 +85,6 @@ class LoginValidation:
|
||||
await count.delete()
|
||||
self.result.msg = "OK"
|
||||
self.result.status = True
|
||||
self.result.user = schemas.UserSimpleOut.from_orm(user)
|
||||
self.result.user = schemas.UserSimpleOut.model_validate(user)
|
||||
await user.update_login_info(db, request.client.host)
|
||||
return self.result
|
||||
|
@ -87,7 +87,7 @@ async def post_user_current_update_avatar(file: UploadFile, auth: Auth = Depends
|
||||
|
||||
@app.get("/user/admin/current/info", summary="获取当前管理员信息")
|
||||
async def get_user_admin_current_info(auth: Auth = Depends(FullAdminAuth())):
|
||||
result = schemas.UserOut.from_orm(auth.user).dict()
|
||||
result = schemas.UserOut.model_validate(auth.user).model_dump()
|
||||
result["permissions"] = list(FullAdminAuth.get_user_permissions(auth.user))
|
||||
return SuccessResponse(result)
|
||||
|
||||
|
@ -7,34 +7,32 @@
|
||||
# @desc : 常见问题
|
||||
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from core.data_types import DatetimeStr
|
||||
from apps.vadmin.auth.schemas import UserSimpleOut
|
||||
from .issue_category import IssueCategorySimpleOut
|
||||
|
||||
|
||||
class Issue(BaseModel):
|
||||
category_id: Optional[int] = None
|
||||
create_user_id: Optional[int] = None
|
||||
category_id: int | None = None
|
||||
create_user_id: int | None = None
|
||||
|
||||
title: Optional[str] = None
|
||||
content: Optional[str] = None
|
||||
view_number: Optional[int] = None
|
||||
is_active: Optional[bool] = None
|
||||
title: str | None = None
|
||||
content: str | None = None
|
||||
view_number: int | None = None
|
||||
is_active: bool | None = None
|
||||
|
||||
|
||||
class IssueSimpleOut(Issue):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: int
|
||||
update_datetime: DatetimeStr
|
||||
create_datetime: DatetimeStr
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
||||
|
||||
class IssueListOut(IssueSimpleOut):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
create_user: UserSimpleOut
|
||||
category: IssueCategorySimpleOut
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
@ -8,38 +8,36 @@
|
||||
|
||||
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from core.data_types import DatetimeStr
|
||||
from apps.vadmin.auth.schemas import UserSimpleOut
|
||||
|
||||
|
||||
class IssueCategory(BaseModel):
|
||||
name: Optional[str] = None
|
||||
platform: Optional[str] = None
|
||||
is_active: Optional[bool] = None
|
||||
name: str | None = None
|
||||
platform: str | None = None
|
||||
is_active: bool | None = None
|
||||
|
||||
create_user_id: Optional[int] = None
|
||||
create_user_id: int | None = None
|
||||
|
||||
|
||||
class IssueCategorySimpleOut(IssueCategory):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: int
|
||||
update_datetime: DatetimeStr
|
||||
create_datetime: DatetimeStr
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
||||
|
||||
class IssueCategoryListOut(IssueCategorySimpleOut):
|
||||
create_user: UserSimpleOut
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
create_user: UserSimpleOut
|
||||
|
||||
|
||||
class IssueCategoryOptionsOut(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
label: str = Field(alias='name')
|
||||
value: int = Field(alias='id')
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
@ -6,24 +6,22 @@
|
||||
# @IDE : PyCharm
|
||||
# @desc : 简要说明
|
||||
|
||||
from typing import Optional, List
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from core.data_types import DatetimeStr
|
||||
from .issue import IssueSimpleOut
|
||||
|
||||
|
||||
class IssueCategoryPlatformOut(BaseModel):
|
||||
name: Optional[str] = None
|
||||
platform: Optional[str] = None
|
||||
is_active: Optional[bool] = None
|
||||
create_user_id: Optional[int] = None
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
name: str | None = None
|
||||
platform: str | None = None
|
||||
is_active: bool | None = None
|
||||
create_user_id: int | None = None
|
||||
|
||||
id: int
|
||||
update_datetime: DatetimeStr
|
||||
create_datetime: DatetimeStr
|
||||
|
||||
issues: Optional[List[IssueSimpleOut]] = None
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
issues: list[IssueSimpleOut] = None
|
||||
|
||||
|
@ -6,7 +6,6 @@
|
||||
# @IDE : PyCharm
|
||||
# @desc : 数据库 增删改查操作
|
||||
import random
|
||||
from typing import List
|
||||
# sqlalchemy 查询操作:https://segmentfault.com/a/1190000016767008
|
||||
# sqlalchemy 关联查询:https://www.jianshu.com/p/dfad7c08c57a
|
||||
# sqlalchemy 关联查询详细:https://blog.csdn.net/u012324798/article/details/103940527
|
||||
@ -22,7 +21,7 @@ class LoginRecordDal(DalBase):
|
||||
def __init__(self, db: AsyncSession):
|
||||
super(LoginRecordDal, self).__init__(db, models.VadminLoginRecord, schemas.LoginRecordSimpleOut)
|
||||
|
||||
async def get_user_distribute(self) -> List[dict]:
|
||||
async def get_user_distribute(self) -> list[dict]:
|
||||
"""
|
||||
获取用户登录分布情况
|
||||
高德经纬度查询:https://lbs.amap.com/tools/picker
|
||||
|
@ -17,8 +17,15 @@ class LoginParams(QueryParams):
|
||||
"""
|
||||
列表分页
|
||||
"""
|
||||
def __init__(self, ip: str = None, address: str = None, telephone: str = None, status: bool = None,
|
||||
platform: str = None, params: Paging = Depends()):
|
||||
def __init__(
|
||||
self,
|
||||
ip: str = None,
|
||||
address: str = None,
|
||||
telephone: str = None,
|
||||
status: bool = None,
|
||||
platform: str = None,
|
||||
params: Paging = Depends()
|
||||
):
|
||||
super().__init__(params)
|
||||
self.ip = ("like", ip)
|
||||
self.telephone = ("like", telephone)
|
||||
|
@ -17,8 +17,13 @@ class OperationParams(QueryParams):
|
||||
"""
|
||||
列表分页
|
||||
"""
|
||||
def __init__(self, summary: str = None, telephone: str = None, request_method: str = None,
|
||||
params: Paging = Depends()):
|
||||
def __init__(
|
||||
self,
|
||||
summary: str = None,
|
||||
telephone: str = None,
|
||||
request_method: str = None,
|
||||
params: Paging = Depends()
|
||||
):
|
||||
super().__init__(params)
|
||||
self.summary = ("like", summary)
|
||||
self.telephone = ("like", telephone)
|
||||
|
@ -6,38 +6,33 @@
|
||||
# @IDE : PyCharm
|
||||
# @desc : pydantic 模型,用于数据库序列化操作
|
||||
|
||||
# pydantic 验证数据:https://blog.csdn.net/qq_44291044/article/details/104693526
|
||||
|
||||
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from core.data_types import DatetimeStr
|
||||
|
||||
|
||||
class LoginRecord(BaseModel):
|
||||
telephone: str
|
||||
status: bool
|
||||
ip: Optional[str] = None
|
||||
address: Optional[str] = None
|
||||
browser: Optional[str] = None
|
||||
system: Optional[str] = None
|
||||
response: Optional[str] = None
|
||||
request: Optional[str] = None
|
||||
postal_code: Optional[str] = None
|
||||
area_code: Optional[str] = None
|
||||
country: Optional[str] = None
|
||||
province: Optional[str] = None
|
||||
city: Optional[str] = None
|
||||
county: Optional[str] = None
|
||||
operator: Optional[str] = None
|
||||
platform: Optional[str] = None
|
||||
login_method: Optional[str] = None
|
||||
ip: str | None = None
|
||||
address: str | None = None
|
||||
browser: str | None = None
|
||||
system: str | None = None
|
||||
response: str | None = None
|
||||
request: str | None = None
|
||||
postal_code: str | None = None
|
||||
area_code: str | None = None
|
||||
country: str | None = None
|
||||
province: str | None = None
|
||||
city: str | None = None
|
||||
county: str | None = None
|
||||
operator: str | None = None
|
||||
platform: str | None = None
|
||||
login_method: str | None = None
|
||||
|
||||
|
||||
class LoginRecordSimpleOut(LoginRecord):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: int
|
||||
create_datetime: DatetimeStr
|
||||
update_datetime: DatetimeStr
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
@ -6,34 +6,30 @@
|
||||
# @IDE : PyCharm
|
||||
# @desc : pydantic 模型,用于数据库序列化操作
|
||||
|
||||
# pydantic 验证数据:https://blog.csdn.net/qq_44291044/article/details/104693526
|
||||
|
||||
|
||||
from typing import Optional, List
|
||||
from pydantic import BaseModel
|
||||
from core.data_types import DatetimeStr, ObjectIdStr
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from core.data_types import DatetimeStr
|
||||
|
||||
|
||||
class OperationRecord(BaseModel):
|
||||
telephone: Optional[str] = None
|
||||
user_id: Optional[str] = None
|
||||
user_name: Optional[str] = None
|
||||
status_code: Optional[int] = None
|
||||
client_ip: Optional[str] = None
|
||||
request_method: Optional[str] = None
|
||||
api_path: Optional[str] = None
|
||||
system: Optional[str] = None
|
||||
browser: Optional[str] = None
|
||||
summary: Optional[str] = None
|
||||
route_name: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
tags: Optional[List[str]] = None
|
||||
process_time: Optional[str] = None
|
||||
params: Optional[str] = None
|
||||
telephone: str | None = None
|
||||
user_id: int | None = None
|
||||
user_name: str | None = None
|
||||
status_code: int | None = None
|
||||
client_ip: str | None = None
|
||||
request_method: str | None = None
|
||||
api_path: str | None = None
|
||||
system: str | None = None
|
||||
browser: str | None = None
|
||||
summary: str | None = None
|
||||
route_name: str | None = None
|
||||
description: str | None = None
|
||||
tags: list[str] | None = None
|
||||
process_time: float | None = None
|
||||
params: str | None = None
|
||||
|
||||
|
||||
class OperationRecordSimpleOut(OperationRecord):
|
||||
create_datetime: DatetimeStr
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
create_datetime: DatetimeStr
|
||||
|
@ -7,18 +7,17 @@
|
||||
# @desc : 简要说明
|
||||
|
||||
|
||||
from typing import Optional, List
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from core.data_types import DatetimeStr
|
||||
|
||||
|
||||
class SMSSendRecord(BaseModel):
|
||||
telephone: str
|
||||
status: bool = True
|
||||
user_id: Optional[int] = None
|
||||
content: Optional[str] = None
|
||||
desc: Optional[str] = None
|
||||
scene: Optional[str] = None
|
||||
user_id: int | None = None
|
||||
content: str | None = None
|
||||
desc: str | None = None
|
||||
scene: str | None = None
|
||||
|
||||
|
||||
class SMSSendRecordSimpleOut(SMSSendRecord):
|
||||
@ -26,5 +25,4 @@ class SMSSendRecordSimpleOut(SMSSendRecord):
|
||||
create_datetime: DatetimeStr
|
||||
update_datetime: DatetimeStr
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
@ -12,11 +12,10 @@
|
||||
import json
|
||||
import os
|
||||
from enum import Enum
|
||||
from typing import List, Union, Any
|
||||
from typing import Any
|
||||
from aioredis import Redis
|
||||
from fastapi.encoders import jsonable_encoder
|
||||
from motor.motor_asyncio import AsyncIOMotorDatabase
|
||||
from pymongo.results import InsertOneResult, UpdateResult
|
||||
from sqlalchemy import select, update
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import joinedload
|
||||
@ -34,7 +33,7 @@ class DictTypeDal(DalBase):
|
||||
def __init__(self, db: AsyncSession):
|
||||
super(DictTypeDal, self).__init__(db, models.VadminDictType, schemas.DictTypeSimpleOut)
|
||||
|
||||
async def get_dicts_details(self, dict_types: List[str]) -> dict:
|
||||
async def get_dicts_details(self, dict_types: list[str]) -> dict:
|
||||
"""
|
||||
获取多个字典类型下的字典元素列表
|
||||
"""
|
||||
@ -51,14 +50,14 @@ class DictTypeDal(DalBase):
|
||||
data[obj.dict_type] = []
|
||||
continue
|
||||
else:
|
||||
data[obj.dict_type] = [schemas.DictDetailsSimpleOut.from_orm(i).dict() for i in obj.details]
|
||||
data[obj.dict_type] = [schemas.DictDetailsSimpleOut.model_validate(i).model_dump() for i in obj.details]
|
||||
return data
|
||||
|
||||
async def get_select_datas(self):
|
||||
"""获取选择数据,全部数据"""
|
||||
sql = select(self.model)
|
||||
queryset = await self.db.execute(sql)
|
||||
return [schemas.DictTypeSelectOut.from_orm(i).dict() for i in queryset.scalars().all()]
|
||||
return [schemas.DictTypeSelectOut.model_validate(i).model_dump() for i in queryset.scalars().all()]
|
||||
|
||||
|
||||
class DictDetailsDal(DalBase):
|
||||
@ -128,7 +127,7 @@ class SettingsTabDal(DalBase):
|
||||
def __init__(self, db: AsyncSession):
|
||||
super(SettingsTabDal, self).__init__(db, models.VadminSystemSettingsTab, schemas.SettingsTabSimpleOut)
|
||||
|
||||
async def get_classify_tab_values(self, classify: List[str], hidden: bool | None = False):
|
||||
async def get_classify_tab_values(self, classify: list[str], hidden: bool | None = False):
|
||||
"""
|
||||
获取系统配置分类下的标签信息
|
||||
"""
|
||||
@ -144,7 +143,7 @@ class SettingsTabDal(DalBase):
|
||||
)
|
||||
return self.__generate_values(datas)
|
||||
|
||||
async def get_tab_name_values(self, tab_names: List[str], hidden: bool | None = False):
|
||||
async def get_tab_name_values(self, tab_names: list[str], hidden: bool | None = False):
|
||||
"""
|
||||
获取系统配置标签下的标签信息
|
||||
"""
|
||||
@ -161,7 +160,7 @@ class SettingsTabDal(DalBase):
|
||||
return self.__generate_values(datas)
|
||||
|
||||
@classmethod
|
||||
def __generate_values(cls, datas: List[models.VadminSystemSettingsTab]):
|
||||
def __generate_values(cls, datas: list[models.VadminSystemSettingsTab]):
|
||||
"""
|
||||
生成字典值
|
||||
"""
|
||||
@ -398,7 +397,7 @@ class TaskDal(MongoManage):
|
||||
"""
|
||||
创建任务
|
||||
"""
|
||||
data_dict = data.dict()
|
||||
data_dict = data.model_dump()
|
||||
is_active = data_dict.pop('is_active')
|
||||
insert_result = await super().create_data(data_dict)
|
||||
obj = await self.get_task(insert_result.inserted_id, v_schema=schemas.TaskSimpleOut)
|
||||
@ -422,7 +421,7 @@ class TaskDal(MongoManage):
|
||||
"""
|
||||
更新任务
|
||||
"""
|
||||
data_dict = data.dict()
|
||||
data_dict = data.model_dump()
|
||||
is_active = data_dict.pop('is_active')
|
||||
await super(TaskDal, self).put_data(_id, data)
|
||||
obj: dict = await self.get_task(_id, v_schema=schemas.TaskSimpleOut)
|
||||
|
@ -6,53 +6,48 @@
|
||||
# @IDE : PyCharm
|
||||
# @desc : pydantic 模型,用于数据库序列化操作
|
||||
|
||||
# pydantic 验证数据:https://blog.csdn.net/qq_44291044/article/details/104693526
|
||||
|
||||
|
||||
from typing import Optional, List
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from core.data_types import DatetimeStr
|
||||
|
||||
|
||||
class DictType(BaseModel):
|
||||
dict_name: str
|
||||
dict_type: str
|
||||
disabled: Optional[bool] = False
|
||||
remark: Optional[str] = None
|
||||
disabled: bool | None = False
|
||||
remark: str | None = None
|
||||
|
||||
|
||||
class DictTypeSimpleOut(DictType):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: int
|
||||
create_datetime: DatetimeStr
|
||||
update_datetime: DatetimeStr
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
||||
|
||||
class DictTypeSelectOut(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: int
|
||||
dict_name: str
|
||||
disabled: bool
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
||||
|
||||
class DictDetails(BaseModel):
|
||||
label: str
|
||||
value: str
|
||||
disabled: Optional[bool] = False
|
||||
is_default: Optional[bool] = False
|
||||
remark: Optional[str] = None
|
||||
order: Optional[int] = None
|
||||
disabled: bool | None = False
|
||||
is_default: bool | None = False
|
||||
remark: str | None = None
|
||||
order: int | None = None
|
||||
dict_type_id: int
|
||||
|
||||
|
||||
class DictDetailsSimpleOut(DictDetails):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: int
|
||||
create_datetime: DatetimeStr
|
||||
update_datetime: DatetimeStr
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
@ -6,27 +6,24 @@
|
||||
# @IDE : PyCharm
|
||||
# @desc : pydantic 模型,用于数据库序列化操作
|
||||
|
||||
# pydantic 验证数据:https://blog.csdn.net/qq_44291044/article/details/104693526
|
||||
|
||||
|
||||
from typing import Optional, List
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from core.data_types import DatetimeStr
|
||||
|
||||
|
||||
class Settings(BaseModel):
|
||||
config_label: Optional[str] = None
|
||||
config_label: str | None = None
|
||||
config_key: str
|
||||
config_value: Optional[str] = None
|
||||
remark: Optional[str] = None
|
||||
disabled: Optional[bool] = None
|
||||
config_value: str | None = None
|
||||
remark: str | None = None
|
||||
disabled: bool | None = None
|
||||
tab_id: int
|
||||
|
||||
|
||||
class SettingsSimpleOut(Settings):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: int
|
||||
create_datetime: DatetimeStr
|
||||
update_datetime: DatetimeStr
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
@ -6,10 +6,8 @@
|
||||
# @IDE : PyCharm
|
||||
# @desc : pydantic 模型,用于数据库序列化操作
|
||||
|
||||
# pydantic 验证数据:https://blog.csdn.net/qq_44291044/article/details/104693526
|
||||
|
||||
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from core.data_types import DatetimeStr
|
||||
|
||||
|
||||
@ -22,9 +20,9 @@ class SettingsTab(BaseModel):
|
||||
|
||||
|
||||
class SettingsTabSimpleOut(SettingsTab):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: int
|
||||
create_datetime: DatetimeStr
|
||||
update_datetime: DatetimeStr
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
@ -6,28 +6,27 @@
|
||||
# @IDE : PyCharm
|
||||
# @desc : 简要说明
|
||||
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from core.data_types import DatetimeStr, ObjectIdStr
|
||||
|
||||
|
||||
class Task(BaseModel):
|
||||
name: str
|
||||
group: Optional[str] = None
|
||||
group: str | None = None
|
||||
job_class: str
|
||||
exec_strategy: str
|
||||
expression: str
|
||||
is_active: Optional[bool] = True # 临时字段,不在表中创建
|
||||
remark: Optional[str] = None
|
||||
start_date: Optional[DatetimeStr] = None
|
||||
end_date: Optional[DatetimeStr] = None
|
||||
is_active: bool | None = True # 临时字段,不在表中创建
|
||||
remark: str | None = None
|
||||
start_date: DatetimeStr | None = None
|
||||
end_date: DatetimeStr | None = None
|
||||
|
||||
|
||||
class TaskSimpleOut(Task):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: ObjectIdStr = Field(..., alias='_id')
|
||||
create_datetime: DatetimeStr
|
||||
update_datetime: DatetimeStr
|
||||
last_run_datetime: Optional[DatetimeStr] = None # 临时字段,不在表中创建
|
||||
last_run_datetime: DatetimeStr | None = None # 临时字段,不在表中创建
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
@ -6,7 +6,6 @@
|
||||
# @desc : 主要接口文件
|
||||
|
||||
# UploadFile 库依赖:pip install python-multipart
|
||||
from typing import List
|
||||
from aioredis import Redis
|
||||
from fastapi import APIRouter, Depends, Body, UploadFile, Form
|
||||
from motor.motor_asyncio import AsyncIOMotorDatabase
|
||||
@ -17,7 +16,6 @@ from utils.file.aliyun_oss import AliyunOSS, BucketConf
|
||||
from utils.file.file_manage import FileManage
|
||||
from utils.response import SuccessResponse, ErrorResponse
|
||||
from utils.sms.code import CodeSMS
|
||||
from utils.tools import generate_string
|
||||
from . import schemas, crud
|
||||
from core.dependencies import IdList
|
||||
from apps.vadmin.auth.utils.current import AllUserAuth, FullAdminAuth, OpenAuth
|
||||
@ -53,7 +51,7 @@ async def delete_dict_types(ids: IdList = Depends(), auth: Auth = Depends(AllUse
|
||||
@app.post("/dict/types/details", summary="获取多个字典类型下的字典元素列表")
|
||||
async def post_dicts_details(
|
||||
auth: Auth = Depends(AllUserAuth()),
|
||||
dict_types: List[str] = Body(None, title="字典元素列表", description="查询字典元素列表")
|
||||
dict_types: list[str] = Body(None, title="字典元素列表", description="查询字典元素列表")
|
||||
):
|
||||
datas = await crud.DictTypeDal(auth.db).get_dicts_details(dict_types)
|
||||
return SuccessResponse(datas)
|
||||
|
@ -19,7 +19,7 @@
|
||||
# https://www.osgeo.cn/sqlalchemy/orm/loading_relationships.html?highlight=selectinload#sqlalchemy.orm.joinedload
|
||||
|
||||
import datetime
|
||||
from typing import List, Set
|
||||
from typing import Set
|
||||
from fastapi import HTTPException
|
||||
from fastapi.encoders import jsonable_encoder
|
||||
from sqlalchemy import func, delete, update, or_
|
||||
@ -47,7 +47,7 @@ class DalBase:
|
||||
data_id: int = None,
|
||||
v_options: list = None,
|
||||
v_join_query: dict = None,
|
||||
v_or: List[tuple] = None,
|
||||
v_or: list[tuple] = None,
|
||||
v_order: str = None,
|
||||
v_order_field: str = None,
|
||||
v_return_none: bool = False,
|
||||
@ -82,7 +82,7 @@ class DalBase:
|
||||
if not data and v_return_none:
|
||||
return None
|
||||
if data and v_schema:
|
||||
return v_schema.from_orm(data).dict()
|
||||
return v_schema.model_validate(data).model_dump()
|
||||
if data:
|
||||
return data
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="未找到此数据")
|
||||
@ -93,7 +93,7 @@ class DalBase:
|
||||
limit: int = 10,
|
||||
v_options: list = None,
|
||||
v_join_query: dict = None,
|
||||
v_or: List[tuple] = None,
|
||||
v_or: list[tuple] = None,
|
||||
v_order: str = None,
|
||||
v_order_field: str = None,
|
||||
v_return_objs: bool = False,
|
||||
@ -131,7 +131,7 @@ class DalBase:
|
||||
return queryset.scalars().unique().all()
|
||||
return [await self.out_dict(i, v_schema=v_schema) for i in queryset.scalars().unique().all()]
|
||||
|
||||
async def get_count(self, v_options: list = None, v_join_query: dict = None, v_or: List[tuple] = None, **kwargs):
|
||||
async def get_count(self, v_options: list = None, v_join_query: dict = None, v_or: list[tuple] = None, **kwargs):
|
||||
"""
|
||||
获取数据总数
|
||||
|
||||
@ -156,7 +156,7 @@ class DalBase:
|
||||
if isinstance(data, dict):
|
||||
obj = self.model(**data)
|
||||
else:
|
||||
obj = self.model(**data.dict())
|
||||
obj = self.model(**data.model_dump())
|
||||
await self.flush(obj)
|
||||
return await self.out_dict(obj, v_options, v_return_obj, v_schema)
|
||||
|
||||
@ -183,7 +183,7 @@ class DalBase:
|
||||
await self.flush(obj)
|
||||
return await self.out_dict(obj, None, v_return_obj, v_schema)
|
||||
|
||||
async def delete_datas(self, ids: List[int], v_soft: bool = False, **kwargs):
|
||||
async def delete_datas(self, ids: list[int], v_soft: bool = False, **kwargs):
|
||||
"""
|
||||
删除多条数据
|
||||
:param ids: 数据集
|
||||
@ -200,13 +200,14 @@ class DalBase:
|
||||
)
|
||||
else:
|
||||
await self.db.execute(delete(self.model).where(self.model.id.in_(ids)))
|
||||
await self.flush()
|
||||
|
||||
def add_filter_condition(
|
||||
self,
|
||||
sql: select,
|
||||
v_options: list = None,
|
||||
v_join_query: dict = None,
|
||||
v_or: List[tuple] = None,
|
||||
v_or: list[tuple] = None,
|
||||
**kwargs
|
||||
) -> select:
|
||||
"""
|
||||
@ -245,7 +246,7 @@ class DalBase:
|
||||
sql = sql.options(*[load for load in v_options])
|
||||
return sql
|
||||
|
||||
def __or_filter(self, sql: select, v_or: List[tuple], v_join_left: Set[str], v_join: Set[str]):
|
||||
def __or_filter(self, sql: select, v_or: list[tuple], v_join_left: Set[str], v_join: Set[str]):
|
||||
"""
|
||||
或逻辑操作
|
||||
:param sql:
|
||||
@ -337,5 +338,5 @@ class DalBase:
|
||||
if v_return_obj:
|
||||
return obj
|
||||
if v_schema:
|
||||
return v_schema.from_orm(obj).dict()
|
||||
return self.schema.from_orm(obj).dict()
|
||||
return v_schema.model_validate(obj).model_dump()
|
||||
return self.schema.model_validate(obj).model_dump()
|
||||
|
@ -1,84 +1,122 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @version : 1.0
|
||||
# @Create Time : 2022/11/14 12:42
|
||||
# @Create Time : 2023/7/16 12:42
|
||||
# @File : data_types.py
|
||||
# @IDE : PyCharm
|
||||
# @desc : 自定义数据类型
|
||||
|
||||
"""
|
||||
自定义数据类型 - 官方文档:https://pydantic-docs.helpmanual.io/usage/types/#custom-data-types
|
||||
自定义数据类型 - 官方文档:https://docs.pydantic.dev/dev-v2/usage/types/custom/#adding-validation-and-serialization
|
||||
"""
|
||||
import datetime
|
||||
from typing import Annotated, Any
|
||||
|
||||
from bson import ObjectId
|
||||
|
||||
from pydantic import AfterValidator, PlainSerializer, WithJsonSchema
|
||||
from .validator import *
|
||||
|
||||
|
||||
class DatetimeStr(str):
|
||||
def DatetimeStrVali(value: str | datetime.datetime | int | float | dict):
|
||||
"""
|
||||
日期时间字符串验证
|
||||
如果我传入的是字符串,那么直接返回,如果我传入的是一个日期类型,那么会转为字符串格式后返回
|
||||
因为在 pydantic 2.0 中是支持 int 或 float 自动转换类型的,所以我这里添加进去,但是在处理时会使这两种类型报错
|
||||
|
||||
@classmethod
|
||||
def __get_validators__(cls):
|
||||
yield cls.validate
|
||||
|
||||
@classmethod
|
||||
def validate(cls, v):
|
||||
if isinstance(v, str):
|
||||
return v
|
||||
elif isinstance(v, dict):
|
||||
# 转换为datetime对象
|
||||
v = datetime.datetime.strptime(v.get("$date"), "%Y-%m-%dT%H:%M:%S.%fZ")
|
||||
return v.strftime("%Y-%m-%d %H:%M:%S")
|
||||
官方文档:https://docs.pydantic.dev/dev-v2/usage/types/datetime/
|
||||
"""
|
||||
if isinstance(value, str):
|
||||
pattern = "%Y-%m-%d %H:%M:%S"
|
||||
try:
|
||||
datetime.datetime.strptime(value, pattern)
|
||||
return value
|
||||
except ValueError:
|
||||
pass
|
||||
elif isinstance(value, datetime.datetime):
|
||||
return value.strftime("%Y-%m-%d %H:%M:%S")
|
||||
elif isinstance(value, dict):
|
||||
# 用于处理 mongodb 日期时间数据类型
|
||||
date_str = value.get("$date")
|
||||
date_format = '%Y-%m-%dT%H:%M:%S.%fZ'
|
||||
# 将字符串转换为datetime.datetime类型
|
||||
datetime_obj = datetime.datetime.strptime(date_str, date_format)
|
||||
# 将datetime.datetime对象转换为指定的字符串格式
|
||||
return datetime_obj.strftime('%Y-%m-%d %H:%M:%S')
|
||||
raise ValueError("无效的日期时间或字符串数据")
|
||||
|
||||
|
||||
class Telephone(str):
|
||||
|
||||
@classmethod
|
||||
def __get_validators__(cls):
|
||||
yield cls.validate
|
||||
|
||||
@classmethod
|
||||
def validate(cls, v):
|
||||
return vali_telephone(v)
|
||||
# 实现自定义一个日期时间字符串的数据类型
|
||||
DatetimeStr = Annotated[
|
||||
str | datetime.datetime | int | float | dict,
|
||||
AfterValidator(DatetimeStrVali),
|
||||
PlainSerializer(lambda x: x, return_type=str),
|
||||
WithJsonSchema({'type': 'string'}, mode='serialization')
|
||||
]
|
||||
|
||||
|
||||
class Email(str):
|
||||
|
||||
@classmethod
|
||||
def __get_validators__(cls):
|
||||
yield cls.validate
|
||||
|
||||
@classmethod
|
||||
def validate(cls, v):
|
||||
return vali_email(v)
|
||||
# 实现自定义一个手机号类型
|
||||
Telephone = Annotated[
|
||||
str,
|
||||
AfterValidator(lambda x: vali_telephone(x)),
|
||||
PlainSerializer(lambda x: x, return_type=str),
|
||||
WithJsonSchema({'type': 'string'}, mode='serialization')
|
||||
]
|
||||
|
||||
|
||||
class DateStr(str):
|
||||
|
||||
@classmethod
|
||||
def __get_validators__(cls):
|
||||
yield cls.validate
|
||||
|
||||
@classmethod
|
||||
def validate(cls, v):
|
||||
if isinstance(v, str):
|
||||
return v
|
||||
return v.strftime("%Y-%m-%d")
|
||||
# 实现自定义一个邮箱类型
|
||||
Email = Annotated[
|
||||
str,
|
||||
AfterValidator(lambda x: vali_email(x)),
|
||||
PlainSerializer(lambda x: x, return_type=str),
|
||||
WithJsonSchema({'type': 'string'}, mode='serialization')
|
||||
]
|
||||
|
||||
|
||||
class ObjectIdStr(str):
|
||||
def DateStrVali(value: str | datetime.date | int | float):
|
||||
"""
|
||||
日期字符串验证
|
||||
如果我传入的是字符串,那么直接返回,如果我传入的是一个日期类型,那么会转为字符串格式后返回
|
||||
因为在 pydantic 2.0 中是支持 int 或 float 自动转换类型的,所以我这里添加进去,但是在处理时会使这两种类型报错
|
||||
|
||||
@classmethod
|
||||
def __get_validators__(cls):
|
||||
yield cls.validate
|
||||
官方文档:https://docs.pydantic.dev/dev-v2/usage/types/datetime/
|
||||
"""
|
||||
if isinstance(value, str):
|
||||
pattern = "%Y-%m-%d"
|
||||
try:
|
||||
datetime.datetime.strptime(value, pattern)
|
||||
return value
|
||||
except ValueError:
|
||||
pass
|
||||
elif isinstance(value, datetime.date):
|
||||
return value.strftime("%Y-%m-%d")
|
||||
raise ValueError("无效的日期时间或字符串数据")
|
||||
|
||||
@classmethod
|
||||
def validate(cls, v):
|
||||
if isinstance(v, str):
|
||||
return v
|
||||
elif isinstance(v, dict):
|
||||
return v.get("$oid")
|
||||
elif isinstance(v, ObjectId):
|
||||
return str(v)
|
||||
return v
|
||||
|
||||
# 实现自定义一个日期字符串的数据类型
|
||||
DateStr = Annotated[
|
||||
str | datetime.date | int | float,
|
||||
AfterValidator(DateStrVali),
|
||||
PlainSerializer(lambda x: x, return_type=str),
|
||||
WithJsonSchema({'type': 'string'}, mode='serialization')
|
||||
]
|
||||
|
||||
|
||||
def ObjectIdStrVali(value: str | dict | ObjectId):
|
||||
"""
|
||||
官方文档:https://docs.pydantic.dev/dev-v2/usage/types/datetime/
|
||||
"""
|
||||
if isinstance(value, str):
|
||||
return value
|
||||
elif isinstance(value, dict):
|
||||
return value.get("$oid")
|
||||
elif isinstance(value, ObjectId):
|
||||
return str(value)
|
||||
raise ValueError("无效的 ObjectId 数据类型")
|
||||
|
||||
|
||||
ObjectIdStr = Annotated[
|
||||
Any, # 这里不能直接使用 any,需要使用 typing.Any
|
||||
AfterValidator(ObjectIdStrVali),
|
||||
PlainSerializer(lambda x: x, return_type=str),
|
||||
WithJsonSchema({'type': 'string'}, mode='serialization')
|
||||
]
|
||||
|
@ -10,7 +10,6 @@
|
||||
类依赖项-官方文档:https://fastapi.tiangolo.com/zh/tutorial/dependencies/classes-as-dependencies/
|
||||
"""
|
||||
|
||||
from typing import List
|
||||
from fastapi import Body
|
||||
import copy
|
||||
|
||||
@ -24,7 +23,7 @@ class QueryParams:
|
||||
self.v_order = params.v_order
|
||||
self.v_order_field = params.v_order_field
|
||||
|
||||
def dict(self, exclude: List[str] = None) -> dict:
|
||||
def dict(self, exclude: list[str] = None) -> dict:
|
||||
result = copy.deepcopy(self.__dict__)
|
||||
if exclude:
|
||||
for item in exclude:
|
||||
@ -34,7 +33,7 @@ class QueryParams:
|
||||
pass
|
||||
return result
|
||||
|
||||
def to_count(self, exclude: List[str] = None) -> dict:
|
||||
def to_count(self, exclude: list[str] = None) -> dict:
|
||||
params = self.dict(exclude=exclude)
|
||||
del params["page"]
|
||||
del params["limit"]
|
||||
@ -59,5 +58,5 @@ class IdList:
|
||||
"""
|
||||
id 列表
|
||||
"""
|
||||
def __init__(self, ids: List[int] = Body(..., title="ID 列表")):
|
||||
def __init__(self, ids: list[int] = Body(..., title="ID 列表")):
|
||||
self.ids = ids
|
||||
|
@ -16,10 +16,11 @@ alibabacloud-tea-util==0.3.8
|
||||
alibabacloud-tea-xml==0.0.2
|
||||
aliyun-python-sdk-core==2.13.36
|
||||
aliyun-python-sdk-kms==2.16.0
|
||||
annotated-types==0.5.0
|
||||
anyio==3.6.2
|
||||
asgiref==3.5.2
|
||||
async-timeout==4.0.2
|
||||
asyncmy==0.2.5
|
||||
asyncmy==0.2.8
|
||||
attrs==22.1.0
|
||||
bcrypt==4.0.1
|
||||
certifi==2022.9.24
|
||||
@ -32,7 +33,7 @@ cryptography==38.0.3
|
||||
dnspython==2.2.1
|
||||
ecdsa==0.18.0
|
||||
et-xmlfile==1.1.0
|
||||
fastapi==0.97.0
|
||||
fastapi==0.100.0
|
||||
frozenlist==1.3.3
|
||||
greenlet==2.0.1
|
||||
gunicorn==20.1.0
|
||||
@ -47,6 +48,7 @@ Mako==1.2.4
|
||||
MarkupSafe==2.1.1
|
||||
motor==3.1.1
|
||||
multidict==6.0.2
|
||||
openai==0.27.4
|
||||
openpyxl==3.0.10
|
||||
orjson==3.8.2
|
||||
oss2==2.16.0
|
||||
@ -55,7 +57,8 @@ Pillow==9.3.0
|
||||
pyasn1==0.4.8
|
||||
pycparser==2.21
|
||||
pycryptodome==3.15.0
|
||||
pydantic==1.10.2
|
||||
pydantic==2.0.3
|
||||
pydantic-core==2.3.0
|
||||
PyJWT==2.6.0
|
||||
pymongo==4.3.3
|
||||
PyMySQL==1.0.2
|
||||
@ -70,8 +73,9 @@ SQLAlchemy==1.4.44
|
||||
SQLAlchemy-Utils==0.38.3
|
||||
SSIM-PIL==1.0.14
|
||||
starlette==0.27.0
|
||||
tqdm==4.65.0
|
||||
typer==0.7.0
|
||||
typing-extensions==4.4.0
|
||||
typing-extensions==4.7.1
|
||||
ua-parser==0.16.1
|
||||
urllib3==1.26.12
|
||||
user-agents==2.2.0
|
||||
|
@ -14,7 +14,6 @@ import datetime
|
||||
import hashlib
|
||||
import os.path
|
||||
import random
|
||||
from typing import List
|
||||
import xlsxwriter
|
||||
from application.settings import TEMP_DIR, TEMP_URL
|
||||
|
||||
@ -45,7 +44,7 @@ class WriteXlsx:
|
||||
self.wb = xlsxwriter.Workbook(self.filename)
|
||||
self.sheet = self.wb.add_worksheet(self.sheet_name)
|
||||
|
||||
def generate_template(self, headers: List[dict] = None, max_row: int = 101) -> None:
|
||||
def generate_template(self, headers: list[dict] = None, max_row: int = 101) -> None:
|
||||
"""
|
||||
生成模板
|
||||
:param headers: 表头
|
||||
|
@ -16,24 +16,22 @@ https://api.ip138.com/ip/?ip=58.16.180.3&datatype=jsonp&token=cc87f3c77747bccbaa
|
||||
aiohttp 异步请求文档:https://docs.aiohttp.org/en/stable/client_quickstart.html
|
||||
"""
|
||||
from aiohttp import TCPConnector
|
||||
|
||||
from application.settings import IP_PARSE_TOKEN, IP_PARSE_ENABLE
|
||||
import aiohttp
|
||||
from core.logger import logger
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class IPLocationOut(BaseModel):
|
||||
ip: Optional[str] = None
|
||||
address: Optional[str] = None
|
||||
country: Optional[str] = None
|
||||
province: Optional[str] = None
|
||||
city: Optional[str] = None
|
||||
county: Optional[str] = None
|
||||
operator: Optional[str] = None
|
||||
postal_code: Optional[str] = None
|
||||
area_code: Optional[str] = None
|
||||
ip: str | None = None
|
||||
address: str | None = None
|
||||
country: str | None = None
|
||||
province: str | None = None
|
||||
city: str | None = None
|
||||
county: str | None = None
|
||||
operator: str | None = None
|
||||
postal_code: str | None = None
|
||||
area_code: str | None = None
|
||||
|
||||
|
||||
class IPManage:
|
||||
|
Loading…
x
Reference in New Issue
Block a user