from datetime import date from pydantic import BaseModel, ConfigDict, Field, field_validator from app.core.base_schema import BaseQueryParam, BaseSchema, UserByQueryParam, UserBySchema class BreedingGermplasmCreateSchema(BaseModel): """亲本资源新增模型""" cultivar_name: str = Field(..., description="品种/种质名称") variety_type: str | None = Field(default=None, description="变种类型(普通桃/油桃/蟠桃/油蟠桃/黄肉)") origin: str | None = Field(default=None, description="来源") preservation_site: str | None = Field(default=None, description="保存地") avg_fruit_weight: float | None = Field(default=None, ge=0, description="平均果重(g)") ssc: float | None = Field(default=None, ge=0, le=100, description="可溶性固形物(%)") firmness: str | None = Field(default=None, description="硬度") maturity_period: str | None = Field(default=None, description="成熟期(早/中/晚)") flowering_period: str | None = Field(default=None, description="花期(粗粒度5档字典)") bloom_start_date: date | None = Field(default=None, description="花期起始(结构化区间,年际重复)") bloom_end_date: date | None = Field(default=None, description="花期结束(结构化区间,年际重复)") chilling_requirement: int | None = Field(default=None, ge=0, description="需冷量(h)") disease_resistance: str | None = Field(default=None, description="抗病性描述") s_alleles: str | None = Field(default=None, description="S-等位基因(如 S1/S3;Sf=自交亲和型)") can_be_female: bool = Field(default=False, description="可作母本") can_be_male: bool = Field(default=False, description="可作父本") pedigree_note: str | None = Field(default=None, description="系谱备注") photo_path: str | None = Field(default=None, description="照片地址(图片URL)") # ---- 护照块(规格 §4 line 558) ---- accession_no: str | None = Field(default=None, description="登记号(引种/库存登记)") stage: str | None = Field(default=None, description="当前育种阶段(breeding_stage)") generation: str | None = Field(default=None, description="世代(breeding_generation)") storage_type: str | None = Field(default=None, description="保存方式(田间/离体/种子/DNA)") is_rootstock: bool = Field(default=False, description="是否砧木材料") rootstock_id: int | None = Field(default=None, description="砧木材料(自关联种质)") institute_code: str | None = Field(default=None, description="保存机构代码") country_origin: str | None = Field(default=None, description="原产国/原产地") collection_site: str | None = Field(default=None, description="采集地点") acquisition_date: date | None = Field(default=None, description="引种/收集日期") biological_status: str | None = Field(default=None, description="生物学状态(wild/landrace/breeding_line)") breeding_program: str | None = Field(default=None, description="所属育种项目(自由文本)") @field_validator("cultivar_name") @classmethod def validate_cultivar_name(cls, v: str) -> str: v = v.strip() if not v: raise ValueError("品种/种质名称不能为空") if len(v) > 100: raise ValueError("品种/种质名称长度不能超过100个字符") return v class BreedingGermplasmUpdateSchema(BaseModel): """亲本资源更新模型""" cultivar_name: str | None = Field(default=None, description="品种/种质名称") variety_type: str | None = Field(default=None, description="变种类型(普通桃/油桃/蟠桃/油蟠桃/黄肉)") origin: str | None = Field(default=None, description="来源") preservation_site: str | None = Field(default=None, description="保存地") avg_fruit_weight: float | None = Field(default=None, ge=0, description="平均果重(g)") ssc: float | None = Field(default=None, ge=0, le=100, description="可溶性固形物(%)") firmness: str | None = Field(default=None, description="硬度") maturity_period: str | None = Field(default=None, description="成熟期(早/中/晚)") flowering_period: str | None = Field(default=None, description="花期(粗粒度5档字典)") bloom_start_date: date | None = Field(default=None, description="花期起始(结构化区间,年际重复)") bloom_end_date: date | None = Field(default=None, description="花期结束(结构化区间,年际重复)") chilling_requirement: int | None = Field(default=None, ge=0, description="需冷量(h)") disease_resistance: str | None = Field(default=None, description="抗病性描述") s_alleles: str | None = Field(default=None, description="S-等位基因(如 S1/S3;Sf=自交亲和型)") can_be_female: bool | None = Field(default=None, description="可作母本") can_be_male: bool | None = Field(default=None, description="可作父本") pedigree_note: str | None = Field(default=None, description="系谱备注") photo_path: str | None = Field(default=None, description="照片地址(图片URL)") # ---- 护照块(规格 §4 line 558) ---- accession_no: str | None = Field(default=None, description="登记号(引种/库存登记)") stage: str | None = Field(default=None, description="当前育种阶段(breeding_stage)") generation: str | None = Field(default=None, description="世代(breeding_generation)") storage_type: str | None = Field(default=None, description="保存方式(田间/离体/种子/DNA)") is_rootstock: bool | None = Field(default=None, description="是否砧木材料") rootstock_id: int | None = Field(default=None, description="砧木材料(自关联种质)") institute_code: str | None = Field(default=None, description="保存机构代码") country_origin: str | None = Field(default=None, description="原产国/原产地") collection_site: str | None = Field(default=None, description="采集地点") acquisition_date: date | None = Field(default=None, description="引种/收集日期") biological_status: str | None = Field(default=None, description="生物学状态(wild/landrace/breeding_line)") breeding_program: str | None = Field(default=None, description="所属育种项目(自由文本)") class BreedingGermplasmOutSchema(BreedingGermplasmCreateSchema, BaseSchema, UserBySchema): """亲本资源响应模型""" model_config = ConfigDict(from_attributes=True) rootstock_name: str | None = None # 由 Service 层联表填充(砧木材料=cultivar_name) class BreedingGermplasmQueryParam(BaseQueryParam, UserByQueryParam): """亲本资源查询参数""" cultivar_name: str | None = Field(None, description="品种/种质名称", json_schema_extra={"q": "like"}) origin: str | None = Field(None, description="来源", json_schema_extra={"q": "like"}) variety_type: str | None = Field(None, description="变种类型", json_schema_extra={"q": "eq"}) firmness: str | None = Field(None, description="硬度", json_schema_extra={"q": "eq"}) maturity_period: str | None = Field(None, description="成熟期", json_schema_extra={"q": "eq"}) can_be_female: bool | None = Field(None, description="可作母本", json_schema_extra={"q": "eq"}) can_be_male: bool | None = Field(None, description="可作父本", json_schema_extra={"q": "eq"}) accession_no: str | None = Field(None, description="登记号", json_schema_extra={"q": "like"}) stage: str | None = Field(None, description="育种阶段", json_schema_extra={"q": "eq"}) generation: str | None = Field(None, description="世代", json_schema_extra={"q": "eq"}) storage_type: str | None = Field(None, description="保存方式", json_schema_extra={"q": "eq"}) is_rootstock: bool | None = Field(None, description="是否砧木材料", json_schema_extra={"q": "eq"}) biological_status: str | None = Field(None, description="生物学状态", json_schema_extra={"q": "eq"}) breeding_program: str | None = Field(None, description="所属育种项目", json_schema_extra={"q": "like"})