model.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. from sqlalchemy import Boolean, ForeignKey, Integer, String
  2. from sqlalchemy.orm import Mapped, mapped_column, relationship, validates
  3. from sqlalchemy.sql import expression
  4. from app.config.setting import settings
  5. from app.core.base_model import ModelMixin, UserMixin
  6. from app.utils.common_util import SqlalchemyUtil
  7. class GenTableModel(ModelMixin, UserMixin):
  8. """
  9. 代码生成表
  10. """
  11. __tablename__: str = "gen_table"
  12. __table_args__: dict[str, str] = {"comment": "代码生成表"}
  13. __loader_options__: list[str] = ["columns", "created_by", "updated_by"]
  14. table_name: Mapped[str] = mapped_column(
  15. String(200), nullable=False, default="", comment="表名称"
  16. )
  17. table_comment: Mapped[str | None] = mapped_column(String(500), nullable=True, comment="表描述")
  18. class_name: Mapped[str] = mapped_column(
  19. String(100), nullable=False, default="", comment="实体类名称"
  20. )
  21. package_name: Mapped[str | None] = mapped_column(
  22. String(100), nullable=True, comment="生成包路径"
  23. )
  24. module_name: Mapped[str | None] = mapped_column(String(30), nullable=True, comment="生成模块名")
  25. business_name: Mapped[str | None] = mapped_column(
  26. String(30), nullable=True, comment="生成业务名"
  27. )
  28. function_name: Mapped[str | None] = mapped_column(
  29. String(100), nullable=True, comment="生成功能名"
  30. )
  31. sub_table_name: Mapped[str | None] = mapped_column(
  32. String(64),
  33. nullable=True,
  34. server_default=SqlalchemyUtil.get_server_default_null(settings.DATABASE_TYPE),
  35. comment="关联子表的表名",
  36. )
  37. sub_table_fk_name: Mapped[str | None] = mapped_column(
  38. String(64),
  39. nullable=True,
  40. server_default=SqlalchemyUtil.get_server_default_null(settings.DATABASE_TYPE),
  41. comment="子表关联的外键名",
  42. )
  43. parent_menu_id: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="父菜单ID")
  44. # 关联关系
  45. columns: Mapped[list["GenTableColumnModel"]] = relationship(
  46. order_by="GenTableColumnModel.sort",
  47. back_populates="table",
  48. cascade="all, delete-orphan",
  49. )
  50. @validates("table_name")
  51. def validate_table_name(self, key: str, table_name: str) -> str:
  52. """
  53. 验证表名非空并去首尾空格。
  54. 参数:
  55. - key (str): 字段名。
  56. - table_name (str): 表名。
  57. 返回:
  58. - str: 规范化后的表名。
  59. 异常:
  60. - ValueError: 表名为空时抛出。
  61. """
  62. if not table_name or not table_name.strip():
  63. raise ValueError("表名称不能为空")
  64. return table_name.strip()
  65. @validates("class_name")
  66. def validate_class_name(self, key: str, class_name: str) -> str:
  67. """
  68. 验证实体类名非空并去首尾空格。
  69. 参数:
  70. - key (str): 字段名。
  71. - class_name (str): 类名。
  72. 返回:
  73. - str: 规范化后的类名。
  74. 异常:
  75. - ValueError: 类名为空时抛出。
  76. """
  77. if not class_name or not class_name.strip():
  78. raise ValueError("实体类名称不能为空")
  79. return class_name.strip()
  80. class GenTableColumnModel(ModelMixin, UserMixin):
  81. """
  82. 代码生成表字段
  83. 数据隔离策略:
  84. - 继承自GenTableModel的隔离级别
  85. - 不需要customer_id
  86. 用于存储代码生成器的字段配置
  87. """
  88. __tablename__: str = "gen_table_column"
  89. __table_args__: dict[str, str] = {"comment": "代码生成表字段"}
  90. __loader_options__: list[str] = ["created_by", "updated_by"]
  91. # 数据库设计表字段
  92. column_name: Mapped[str] = mapped_column(String(200), nullable=False, comment="列名称")
  93. column_comment: Mapped[str | None] = mapped_column(String(500), nullable=True, comment="列描述")
  94. column_type: Mapped[str] = mapped_column(String(100), nullable=False, comment="列类型")
  95. column_length: Mapped[str | None] = mapped_column(String(50), nullable=True, comment="列长度")
  96. column_default: Mapped[str | None] = mapped_column(
  97. String(200), nullable=True, comment="列默认值"
  98. )
  99. is_pk: Mapped[bool] = mapped_column(
  100. Boolean,
  101. nullable=False,
  102. default=False,
  103. server_default=expression.false(),
  104. comment="是否主键",
  105. )
  106. is_increment: Mapped[bool] = mapped_column(
  107. Boolean,
  108. nullable=False,
  109. default=False,
  110. server_default=expression.false(),
  111. comment="是否自增",
  112. )
  113. is_nullable: Mapped[bool] = mapped_column(
  114. Boolean,
  115. nullable=False,
  116. default=True,
  117. server_default=expression.true(),
  118. comment="是否允许为空",
  119. )
  120. is_unique: Mapped[bool] = mapped_column(
  121. Boolean,
  122. nullable=False,
  123. default=False,
  124. server_default=expression.false(),
  125. comment="是否唯一",
  126. )
  127. # Python字段映射
  128. python_type: Mapped[str | None] = mapped_column(
  129. String(100), nullable=True, comment="Python类型"
  130. )
  131. python_field: Mapped[str | None] = mapped_column(
  132. String(200), nullable=True, comment="Python字段名"
  133. )
  134. # 序列化配置
  135. is_insert: Mapped[bool] = mapped_column(
  136. Boolean,
  137. nullable=False,
  138. default=True,
  139. server_default=expression.true(),
  140. comment="是否为新增字段",
  141. )
  142. is_edit: Mapped[bool] = mapped_column(
  143. Boolean,
  144. nullable=False,
  145. default=True,
  146. server_default=expression.true(),
  147. comment="是否编辑字段",
  148. )
  149. is_list: Mapped[bool] = mapped_column(
  150. Boolean,
  151. nullable=False,
  152. default=True,
  153. server_default=expression.true(),
  154. comment="是否列表字段",
  155. )
  156. is_query: Mapped[bool] = mapped_column(
  157. Boolean,
  158. nullable=False,
  159. default=False,
  160. server_default=expression.false(),
  161. comment="是否查询字段",
  162. )
  163. query_type: Mapped[str | None] = mapped_column(
  164. String(50), nullable=True, default=None, comment="查询方式"
  165. )
  166. # 前端展示配置
  167. html_type: Mapped[str | None] = mapped_column(
  168. String(100), nullable=True, default="input", comment="显示类型"
  169. )
  170. dict_type: Mapped[str | None] = mapped_column(
  171. String(200), nullable=True, default="", comment="字典类型"
  172. )
  173. # 排序和扩展配置
  174. sort: Mapped[int] = mapped_column(Integer, nullable=False, default=0, comment="排序")
  175. # 归属关系
  176. table_id: Mapped[int] = mapped_column(
  177. Integer,
  178. ForeignKey("gen_table.id", ondelete="CASCADE"),
  179. nullable=False,
  180. index=True,
  181. comment="归属表编号",
  182. )
  183. # 关联关系
  184. table: Mapped["GenTableModel"] = relationship(back_populates="columns")
  185. @validates("column_name")
  186. def validate_column_name(self, key: str, column_name: str) -> str:
  187. """
  188. 验证列名非空并去首尾空格。
  189. 参数:
  190. - key (str): 字段名。
  191. - column_name (str): 列名。
  192. 返回:
  193. - str: 规范化后的列名。
  194. 异常:
  195. - ValueError: 列名为空时抛出。
  196. """
  197. if not column_name or not column_name.strip():
  198. raise ValueError("列名称不能为空")
  199. return column_name.strip()
  200. @validates("column_type")
  201. def validate_column_type(self, key: str, column_type: str) -> str:
  202. """
  203. 验证列类型非空并去首尾空格。
  204. 参数:
  205. - key (str): 字段名。
  206. - column_type (str): 列类型字符串。
  207. 返回:
  208. - str: 规范化后的列类型。
  209. 异常:
  210. - ValueError: 列类型为空时抛出。
  211. """
  212. if not column_type or not column_type.strip():
  213. raise ValueError("列类型不能为空")
  214. return column_type.strip()