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