category.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. """方案分类模型。"""
  2. from __future__ import annotations
  3. from sqlalchemy import (
  4. BigInteger,
  5. Boolean,
  6. CheckConstraint,
  7. Computed,
  8. ForeignKey,
  9. Index,
  10. Integer,
  11. String,
  12. UniqueConstraint,
  13. text,
  14. )
  15. from sqlalchemy.orm import Mapped, mapped_column
  16. from dms.database.base import BusinessTableMixin
  17. from dms.extensions import db
  18. class Category(BusinessTableMixin, db.Model):
  19. __tablename__ = "doc_category"
  20. __table_args__ = (
  21. UniqueConstraint(
  22. "category_code",
  23. "active_marker",
  24. name="uq_doc_category_category_code_active",
  25. ),
  26. CheckConstraint(
  27. "category_type IN ('SCENE', 'STYLE', 'SITUATION', 'VERSION', 'OTHER')",
  28. name="category_type",
  29. ),
  30. CheckConstraint(
  31. "status IN ('ENABLED', 'DISABLED')",
  32. name="category_status",
  33. ),
  34. Index(
  35. "ix_doc_category_parent_active_sort",
  36. "parent_id",
  37. "is_deleted",
  38. "sort_no",
  39. ),
  40. Index(
  41. "ix_doc_category_status_active",
  42. "status",
  43. "is_deleted",
  44. ),
  45. Index(
  46. "ix_doc_category_type_active",
  47. "category_type",
  48. "is_deleted",
  49. ),
  50. )
  51. parent_id: Mapped[int | None] = mapped_column(
  52. BigInteger,
  53. ForeignKey("doc_category.id", ondelete="RESTRICT"),
  54. nullable=True,
  55. )
  56. category_code: Mapped[str] = mapped_column(
  57. String(64),
  58. nullable=False,
  59. )
  60. category_name: Mapped[str] = mapped_column(String(128), nullable=False)
  61. category_type: Mapped[str] = mapped_column(
  62. String(32),
  63. nullable=False,
  64. server_default=text("'OTHER'"),
  65. )
  66. category_path: Mapped[str] = mapped_column(String(1000), nullable=False)
  67. sort_no: Mapped[int] = mapped_column(
  68. Integer,
  69. nullable=False,
  70. server_default=text("0"),
  71. )
  72. document_count: Mapped[int] = mapped_column(
  73. Integer,
  74. nullable=False,
  75. server_default=text("0"),
  76. )
  77. status: Mapped[str] = mapped_column(
  78. String(20),
  79. nullable=False,
  80. server_default=text("'ENABLED'"),
  81. )
  82. # 扁平模式:仅一级分类(parent_id IS NULL)有意义。
  83. # true 表示挂在该分类(含子分类)下的主案在前端不展示
  84. # "挂载子方案"与"挂载配套资料"入口;后端挂载接口不强制拒绝(弱约束)。
  85. flat_mode: Mapped[bool] = mapped_column(
  86. Boolean,
  87. nullable=False,
  88. server_default=text("0"),
  89. )
  90. # 类型显示名称:仅一级分类(parent_id IS NULL)有意义。
  91. # 检索结果列表中,该分类(含子分类)下主体方案的类型徽标
  92. # 显示该名称;NULL 表示未设置,回退显示分类名称。
  93. type_display_name: Mapped[str | None] = mapped_column(
  94. String(128),
  95. nullable=True,
  96. )
  97. active_marker: Mapped[int | None] = mapped_column(
  98. Integer,
  99. Computed("IF(is_deleted = 0, 1, NULL)", persisted=False),
  100. nullable=True,
  101. )