model.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. # -*- coding: utf-8 -*-
  2. from typing import TYPE_CHECKING
  3. from datetime import datetime
  4. from sqlalchemy import Boolean, String, Integer, DateTime, ForeignKey
  5. from sqlalchemy.orm import relationship, Mapped, mapped_column
  6. from app.core.base_model import MappedBase, ModelMixin, UserMixin
  7. if TYPE_CHECKING:
  8. from app.api.v1.module_system.dept.model import DeptModel
  9. from app.api.v1.module_system.position.model import PositionModel
  10. from app.api.v1.module_system.role.model import RoleModel
  11. class UserRolesModel(MappedBase):
  12. """
  13. 用户角色关联表
  14. 定义用户与角色的多对多关系
  15. """
  16. __tablename__: str = "sys_user_roles"
  17. __table_args__: dict[str, str] = ({'comment': '用户角色关联表'})
  18. user_id: Mapped[int] = mapped_column(
  19. Integer,
  20. ForeignKey("sys_user.id", ondelete="CASCADE", onupdate="CASCADE"),
  21. primary_key=True,
  22. comment="用户ID"
  23. )
  24. role_id: Mapped[int] = mapped_column(
  25. Integer,
  26. ForeignKey("sys_role.id", ondelete="CASCADE", onupdate="CASCADE"),
  27. primary_key=True,
  28. comment="角色ID"
  29. )
  30. class UserPositionsModel(MappedBase):
  31. """
  32. 用户岗位关联表
  33. 定义用户与岗位的多对多关系
  34. """
  35. __tablename__: str = "sys_user_positions"
  36. __table_args__: dict[str, str] = ({'comment': '用户岗位关联表'})
  37. user_id: Mapped[int] = mapped_column(
  38. Integer,
  39. ForeignKey("sys_user.id", ondelete="CASCADE", onupdate="CASCADE"),
  40. primary_key=True,
  41. comment="用户ID"
  42. )
  43. position_id: Mapped[int] = mapped_column(
  44. Integer,
  45. ForeignKey("sys_position.id", ondelete="CASCADE", onupdate="CASCADE"),
  46. primary_key=True,
  47. comment="岗位ID"
  48. )
  49. class UserModel(ModelMixin, UserMixin):
  50. """
  51. 用户模型
  52. """
  53. __tablename__: str = "sys_user"
  54. __table_args__: dict[str, str] = ({'comment': '用户表'})
  55. __loader_options__: list[str] = ["dept", "roles", "positions", "created_by", "updated_by"]
  56. username: Mapped[str] = mapped_column(String(32), nullable=False, unique=True, comment="用户名/登录账号")
  57. password: Mapped[str] = mapped_column(String(255), nullable=False, comment="密码哈希")
  58. name: Mapped[str] = mapped_column(String(32), nullable=False, comment="昵称")
  59. mobile: Mapped[str | None] = mapped_column(String(11), nullable=True, unique=True, comment="手机号")
  60. email: Mapped[str | None] = mapped_column(String(64), nullable=True, unique=True, comment="邮箱")
  61. gender: Mapped[str | None] = mapped_column(String(1), default='2', nullable=True, comment="性别(0:男 1:女 2:未知)")
  62. avatar: Mapped[str | None] = mapped_column(String(255), nullable=True, comment="头像URL地址")
  63. is_superuser: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False, comment="是否超管")
  64. last_login: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True, comment="最后登录时间")
  65. gitee_login: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="Gitee登录")
  66. github_login: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="Github登录")
  67. wx_login: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="微信登录")
  68. qq_login: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="QQ登录")
  69. dept_id: Mapped[int | None] = mapped_column(
  70. Integer,
  71. ForeignKey('sys_dept.id', ondelete="SET NULL", onupdate="CASCADE"),
  72. nullable=True,
  73. index=True,
  74. comment="部门ID"
  75. )
  76. dept: Mapped["DeptModel | None"] = relationship(
  77. back_populates="users",
  78. foreign_keys=[dept_id],
  79. lazy="selectin"
  80. )
  81. roles: Mapped[list["RoleModel"]] = relationship(
  82. secondary="sys_user_roles",
  83. back_populates="users",
  84. lazy="selectin"
  85. )
  86. positions: Mapped[list["PositionModel"]] = relationship(
  87. secondary="sys_user_positions",
  88. back_populates="users",
  89. lazy="selectin"
  90. )
  91. # 覆盖 UserMixin 的关系定义,显式指定 foreign_keys 避免自引用混淆
  92. created_by: Mapped["UserModel | None"] = relationship(
  93. "UserModel",
  94. foreign_keys="UserModel.created_id",
  95. remote_side="UserModel.id",
  96. lazy="selectin",
  97. uselist=False,
  98. viewonly=True # 防止级联操作
  99. )
  100. updated_by: Mapped["UserModel | None"] = relationship(
  101. "UserModel",
  102. foreign_keys="UserModel.updated_id",
  103. remote_side="UserModel.id",
  104. lazy="selectin",
  105. uselist=False,
  106. viewonly=True # 防止级联操作
  107. )