Эх сурвалжийг харах

新建farmland orm模型;生成迁移脚本;说明文档添加数据库改动描述

drggboy 1 өдөр өмнө
parent
commit
8399184335

+ 164 - 32
PROJECT_RULES.md

@@ -37,7 +37,7 @@
 - 矢量数据处理 (Vector Data Processing)  
 - 空间数据查询和分析
 - GIS数据导入导出
-- **Cd预测模型分析 (Cd Prediction Analysis)** ✨新增
+- Cd预测模型分析 (Cd Prediction Analysis)
   - 作物Cd含量预测
   - 有效态Cd含量预测
   - 预测结果可视化
@@ -51,24 +51,25 @@ AcidMap/
 │   ├── api/               # API路由层
 │   │   ├── raster.py      # 栅格数据接口
 │   │   ├── vector.py      # 矢量数据接口
-│   │   └── cd_prediction.py # Cd预测模型接口 ✨新增
+│   │   └── cd_prediction.py # Cd预测模型接口
 │   ├── services/          # 业务逻辑层
 │   │   ├── raster_service.py
 │   │   ├── vector_service.py
-│   │   └── cd_prediction_service.py # Cd预测业务服务 ✨新增
+│   │   └── cd_prediction_service.py # Cd预测业务服务
 │   ├── models/            # 数据模型层
 │   │   ├── base.py        # 基础模型
 │   │   ├── orm_models.py  # ORM模型
 │   │   ├── raster.py      # 栅格数据模型
 │   │   ├── vector.py      # 矢量数据模型
-│   │   └── county.py      # 县域数据模型
+│   │   ├── county.py      # 县域数据模型
+│   │   └── farmland.py    # 农田样点数据模型
 │   ├── utils/             # 工具函数
 │   │   ├── file_validators.py
-│   │   └── cd_prediction_wrapper.py # Cd预测系统包装器 ✨新增
-│   ├── config/            # 配置管理 ✨新增
+│   │   └── cd_prediction_wrapper.py # Cd预测系统包装器
+│   ├── config/            # 配置管理
 │   │   ├── __init__.py
 │   │   └── cd_prediction_config.py # Cd预测配置管理
-│   ├── static/            # 静态文件 ✨新增
+│   ├── static/            # 静态文件
 │   │   └── cd_predictions/ # Cd预测输出文件
 │   │       ├── figures/    # 地图和直方图
 │   │       ├── raster/     # 栅格文件
@@ -78,7 +79,7 @@ AcidMap/
 │   ├── scripts/           # 脚本文件
 │   ├── database.py        # 数据库配置
 │   └── main.py           # FastAPI应用入口
-├── Cd_Prediction_Integrated_System/ # Cd预测系统 ✨新增
+├── Cd_Prediction_Integrated_System/ # Cd预测系统
 │   ├── models/            # 预测模型
 │   │   ├── crop_cd_model/
 │   │   └── effective_cd_model/
@@ -98,9 +99,9 @@ AcidMap/
 ├── soilgd.sql           # 数据库备份文件
 ├── db_migrate.py        # 数据库迁移脚本
 ├── reset_db.py          # 数据库重置脚本
-├── test_cd_integration.py # Cd集成测试脚本 ✨新增
-├── INTEGRATION_GUIDE.md  # 集成使用指南 ✨新增
-├── CD_INTEGRATION_SUMMARY.md # 集成总结文档 ✨新增
+├── test_cd_integration.py # Cd集成测试脚本
+├── INTEGRATION_GUIDE.md  # 集成使用指南
+├── CD_INTEGRATION_SUMMARY.md # 集成总结文档
 └── main.py              # 应用启动入口
 ```
 
@@ -109,7 +110,7 @@ AcidMap/
 2. **Service层 (app/services/)**: 业务逻辑处理,数据转换,调用Model层
 3. **Model层 (app/models/)**: 数据模型定义,数据库操作
 4. **Utils层 (app/utils/)**: 通用工具函数,验证器等
-5. **Config层 (app/config/)**: 配置管理,环境设置 ✨新增
+5. **Config层 (app/config/)**: 配置管理,环境设置
 
 ## 3. 开发规范
 
@@ -163,7 +164,7 @@ from .services import RasterService
 #### 3.2.1 路由组织
 - 栅格数据: `/api/raster/*`
 - 矢量数据: `/api/vector/*`
-- **Cd预测分析: `/api/cd-prediction/*`** ✨新增
+- **Cd预测分析: `/api/cd-prediction/*`**
 - 使用RESTful设计原则
 
 #### 3.2.2 HTTP状态码
@@ -199,7 +200,7 @@ from .services import RasterService
 #### 3.3.3 迁移管理
 - 使用Alembic进行数据库迁移
 
-### 3.4 可视化规范 ✨新增
+### 3.4 可视化规范
 
 #### 3.4.1 分辨率设置
 - **默认DPI**: 300 (标准分辨率输出)
@@ -238,18 +239,22 @@ from .services import RasterService
 ### 4.2 API路由层
 - **栅格API (api/raster.py)**: 处理栅格数据的CRUD操作
 - **矢量API (api/vector.py)**: 处理矢量数据的CRUD操作
-- **Cd预测API (api/cd_prediction.py)**: 处理Cd预测模型的调用和结果获取 ✨新增
+- **Cd预测API (api/cd_prediction.py)**: 处理Cd预测模型的调用和结果获取
 
 ### 4.3 业务服务层
 - **RasterService**: 栅格数据业务逻辑
 - **VectorService**: 矢量数据业务逻辑
-- **CdPredictionService**: Cd预测分析业务逻辑 ✨新增
+- **CdPredictionService**: Cd预测分析业务逻辑
 
 ### 4.4 数据模型层
 - **ORM模型**: 数据库表映射
+  - RasterData: 栅格数据模型
+  - VectorData: 矢量数据模型
+  - Counties: 县域地理数据模型
+  - FarmlandData: 农田样点空间位置与索引数据模型
 - **Pydantic模型**: API输入输出验证
 
-### 4.5 Cd预测系统组件 ✨新增
+### 4.5 Cd预测系统组件
 - **CdPredictionWrapper**: Cd预测系统包装器
 - **CdPredictionConfig**: Cd预测配置管理
 - **作物Cd预测模型**: 基于神经网络的作物Cd含量预测
@@ -264,13 +269,140 @@ from .services import RasterService
 4. **API层开发**: 实现HTTP接口
 5. **测试**: 单元测试和集成测试
 6. **文档更新**: 更新API文档和代码注释
-7. **规则文件更新**: 更新PROJECT_RULES.md中的相关规范 ✨新增
+7. **规则文件更新**: 更新PROJECT_RULES.md中的相关规范
 
 ### 5.2 数据库变更流程
-1. 修改ORM模型
-2. 生成迁移文件: `alembic revision --autogenerate -m "描述"`
-3. 执行迁移: `alembic upgrade head`
-4. 更新数据库备份文件
+
+#### 5.2.1 数据库表格添加标准流程
+
+**第一步: 创建/修改 ORM 模型**
+1. 在 `app/models/` 目录下创建或编辑模型文件
+2. 定义SQLAlchemy ORM模型类,继承Base类
+3. 确保在 `app/models/__init__.py` 中导入新模型
+
+```python
+# 实际案例: 农田数据模型
+# app/models/farmland.py
+from sqlalchemy import Column, Integer, Float
+from geoalchemy2 import Geometry
+from app.database import Base  # 统一的Base导入
+
+class FarmlandData(Base):
+    """
+    农田样点空间位置与索引数据模型
+    
+    @param {int} farmland_id - 区域农业用地矢量点编号(主键)
+    @param {int} sample_id - 采样自增的ID(主键+自增)
+    @param {float} lon - 经度
+    @param {float} lan - 纬度
+    @param {float} type - 用地类型:旱地(0)、水田(1)、水浇地(2)
+    """
+    __tablename__ = 'Farmland_data'
+    
+    farmland_id = Column('Farmland_ID', Integer, primary_key=True)
+    sample_id = Column('Sample_ID', Integer, primary_key=True, autoincrement=True)
+    lon = Column('lon', Float, nullable=True)
+    lan = Column('lan', Float, nullable=True)
+    type = Column('Type', Float, nullable=True)
+    geom = Column(Geometry('POINT', srid=4326))
+```
+
+**第二步: 使用迁移脚本生成迁移文件**
+```bash
+# 使用项目自带的迁移脚本
+python db_migrate.py create "添加新数据表"
+
+# 或直接使用alembic命令
+alembic revision --autogenerate -m "添加新数据表"
+```
+
+**第三步: 检查生成的迁移文件**
+1. 查看 `migrations/versions/` 目录下新生成的迁移文件
+2. 验证迁移内容是否正确
+3. 必要时手动调整迁移脚本
+
+**第四步: 执行数据库迁移**
+```bash
+# 使用项目迁移脚本
+python db_migrate.py upgrade
+
+# 或直接使用alembic命令  
+alembic upgrade head
+```
+
+**第五步: 验证迁移结果**
+```bash
+# 查看当前数据库版本
+python db_migrate.py current
+
+# 查看迁移历史
+python db_migrate.py history
+```
+
+#### 5.2.2 使用sqlacodegen反向生成模型 (可选)
+
+当需要从现有数据库表生成ORM模型时:
+
+```bash
+# 反向生成所有表的模型
+sqlacodegen postgresql://postgres:123456789Qq@localhost/soilgd > models.py
+
+# 生成特定表的模型
+sqlacodegen postgresql://postgres:123456789Qq@localhost/soilgd --tables table1,table2 > specific_models.py
+```
+
+#### 5.2.3 数据库脚本命令参考
+
+**db_migrate.py 脚本命令**:
+- `python db_migrate.py create "描述"` - 创建新迁移
+- `python db_migrate.py upgrade` - 升级到最新版本
+- `python db_migrate.py downgrade` - 降级到上一版本
+- `python db_migrate.py current` - 显示当前版本
+- `python db_migrate.py history` - 显示迁移历史
+- `python db_migrate.py stamp head` - 标记数据库版本
+
+**其他数据库操作**:
+- `python reset_db.py` - 重置数据库
+- `psql -U postgres -d soilgd -f soilgd.sql` - 从备份文件恢复数据库
+
+#### 5.2.4 GeoJSON数据导入流程
+
+对于地理空间数据的导入:
+
+1. **准备GeoJSON文件**: 确保文件格式正确
+2. **创建地理空间模型**: 使用GeoAlchemy2定义几何字段
+3. **编写导入脚本**: 
+   ```python
+   # 示例: scripts/import_geojson.py
+   import geopandas as gpd
+   from app.models import YourGeoModel
+   from app.database import SessionLocal
+   
+   def import_geojson_data(file_path: str):
+       """导入GeoJSON数据到数据库"""
+       gdf = gpd.read_file(file_path)
+       db = SessionLocal()
+       try:
+           for _, row in gdf.iterrows():
+               record = YourGeoModel(
+                   name=row['name'],
+                   geometry=row['geometry'].wkt
+               )
+               db.add(record)
+           db.commit()
+       finally:
+           db.close()
+   ```
+4. **执行导入**: `python scripts/import_geojson.py`
+
+#### 5.2.5 注意事项
+- 备份数据库后再执行迁移
+- 在开发环境先测试迁移
+- 保持迁移文件的版本控制
+- 迁移失败时及时回滚
+- **Base类统一性**:所有模型必须使用`app.database`中的同一个Base实例
+  - ❌ 错误:`from .base import Base`(会创建独立的Base)
+  - ✅ 正确:`from app.database import Base`(使用统一的Base)
 
 ### 5.3 代码提交规范
 - feat: 新功能
@@ -278,9 +410,9 @@ from .services import RasterService
 - docs: 文档更新
 - refactor: 代码重构
 - test: 测试相关
-- **integrate: 系统集成** ✨新增
+- **integrate: 系统集成**
 
-### 5.4 Cd预测功能开发流程 ✨新增
+### 5.4 Cd预测功能开发流程
 1. **模型验证**: 确保Cd预测系统完整性
 2. **包装器开发**: 创建系统调用包装器
 3. **服务层集成**: 实现异步预测服务
@@ -293,7 +425,7 @@ from .services import RasterService
 ### 6.1 开发环境要求
 - Python 3.8+
 - PostgreSQL 12+ (with PostGIS)
-- **Cd预测系统依赖**: ✨新增
+- **Cd预测系统依赖**:
   - PyTorch >= 1.9.0
   - scikit-learn >= 1.0.0
   - geopandas >= 0.10.0
@@ -335,7 +467,7 @@ python test_cd_integration.py
 - 文件大小限制
 - 恶意文件检测
 
-### 7.4 Cd预测系统安全 ✨新增
+### 7.4 Cd预测系统安全
 - 预测任务超时控制 (5分钟)
 - 输出文件访问权限管理
 - 敏感路径信息隐藏
@@ -353,7 +485,7 @@ python test_cd_integration.py
 - 缓存策略
 - 分页处理
 
-### 8.3 Cd预测性能优化 ✨新增
+### 8.3 Cd预测性能优化
 - 异步任务处理 (asyncio)
 - CPU密集型任务线程池执行
 - 预测结果文件缓存
@@ -371,7 +503,7 @@ python test_cd_integration.py
 - 分级别记录日志
 - 敏感信息脱敏
 
-### 9.3 Cd预测错误处理 ✨新增
+### 9.3 Cd预测错误处理
 - 预测系统完整性检查
 - 依赖包缺失检测
 - 预测超时异常处理
@@ -389,7 +521,7 @@ python test_cd_integration.py
 - 测试数据隔离
 - 数据清理策略
 
-### 10.3 Cd预测测试规范 ✨新增
+### 10.3 Cd预测测试规范
 - 配置模块测试
 - 包装器功能测试
 - API端点注册验证
@@ -407,13 +539,13 @@ python test_cd_integration.py
 - 错误日志监控
 - 数据库性能监控
 
-### 11.3 Cd预测部署特殊要求 ✨新增
+### 11.3 Cd预测部署特殊要求
 - 确保Cd_Prediction_Integrated_System目录完整
 - 验证地理空间库安装 (fiona, pyogrio)
 - 配置预测输出目录权限
 - 监控预测任务执行时间
 
-## 12. API文档规范 ✨新增
+## 12. API文档规范
 
 ### 12.1 Cd预测API端点
 
@@ -435,7 +567,7 @@ GET  /api/cd-prediction/crop-cd/download-histogram
 GET  /api/cd-prediction/effective-cd/download-histogram
 ```
 
-### 12.2 一键接口特点 ✨新增
+### 12.2 一键接口特点
 - **即时响应**: 生成完成后直接返回图片文件
 - **简化操作**: 无需分两步操作,一次调用完成
 - **适用场景**: 前端直接显示、浏览器预览、快速下载

+ 2 - 1
app/models/__init__.py

@@ -1,4 +1,5 @@
 from app.models.orm_models import *
 from app.models.vector import *
 from app.models.raster import *
-from app.models.county import *  # 导入新的县级地理数据模型 
+from app.models.county import *  # 导入新的县级地理数据模型
+from app.models.farmland import *  # 导入农田数据模型 

+ 71 - 0
app/models/farmland.py

@@ -0,0 +1,71 @@
+"""
+农田数据模型
+
+定义Farmland_data表的ORM模型,用于存储耕地样点空间位置与索引数据
+"""
+
+from sqlalchemy import Column, Integer, Float, ForeignKey
+from geoalchemy2 import Geometry
+from app.database import Base
+
+
+class FarmlandData(Base):
+    """
+    耕地样点空间位置与索引数据模型
+    
+    @param {int} farmland_id - 区域农业用地矢量点编号(主键)
+    @param {int} sample_id - 采样自增的ID(主键+外键+自增)
+    @param {float} lon - 经度
+    @param {float} lan - 纬度
+    @param {float} type - 用地类型,旱地(0)、水田(1)、水浇地(2)
+    @param {geometry} geom - 点几何对象(使用PostGIS,基于经纬度生成)
+    """
+    __tablename__ = 'Farmland_data'
+    
+    # 主键字段 - 保持与原表结构完全一致的大小写
+    farmland_id = Column('Farmland_ID', Integer, primary_key=True, comment='区域农业用地矢量点编号')
+    sample_id = Column('Sample_ID', Integer, primary_key=True, autoincrement=True, comment='采样自增的ID')
+    
+    # 地理坐标字段 - 保持原始大小写
+    lon = Column('lon', Float, nullable=True, comment='经度')
+    lan = Column('lan', Float, nullable=True, comment='纬度')
+    
+    # 用地类型字段 - 保持原始大小写
+    type = Column('Type', Float, nullable=True, comment='用地类型:旱地(0)、水田(1)、水浇地(2)')
+    
+    # 使用PostGIS几何字段存储点位置(可选,便于空间查询)
+    geom = Column(Geometry('POINT', srid=4326), comment='点几何对象')
+    
+    def __repr__(self):
+        return f"<FarmlandData(farmland_id={self.farmland_id}, sample_id={self.sample_id}, " \
+               f"lon={self.lon}, lan={self.lan}, type={self.type})>"
+    
+    @property
+    def land_type_name(self):
+        """
+        获取用地类型名称
+        
+        @returns {str} 用地类型名称
+        """
+        type_mapping = {
+            0.0: "旱地",
+            1.0: "水田", 
+            2.0: "水浇地"
+        }
+        return type_mapping.get(self.type, "未知类型")
+    
+    def to_dict(self):
+        """
+        转换为字典格式
+        
+        @returns {dict} 包含所有字段的字典
+        """
+        return {
+            'farmland_id': self.farmland_id,
+            'sample_id': self.sample_id,
+            'lon': self.lon,
+            'lan': self.lan,
+            'type': self.type,
+            'land_type_name': self.land_type_name,
+            'geom': str(self.geom) if self.geom else None
+        } 

+ 67 - 0
migrations/versions/beeaf68d0ee1_creat_farmland_orm.py

@@ -0,0 +1,67 @@
+"""creat_farmland_orm
+
+Revision ID: beeaf68d0ee1
+Revises: f0d12e4fab12
+Create Date: 2025-06-14 17:07:57.976453
+
+"""
+from alembic import op
+import sqlalchemy as sa
+import geoalchemy2
+
+
+# revision identifiers, used by Alembic.
+revision = 'beeaf68d0ee1'
+down_revision = 'f0d12e4fab12'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+    """升级数据库到当前版本"""
+    # ### commands auto generated by Alembic - please adjust! ###
+    
+    # 检查表是否已存在,如果不存在才创建
+    connection = op.get_bind()
+    inspector = sa.inspect(connection)
+    
+    if 'Farmland_data' not in inspector.get_table_names():
+        op.create_table('Farmland_data',
+        sa.Column('Farmland_ID', sa.Integer(), nullable=False, comment='区域农业用地矢量点编号'),
+        sa.Column('Sample_ID', sa.Integer(), autoincrement=True, nullable=False, comment='采样自增的ID'),
+        sa.Column('lon', sa.Float(), nullable=True, comment='经度'),
+        sa.Column('lan', sa.Float(), nullable=True, comment='纬度'),
+        sa.Column('Type', sa.Float(), nullable=True, comment='用地类型:旱地(0)、水田(1)、水浇地(2)'),
+        sa.Column('geom', geoalchemy2.types.Geometry(geometry_type='POINT', srid=4326, from_text='ST_GeomFromEWKT', name='geometry'), nullable=True, comment='点几何对象'),
+        sa.PrimaryKeyConstraint('Farmland_ID', 'Sample_ID')
+        )
+    
+    # 使用原生SQL安全创建索引
+    try:
+        op.execute('CREATE INDEX IF NOT EXISTS idx_Farmland_data_geom ON "Farmland_data" USING gist (geom)')
+    except Exception as e:
+        print(f"索引创建警告: {e}")
+    
+    # ### end Alembic commands ###
+
+
+def downgrade():
+    """将数据库降级到上一版本"""
+    # ### commands auto generated by Alembic - please adjust! ###
+    
+    # 安全地删除索引和表,检查存在性
+    connection = op.get_bind()
+    inspector = sa.inspect(connection)
+    
+    if 'Farmland_data' in inspector.get_table_names():
+        # 检查索引是否存在,存在才删除
+        indexes = inspector.get_indexes('Farmland_data')
+        index_names = [idx['name'] for idx in indexes]
+        
+        if 'idx_Farmland_data_geom' in index_names:
+            op.drop_index('idx_Farmland_data_geom', table_name='Farmland_data', postgresql_using='gist')
+            
+        # 删除表
+        op.drop_table('Farmland_data')
+    
+    # ### end Alembic commands ###