Skip to content

Commit e6e5329

Browse files
authored
Optimize sqlalchemy types to simplify compatibility (#870)
* Optimize sqlalchemy types to simplify compatibility * Update TimeZone type comment
1 parent f533de8 commit e6e5329

File tree

25 files changed

+104
-126
lines changed

25 files changed

+104
-126
lines changed

backend/app/admin/crud/crud_dept.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ async def get(self, db: AsyncSession, dept_id: int) -> Dept | None:
2020
:param dept_id: 部门 ID
2121
:return:
2222
"""
23-
return await self.select_model_by_column(db, id=dept_id, del_flag=0)
23+
return await self.select_model_by_column(db, id=dept_id, del_flag=False)
2424

2525
async def get_by_name(self, db: AsyncSession, name: str) -> Dept | None:
2626
"""
@@ -30,7 +30,7 @@ async def get_by_name(self, db: AsyncSession, name: str) -> Dept | None:
3030
:param name: 部门名称
3131
:return:
3232
"""
33-
return await self.select_model_by_column(db, name=name, del_flag=0)
33+
return await self.select_model_by_column(db, name=name, del_flag=False)
3434

3535
async def get_all(
3636
self,
@@ -52,7 +52,7 @@ async def get_all(
5252
:param status: 部门状态
5353
:return:
5454
"""
55-
filters = {'del_flag': 0}
55+
filters = {'del_flag': False}
5656

5757
if name is not None:
5858
filters['name__like'] = f'%{name}%'

backend/app/admin/model/dept.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import sqlalchemy as sa
66

7-
from sqlalchemy.dialects.mysql import TINYINT
87
from sqlalchemy.orm import Mapped, mapped_column, relationship
98

109
from backend.common.model import Base, id_key
@@ -25,9 +24,7 @@ class Dept(Base):
2524
phone: Mapped[str | None] = mapped_column(sa.String(11), default=None, comment='手机')
2625
email: Mapped[str | None] = mapped_column(sa.String(50), default=None, comment='邮箱')
2726
status: Mapped[int] = mapped_column(default=1, comment='部门状态(0停用 1正常)')
28-
del_flag: Mapped[bool] = mapped_column(
29-
sa.INTEGER().with_variant(TINYINT, 'mysql'), default=False, comment='删除标志(0删除 1存在)'
30-
)
27+
del_flag: Mapped[bool] = mapped_column(default=False, comment='删除标志(0删除 1存在)')
3128

3229
# 父级部门一对多
3330
parent_id: Mapped[int | None] = mapped_column(

backend/app/admin/model/login_log.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22

33
import sqlalchemy as sa
44

5-
from sqlalchemy.dialects.mysql import LONGTEXT
65
from sqlalchemy.orm import Mapped, mapped_column
76

8-
from backend.common.model import DataClassBase, TimeZone, id_key
7+
from backend.common.model import DataClassBase, TimeZone, UniversalText, id_key
98
from backend.utils.timezone import timezone
109

1110

@@ -26,7 +25,7 @@ class LoginLog(DataClassBase):
2625
os: Mapped[str | None] = mapped_column(sa.String(50), comment='操作系统')
2726
browser: Mapped[str | None] = mapped_column(sa.String(50), comment='浏览器')
2827
device: Mapped[str | None] = mapped_column(sa.String(50), comment='设备')
29-
msg: Mapped[str] = mapped_column(sa.TEXT().with_variant(LONGTEXT, 'mysql'), comment='提示消息')
28+
msg: Mapped[str] = mapped_column(UniversalText, comment='提示消息')
3029
login_time: Mapped[datetime] = mapped_column(TimeZone, comment='登录时间')
3130
created_time: Mapped[datetime] = mapped_column(
3231
TimeZone,

backend/app/admin/model/menu.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@
44

55
import sqlalchemy as sa
66

7-
from sqlalchemy.dialects.mysql import LONGTEXT
87
from sqlalchemy.orm import Mapped, mapped_column, relationship
98

109
from backend.app.admin.model.m2m import sys_role_menu
11-
from backend.common.model import Base, id_key
10+
from backend.common.model import Base, UniversalText, id_key
1211

1312
if TYPE_CHECKING:
1413
from backend.app.admin.model import Role
@@ -31,10 +30,8 @@ class Menu(Base):
3130
status: Mapped[int] = mapped_column(default=1, comment='菜单状态(0停用 1正常)')
3231
display: Mapped[int] = mapped_column(default=1, comment='是否显示(0否 1是)')
3332
cache: Mapped[int] = mapped_column(default=1, comment='是否缓存(0否 1是)')
34-
link: Mapped[str | None] = mapped_column(
35-
sa.TEXT().with_variant(LONGTEXT, 'mysql'), default=None, comment='外链地址'
36-
)
37-
remark: Mapped[str | None] = mapped_column(sa.TEXT().with_variant(LONGTEXT, 'mysql'), default=None, comment='备注')
33+
link: Mapped[str | None] = mapped_column(UniversalText, default=None, comment='外链地址')
34+
remark: Mapped[str | None] = mapped_column(UniversalText, default=None, comment='备注')
3835

3936
# 父级菜单一对多
4037
parent_id: Mapped[int | None] = mapped_column(

backend/app/admin/model/opera_log.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22

33
import sqlalchemy as sa
44

5-
from sqlalchemy.dialects.mysql import LONGTEXT
65
from sqlalchemy.orm import Mapped, mapped_column
76

8-
from backend.common.model import DataClassBase, TimeZone, id_key
7+
from backend.common.model import DataClassBase, TimeZone, UniversalText, id_key
98
from backend.utils.timezone import timezone
109

1110

@@ -31,7 +30,7 @@ class OperaLog(DataClassBase):
3130
args: Mapped[str | None] = mapped_column(sa.JSON(), comment='请求参数')
3231
status: Mapped[int] = mapped_column(comment='操作状态(0异常 1正常)')
3332
code: Mapped[str] = mapped_column(sa.String(20), insert_default='200', comment='操作状态码')
34-
msg: Mapped[str | None] = mapped_column(sa.TEXT().with_variant(LONGTEXT, 'mysql'), comment='提示消息')
33+
msg: Mapped[str | None] = mapped_column(UniversalText, comment='提示消息')
3534
cost_time: Mapped[float] = mapped_column(insert_default=0.0, comment='请求耗时(ms)')
3635
opera_time: Mapped[datetime] = mapped_column(TimeZone, comment='操作时间')
3736
created_time: Mapped[datetime] = mapped_column(

backend/app/admin/model/role.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@
44

55
import sqlalchemy as sa
66

7-
from sqlalchemy.dialects.mysql import LONGTEXT, TINYINT
87
from sqlalchemy.orm import Mapped, mapped_column, relationship
98

109
from backend.app.admin.model.m2m import sys_role_data_scope, sys_role_menu, sys_user_role
11-
from backend.common.model import Base, id_key
10+
from backend.common.model import Base, UniversalText, id_key
1211

1312
if TYPE_CHECKING:
1413
from backend.app.admin.model import DataScope, Menu, User
@@ -22,10 +21,8 @@ class Role(Base):
2221
id: Mapped[id_key] = mapped_column(init=False)
2322
name: Mapped[str] = mapped_column(sa.String(20), unique=True, comment='角色名称')
2423
status: Mapped[int] = mapped_column(default=1, comment='角色状态(0停用 1正常)')
25-
is_filter_scopes: Mapped[bool] = mapped_column(
26-
sa.INTEGER().with_variant(TINYINT, 'mysql'), default=True, comment='过滤数据权限(0否 1是)'
27-
)
28-
remark: Mapped[str | None] = mapped_column(sa.TEXT().with_variant(LONGTEXT, 'mysql'), default=None, comment='备注')
24+
is_filter_scopes: Mapped[bool] = mapped_column(default=True, comment='过滤数据权限(0否 1是)')
25+
remark: Mapped[str | None] = mapped_column(UniversalText, default=None, comment='备注')
2926

3027
# 角色用户多对多
3128
users: Mapped[list[User]] = relationship(init=False, secondary=sys_user_role, back_populates='roles')

backend/app/admin/model/user.py

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55

66
import sqlalchemy as sa
77

8-
from sqlalchemy.dialects.mysql import TINYINT
9-
from sqlalchemy.dialects.postgresql import BYTEA
108
from sqlalchemy.orm import Mapped, mapped_column, relationship
119

1210
from backend.app.admin.model.m2m import sys_user_role
@@ -28,28 +26,22 @@ class User(Base):
2826
username: Mapped[str] = mapped_column(sa.String(20), unique=True, index=True, comment='用户名')
2927
nickname: Mapped[str] = mapped_column(sa.String(20), comment='昵称')
3028
password: Mapped[str | None] = mapped_column(sa.String(255), comment='密码')
31-
salt: Mapped[bytes | None] = mapped_column(BYTEA(255).with_variant(sa.VARBINARY, 'mysql'), comment='加密盐')
29+
salt: Mapped[bytes | None] = mapped_column(sa.LargeBinary(255), comment='加密盐')
3230
email: Mapped[str | None] = mapped_column(sa.String(50), default=None, unique=True, index=True, comment='邮箱')
3331
phone: Mapped[str | None] = mapped_column(sa.String(11), default=None, comment='手机号')
3432
avatar: Mapped[str | None] = mapped_column(sa.String(255), default=None, comment='头像')
3533
status: Mapped[int] = mapped_column(default=1, index=True, comment='用户账号状态(0停用 1正常)')
36-
is_superuser: Mapped[bool] = mapped_column(
37-
sa.INTEGER().with_variant(TINYINT, 'mysql'), default=False, comment='超级权限(0否 1是)'
38-
)
39-
is_staff: Mapped[bool] = mapped_column(
40-
sa.INTEGER().with_variant(TINYINT, 'mysql'), default=False, comment='后台管理登陆(0否 1是)'
41-
)
42-
is_multi_login: Mapped[bool] = mapped_column(
43-
sa.INTEGER().with_variant(TINYINT, 'mysql'), default=False, comment='是否重复登陆(0否 1是)'
44-
)
34+
is_superuser: Mapped[bool] = mapped_column(default=False, comment='超级权限(0否 1是)')
35+
is_staff: Mapped[bool] = mapped_column(default=False, comment='后台管理登陆(0否 1是)')
36+
is_multi_login: Mapped[bool] = mapped_column(default=False, comment='是否重复登陆(0否 1是)')
4537
join_time: Mapped[datetime] = mapped_column(TimeZone, init=False, default_factory=timezone.now, comment='注册时间')
4638
last_login_time: Mapped[datetime | None] = mapped_column(
4739
TimeZone, init=False, onupdate=timezone.now, comment='上次登录'
4840
)
4941

5042
# 部门用户一对多
5143
dept_id: Mapped[int | None] = mapped_column(
52-
sa.ForeignKey('sys_dept.id', ondelete='SET NULL'), default=None, comment='部门关联ID'
44+
sa.BigInteger, sa.ForeignKey('sys_dept.id', ondelete='SET NULL'), default=None, comment='部门关联ID'
5345
)
5446
dept: Mapped[Dept | None] = relationship(init=False, back_populates='users')
5547

backend/app/task/model/scheduler.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,10 @@
55
import sqlalchemy as sa
66

77
from sqlalchemy import event
8-
from sqlalchemy.dialects.mysql import LONGTEXT, TINYINT
98
from sqlalchemy.orm import Mapped, mapped_column
109

1110
from backend.common.exception import errors
12-
from backend.common.model import Base, TimeZone, id_key
11+
from backend.common.model import Base, TimeZone, UniversalText, id_key
1312
from backend.core.conf import settings
1413
from backend.database.redis import redis_client
1514
from backend.utils.timezone import timezone
@@ -35,15 +34,11 @@ class TaskScheduler(Base):
3534
interval_every: Mapped[int | None] = mapped_column(comment='任务再次运行前的间隔周期数')
3635
interval_period: Mapped[str | None] = mapped_column(sa.String(255), comment='任务运行之间的周期类型')
3736
crontab: Mapped[str | None] = mapped_column(sa.String(50), default='* * * * *', comment='任务运行的 Crontab 计划')
38-
one_off: Mapped[bool] = mapped_column(
39-
sa.INTEGER().with_variant(TINYINT, 'mysql'), default=False, comment='是否仅运行一次'
40-
)
41-
enabled: Mapped[bool] = mapped_column(
42-
sa.INTEGER().with_variant(TINYINT, 'mysql'), default=True, comment='是否启用任务'
43-
)
37+
one_off: Mapped[bool] = mapped_column(default=False, comment='是否仅运行一次')
38+
enabled: Mapped[bool] = mapped_column(default=True, comment='是否启用任务')
4439
total_run_count: Mapped[int] = mapped_column(default=0, comment='任务触发的总次数')
4540
last_run_time: Mapped[datetime | None] = mapped_column(TimeZone, default=None, comment='任务最后触发的时间')
46-
remark: Mapped[str | None] = mapped_column(sa.TEXT().with_variant(LONGTEXT, 'mysql'), default=None, comment='备注')
41+
remark: Mapped[str | None] = mapped_column(UniversalText, default=None, comment='备注')
4742

4843
no_changes: bool = False
4944

backend/app/task/utils/schedulers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ async def get_all_task_schedulers(self) -> dict:
399399
"""获取所有任务调度"""
400400
async with async_db_session() as db:
401401
logger.debug('DatabaseScheduler: Fetching database schedule')
402-
stmt = select(TaskScheduler).where(TaskScheduler.enabled == 1)
402+
stmt = select(TaskScheduler).where(TaskScheduler.enabled == True) # noqa: E712
403403
query = await db.execute(stmt)
404404
schedulers = query.scalars().all()
405405
s = {}

backend/common/model.py

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
from datetime import datetime
22
from typing import Annotated
33

4-
from sqlalchemy import BigInteger, DateTime, TypeDecorator
4+
from sqlalchemy import BigInteger, DateTime, Text, TypeDecorator
5+
from sqlalchemy.dialects.mysql import LONGTEXT
56
from sqlalchemy.ext.asyncio import AsyncAttrs
67
from sqlalchemy.orm import DeclarativeBase, Mapped, MappedAsDataclass, declared_attr, mapped_column
78

9+
from backend.core.conf import settings
810
from backend.utils.snowflake import snowflake
911
from backend.utils.timezone import timezone
1012

@@ -41,16 +43,21 @@
4143
]
4244

4345

44-
# Mixin: 一种面向对象编程概念, 使结构变得更加清晰, `Wiki <https://en.wikipedia.org/wiki/Mixin/>`__
45-
class UserMixin(MappedAsDataclass):
46-
"""用户 Mixin 数据类"""
46+
class UniversalText(TypeDecorator[str]):
47+
"""PostgreSQL、MySQL 兼容性(长)文本类型"""
4748

48-
created_by: Mapped[int] = mapped_column(sort_order=998, comment='创建者')
49-
updated_by: Mapped[int | None] = mapped_column(init=False, default=None, sort_order=998, comment='修改者')
49+
impl = LONGTEXT if settings.DATABASE_TYPE == 'mysql' else Text
50+
cache_ok = True
51+
52+
def process_bind_param(self, value: str | None, dialect) -> str | None: # noqa: ANN001
53+
return value
54+
55+
def process_result_value(self, value: str | None, dialect) -> str | None: # noqa: ANN001
56+
return value
5057

5158

5259
class TimeZone(TypeDecorator[datetime]):
53-
"""时区感知 DateTime"""
60+
"""PostgreSQL、MySQL 兼容性时区感知类型"""
5461

5562
impl = DateTime(timezone=True)
5663
cache_ok = True
@@ -71,6 +78,14 @@ def process_result_value(self, value: datetime | None, dialect) -> datetime | No
7178
return value
7279

7380

81+
# Mixin: 一种面向对象编程概念, 使结构变得更加清晰, `Wiki <https://en.wikipedia.org/wiki/Mixin/>`__
82+
class UserMixin(MappedAsDataclass):
83+
"""用户 Mixin 数据类"""
84+
85+
created_by: Mapped[int] = mapped_column(sort_order=998, comment='创建者')
86+
updated_by: Mapped[int | None] = mapped_column(init=False, default=None, sort_order=998, comment='修改者')
87+
88+
7489
class DateTimeMixin(MappedAsDataclass):
7590
"""日期时间 Mixin 数据类"""
7691

0 commit comments

Comments
 (0)