"""基地与试验地管理 —— 数据模型 两张无 `status` 列的域表,必须显式覆盖 `__table_args__`, 只保留 `created_time` / `is_deleted` 索引(框架基类默认会加 `ix_<表>_status` 索引,但本表无 status 列,不覆盖会建表失败)。 """ from datetime import datetime from sqlalchemy import Float, ForeignKey, Index, Integer, String, Text, text from sqlalchemy.orm import Mapped, mapped_column from app.core.base_model import MappedBase, ModelMixin, UserMixin class BreedingSiteModel(ModelMixin, UserMixin, MappedBase): """育种基地(试验站)主数据表。""" __tablename__ = "bre_site" site_name: Mapped[str] = mapped_column( String(100), nullable=False, unique=True, comment="基地名称" ) address: Mapped[str | None] = mapped_column(String(255), nullable=True, comment="详细地址") area: Mapped[float | None] = mapped_column(Float, nullable=True, comment="基地面积(亩)") longitude: Mapped[float | None] = mapped_column(Float, nullable=True, comment="经度") latitude: Mapped[float | None] = mapped_column(Float, nullable=True, comment="纬度") eco_type: Mapped[str | None] = mapped_column( String(50), nullable=True, comment="生态区类型(如 华北/西北/华东/西南/东北/华南)" ) soil_type: Mapped[str | None] = mapped_column(String(50), nullable=True, comment="土壤类型", default=None) elevation: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="海拔(m)", default=None) remark: Mapped[str | None] = mapped_column(Text, nullable=True, comment="备注") # 注:created_time / is_deleted 已由 ModelMixin 的 index=True 自动建索引 # (ix_bre_site_created_time / ix_bre_site_is_deleted),此处仅补一个 # 复合索引用于数据权限过滤,且必须覆盖基类默认会建的 ix_<表>_status_deleted # (本表无 status 列,不覆盖会引用不存在的列而建表失败)。 __table_args__ = ( Index("ix_bre_site_created_deleted", "created_time", "is_deleted"), ) class BreedingPlotModel(ModelMixin, UserMixin, MappedBase): """试验地块 —— 隶属于某个基地。""" __tablename__ = "bre_plot" site_id: Mapped[int] = mapped_column( Integer, ForeignKey("bre_site.id", ondelete="CASCADE"), nullable=False, index=True, comment="所属基地ID", ) plot_code: Mapped[str] = mapped_column( String(50), nullable=False, comment="地块编号/名称" ) row_orientation: Mapped[str | None] = mapped_column( String(20), nullable=True, comment="行向(南北行/东西行)" ) row_count: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="行数") col_count: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="每行株数") grid_note: Mapped[str | None] = mapped_column(Text, nullable=True, comment="株行距/网格说明") area: Mapped[float | None] = mapped_column(Float, nullable=True, comment="地块面积(亩)") __table_args__ = ( Index("ix_bre_plot_created_deleted", "created_time", "is_deleted"), # 基地内地块编号唯一(仅约束未软删记录,与 service 层查重语义一致) Index( "uniq_bre_plot_site_code", "site_id", "plot_code", unique=True, postgresql_where=text("is_deleted = false"), ), )