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

更新数据库连接信息加载方式,使用dotenv从配置文件中读取环境变量;
为五万亩调查数据表及其列添加注释;
更新文档以包含数据库备份与恢复操作说明;
删除不再使用的uninstall.txt文件。

drggboy 1 долоо хоног өмнө
parent
commit
3ba8b7d417

+ 33 - 4
PROJECT_RULES.md

@@ -298,7 +298,8 @@ class FarmlandData(Base):
     @param {float} type - 用地类型:旱地(0)、水田(1)、水浇地(2)
     """
     __tablename__ = 'Farmland_data'
-    
+    __table_args__ = {'comment': '农田样点空间位置与索引数据模型'}
+
     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)
@@ -361,9 +362,37 @@ sqlacodegen postgresql://postgres:123456789Qq@localhost/soilgd --tables table1,t
 - `python db_migrate.py history` - 显示迁移历史
 - `python db_migrate.py stamp head` - 标记数据库版本
 
-**其他数据库操作**:
-- `python reset_db.py` - 重置数据库
-- `psql -U postgres -d soilgd -f soilgd.sql` - 从备份文件恢复数据库
+**数据库备份与恢复**:
+
+### 备份操作
+```bash
+# 自定义格式(推荐,文件小,支持选择性恢复)
+pg_dump -U postgres -Fc soilgd > soilgd.dump
+
+# SQL文本格式(兼容性好,可读性强)
+pg_dump -U postgres soilgd > soilgd.sql
+```
+
+### 导入操作
+```bash
+# 导入自定义格式备份
+createdb -U postgres soilgd
+pg_restore -U postgres -d soilgd soilgd.dump
+
+# 导入SQL文本格式备份
+createdb -U postgres soilgd
+psql -U postgres -d soilgd -f soilgd.sql
+```
+
+### 快速参考
+| 导出格式 | 导出命令 | 导入命令 |
+|---------|---------|---------|
+| 自定义格式 | `pg_dump -Fc` | `pg_restore` |
+| SQL文本 | `pg_dump` | `psql` |
+
+### 注意事项
+- 格式必须匹配:`pg_dump -Fc` 导出 → `pg_restore` 导入
+
 
 #### 5.2.4 数据导入脚本开发规范
 

+ 103 - 100
app/models/orm_models.py

@@ -33,108 +33,111 @@ class PointInformation(Base):
 
 
 class FiftyThousandSurveyDatum(Base):
+    """
+    五万亩调查数据
+    """
     __tablename__ = 'fifty_thousand_survey_data'
+    __table_args__ = {'comment': '五万亩调查数据表'}
 
-    gid = Column(Integer, primary_key=True, autoincrement=True)
-    id = Column(Float(53))
-    dwmc = Column(String(254))
-    r_dwmc = Column(String(254))
-    lat = Column(Float(53))
-    lon = Column(Float(53))
-    xmc = Column(String(254))
-    zmc = Column(String(254))
-    cmc = Column(String(254))
-    tql_cd = Column(Float(53))
-    tql_as = Column(Float(53))
-    tql_pb = Column(Float(53))
-    ph = Column(Float(53))
-    zzm_cd = Column(Float(53))
-    zzm_as = Column(Float(53))
-    zzm_pb = Column(Float(53))
-    wzm_cd = Column(Float(53))
-    wzm_as = Column(Float(53))
-    wzm_pb = Column(Float(53))
-    tcb_cd = Column(Float(53))
-    tcb_as = Column(Float(53))
-    tcb_pb = Column(Float(53))
-    mcb_cd = Column(Float(53))
-    mcb_as = Column(Float(53))
-    mcb_pb = Column(Float(53))
-    tzs_cd = Column(Float(53))
-    tzs_as = Column(Float(53))
-    tzs_pb = Column(Float(53))
-    z_mzs_cd = Column(Float(53))
-    z_mzs_as = Column(Float(53))
-    z_mzs_pb = Column(Float(53))
-    w_mzs_cd = Column(Float(53))
-    w_mzs_as = Column(Float(53))
-    w_mzs_pb = Column(Float(53))
-    tzs_max = Column(Float(53))
-    mzs_max = Column(Float(53))
-    s_tfj_max = Column(Float(53))
-    s_mfj_max = Column(Float(53))
-    h_tfj_max = Column(Float(53))
-    h_mfj_max = Column(Float(53))
-    s_pdtj = Column(String(254))
-    h_pdtj = Column(String(254))
-    s_xtfx = Column(String(254))
-    h_xtfx = Column(String(254))
-    mzs_cd_max = Column(Float(53))
-    mzs_as_max = Column(Float(53))
-    mzs_pd_max = Column(Float(53))
-    tzs_cd_fj = Column(Float(53))
-    tzs_as_fj = Column(Float(53))
-    tzs_pb_fj = Column(Float(53))
-    mzs_cd_fj = Column(Float(53))
-    mzs_as_fj = Column(Float(53))
-    mzs_pb_fj = Column(Float(53))
-    s_cd_pdtj = Column(String(254))
-    s_cd_pdtj1 = Column(String(254))
-    s_pb_pdtj = Column(String(254))
-    s_cd_xtfx = Column(String(254))
-    s_as_xtfx = Column(String(254))
-    s_pb_xtfx = Column(String(254))
-    s_cd_fz = Column(Float(53))
-    s_as_fz = Column(Float(53))
-    cd_as_pdtj = Column(String(254))
-    cd_as_fhwr = Column(String(254))
-    wrlx = Column(String(254))
-    wrlx_pb = Column(String(254))
-    cec__cmol_ = Column(Float(53))
-    tom_g_kg_ = Column(Float(53))
-    mmax_cd = Column(Float(53))
-    mmax_as = Column(Float(53))
-    mmax_pb = Column(Float(53))
-    bcf_cd = Column(Float(53))
-    bcf_as = Column(Float(53))
-    bcf_pb = Column(Float(53))
-    nl_g_kg_ = Column(Float(53))
-    fl_g_kg_ = Column(Float(53))
-    sl_g_kg_ = Column(Float(53))
-    nl_zb = Column(Float(53))
-    fl_zb = Column(Float(53))
-    sl_zb = Column(Float(53))
-    trlx = Column(String(254))
-    dtpa_cd = Column(Float(53))
-    lin_suan_er_qing_an = Column(Float(53))
-    dtpa_pb = Column(Float(53))
-    zb_cd = Column(Float(53))
-    zb_as = Column(Float(53))
-    zb_pb = Column(Float(53))
-    tql_cr = Column(Float(53))
-    tql_hg = Column(Float(53))
-    f_2_00mm = Column(String(254))
-    _2_1mm = Column('2_1mm', Float(53))
-    _1_0_5mm = Column('1_0_5mm', Float(53))
-    _0_5_0_25mm = Column('0_5_0_25mm', Float(53))
-    _0_25_0_05m = Column('0_25_0_05m', Float(53))
-    _0_05_0_02m = Column('0_05_0_02m', Float(53))
-    _0_02_0_002 = Column('0_02_0_002', Float(53))
-    f_0_002mm = Column(Float(53))
-    ph_fj = Column(Float(53))
-    ph_fj_2 = Column(Float(53))
-    geom = Column(Geometry('POINT', from_text='ST_GeomFromEWKT', name='geometry'), index=True)
-
+    gid = Column(Integer, primary_key=True, autoincrement=True, comment='主键ID')
+    id = Column(Float(53), comment='编号')
+    dwmc = Column(String(254), comment='点位原始编码')
+    r_dwmc = Column(String(254), comment='点位重编码')
+    lat = Column(Float(53), comment='位置信息-纬度')
+    lon = Column(Float(53), comment='位置信息-经度')
+    xmc = Column(String(254), comment='位置信息-县名称')
+    zmc = Column(String(254), comment='位置信息-镇名称')
+    cmc = Column(String(254), comment='位置信息-村名称')
+    tql_cd = Column(Float(53), comment='土壤单全量-镉(mg/kg)')
+    tql_as = Column(Float(53), comment='土壤单全量-砷(mg/kg)')
+    tql_pb = Column(Float(53), comment='土壤单全量-铅(mg/kg)')
+    ph = Column(Float(53), comment='pH值')
+    zzm_cd = Column(Float(53), comment='早稻米-镉(mg/kg)')
+    zzm_as = Column(Float(53), comment='早稻米-砷(mg/kg)')
+    zzm_pb = Column(Float(53), comment='早稻米-铅(mg/kg)')
+    wzm_cd = Column(Float(53), comment='晚稻米-镉(mg/kg)')
+    wzm_as = Column(Float(53), comment='晚稻米-砷(mg/kg)')
+    wzm_pb = Column(Float(53), comment='晚稻米-铅(mg/kg)')
+    tcb_cd = Column(Float(53), comment='土壤参比值-镉(mg/kg)')
+    tcb_as = Column(Float(53), comment='土壤参比值-砷(mg/kg)')
+    tcb_pb = Column(Float(53), comment='土壤参比值-铅(mg/kg)')
+    mcb_cd = Column(Float(53), comment='稻米参比值-镉(mg/kg)')
+    mcb_as = Column(Float(53), comment='稻米参比值-砷(mg/kg)')
+    mcb_pb = Column(Float(53), comment='稻米参比值-铅(mg/kg)')
+    tzs_cd = Column(Float(53), comment='土壤指数-镉(mg/kg)')
+    tzs_as = Column(Float(53), comment='土壤指数-砷(mg/kg)')
+    tzs_pb = Column(Float(53), comment='土壤指数-铅(mg/kg)')
+    z_mzs_cd = Column(Float(53), comment='早造米指数-镉(mg/kg)')
+    z_mzs_as = Column(Float(53), comment='早造米指数-砷(mg/kg)')
+    z_mzs_pb = Column(Float(53), comment='早造米指数-铅(mg/kg)')
+    w_mzs_cd = Column(Float(53), comment='晚造米指数-镉(mg/kg)')
+    w_mzs_as = Column(Float(53), comment='晚造米指数-砷(mg/kg)')
+    w_mzs_pb = Column(Float(53), comment='晚造米指数-铅(mg/kg)')
+    tzs_max = Column(Float(53), comment='土壤综合指数')
+    mzs_max = Column(Float(53), comment='稻米综合指数')
+    s_tfj_max = Column(Float(53), comment='综合指数分级')
+    s_mfj_max = Column(Float(53), comment='综合指数分级')
+    h_tfj_max = Column(Float(53), comment='环保97号文土壤指数分级')
+    h_mfj_max = Column(Float(53), comment='环保98号文稻米指数分级')
+    s_pdtj = Column(String(254), comment='综合风险等级代码')
+    h_pdtj = Column(String(254), comment='土壤环境质量类别代码')
+    s_xtfx = Column(String(254), comment='综合风险等级')
+    h_xtfx = Column(String(254), comment='土壤环境质量类别')
+    mzs_cd_max = Column(Float(53), comment='单金属最大米指数')
+    mzs_as_max = Column(Float(53), comment='单金属最大米指数')
+    mzs_pd_max = Column(Float(53), comment='单金属最大米指数')
+    tzs_cd_fj = Column(Float(53), comment='按土壤指数分级')
+    tzs_as_fj = Column(Float(53), comment='按土壤指数分级')
+    tzs_pb_fj = Column(Float(53), comment='按土壤指数分级')
+    mzs_cd_fj = Column(Float(53), comment='按稻米指数分级')
+    mzs_as_fj = Column(Float(53), comment='按稻米指数分级')
+    mzs_pb_fj = Column(Float(53), comment='按稻米指数分级')
+    s_cd_pdtj = Column(String(254), comment='单金属风险代码')
+    s_cd_pdtj1 = Column(String(254), comment='单金属风险代码')
+    s_pb_pdtj = Column(String(254), comment='单金属风险代码')
+    s_cd_xtfx = Column(String(254), comment='单金属协同风险等级')
+    s_as_xtfx = Column(String(254), comment='单金属协同风险等级')
+    s_pb_xtfx = Column(String(254), comment='单金属协同风险等级')
+    s_cd_fz = Column(Float(53), comment='镉分风险分级')
+    s_as_fz = Column(Float(53), comment='砷分风险分级')
+    cd_as_pdtj = Column(String(254), comment='镉-砷复合污染分级代码')
+    cd_as_fhwr = Column(String(254), comment='镉-砷复合污染分级代码')
+    wrlx = Column(String(254), comment='镉-砷复合污染分级')
+    wrlx_pb = Column(String(254), comment='铅是否有风险')
+    cec__cmol_ = Column(Float(53), comment='阳离子交换容量(cmol/kg)')
+    tom_g_kg_ = Column(Float(53), comment='土壤有机质(g/kg)')
+    mmax_cd = Column(Float(53), comment='单金属稻米最大值')
+    mmax_as = Column(Float(53), comment='单金属稻米最大值')
+    mmax_pb = Column(Float(53), comment='单金属稻米最大值')
+    bcf_cd = Column(Float(53), comment='稻米富集系数')
+    bcf_as = Column(Float(53), comment='稻米富集系数')
+    bcf_pb = Column(Float(53), comment='稻米富集系数')
+    nl_g_kg_ = Column(Float(53), comment='粘粒')
+    fl_g_kg_ = Column(Float(53), comment='粘粒')
+    sl_g_kg_ = Column(Float(53), comment='粘粒')
+    nl_zb = Column(Float(53), comment='黏粒占比')
+    fl_zb = Column(Float(53), comment='粉粒占比')
+    sl_zb = Column(Float(53), comment='砂粒占比')
+    trlx = Column(String(254), comment='土壤质地')
+    dtpa_cd = Column(Float(53), comment='土壤单金属提取态')
+    lin_suan_er_qing_an = Column(Float(53), comment='土壤单金属提取态')
+    dtpa_pb = Column(Float(53), comment='土壤单金属提取态')
+    zb_cd = Column(Float(53), comment='土壤单金v属提取态占比')
+    zb_as = Column(Float(53), comment='土壤单金属提取态占比')
+    zb_pb = Column(Float(53), comment='土壤单金属提取态占比')
+    tql_cr = Column(Float(53), comment='土壤单金属全量')
+    tql_hg = Column(Float(53), comment='土壤单金属全量')
+    f_2_00mm = Column(String(254), comment='土壤机械组成数据>2.00mm粒径分布')
+    _2_1mm = Column('2_1mm', Float(53), comment='土壤机械组成数据2-1mm粒径分布')
+    _1_0_5mm = Column('1_0_5mm', Float(53), comment='土壤机械组成数据1-0.5mm粒径分布')
+    _0_5_0_25mm = Column('0_5_0_25mm', Float(53), comment='土壤机械组成数据0.5-0.25mm粒径分布')
+    _0_25_0_05m = Column('0_25_0_05m', Float(53), comment='土壤机械组成数据0.25-0.05mm粒径分布')
+    _0_05_0_02m = Column('0_05_0_02m', Float(53), comment='土壤机械组成数据0.05-0.02mm粒径分布')
+    _0_02_0_002 = Column('0_02_0_002', Float(53), comment='土壤机械组成数据0.02-0.002mm粒径分布')
+    f_0_002mm = Column(Float(53), comment='土壤机械组成数据<0.002mm粒径分布')
+    ph_fj = Column(Float(53), comment='pH值分级1')
+    ph_fj_2 = Column(Float(53), comment='pH值分级2')
+    geom = Column(Geometry('POINT', from_text='ST_GeomFromEWKT', name='geometry'), index=True, comment='几何位置信息')
 
 class RasterTable(Base):
     __tablename__ = 'raster_table'

+ 10 - 6
db_migrate.py

@@ -15,12 +15,16 @@ import traceback
 from alembic.config import Config
 from alembic import command
 
-# 直接设置环境变量,确保所有地方使用相同的数据库连接信息
-os.environ["DB_USER"] = "postgres"
-os.environ["DB_PASSWORD"] = "scau2025"
-os.environ["DB_HOST"] = "localhost"
-os.environ["DB_PORT"] = "5432"
-os.environ["DB_NAME"] = "data_db"
+# 加载环境变量配置
+from dotenv import load_dotenv
+load_dotenv("config.env")
+
+# 从环境变量获取数据库连接信息,如果没有则使用默认值
+os.environ["DB_USER"] = os.getenv("DB_USER", "postgres")
+os.environ["DB_PASSWORD"] = os.getenv("DB_PASSWORD", "123456789Qq")
+os.environ["DB_HOST"] = os.getenv("DB_HOST", "localhost")
+os.environ["DB_PORT"] = os.getenv("DB_PORT", "5432")
+os.environ["DB_NAME"] = os.getenv("DB_NAME", "soilgd")
 
 def get_alembic_config():
     """

+ 238 - 0
migrations/versions/5e763f8e3da6_五万亩模型添加comment.py

@@ -0,0 +1,238 @@
+"""五万亩模型添加comment
+
+Revision ID: 5e763f8e3da6
+Revises: a2cfbc6c2673
+Create Date: 2025-07-13 10:28:20.629961
+
+"""
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = '5e763f8e3da6'
+down_revision = 'a2cfbc6c2673'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+    """升级数据库到当前版本"""
+    # ### commands auto generated by Alembic - please adjust! ###
+    
+    # 为五万亩调查数据表添加comment
+    op.execute("COMMENT ON TABLE fifty_thousand_survey_data IS '五万亩调查数据表'")
+    
+    # 为五万亩调查数据表的列添加comment
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.gid IS '主键ID'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.id IS '编号'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.dwmc IS '点位原始编码'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.r_dwmc IS '点位重编码'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.lat IS '位置信息-纬度'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.lon IS '位置信息-经度'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.xmc IS '位置信息-县名称'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.zmc IS '位置信息-镇名称'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.cmc IS '位置信息-村名称'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tql_cd IS '土壤单全量-镉(mg/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tql_as IS '土壤单全量-砷(mg/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tql_pb IS '土壤单全量-铅(mg/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.ph IS 'pH值'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.zzm_cd IS '早稻米-镉(mg/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.zzm_as IS '早稻米-砷(mg/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.zzm_pb IS '早稻米-铅(mg/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.wzm_cd IS '晚稻米-镉(mg/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.wzm_as IS '晚稻米-砷(mg/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.wzm_pb IS '晚稻米-铅(mg/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tcb_cd IS '土壤参比值-镉(mg/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tcb_as IS '土壤参比值-砷(mg/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tcb_pb IS '土壤参比值-铅(mg/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mcb_cd IS '稻米参比值-镉(mg/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mcb_as IS '稻米参比值-砷(mg/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mcb_pb IS '稻米参比值-铅(mg/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tzs_cd IS '土壤指数-镉(mg/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tzs_as IS '土壤指数-砷(mg/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tzs_pb IS '土壤指数-铅(mg/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.z_mzs_cd IS '早造米指数-镉(mg/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.z_mzs_as IS '早造米指数-砷(mg/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.z_mzs_pb IS '早造米指数-铅(mg/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.w_mzs_cd IS '晚造米指数-镉(mg/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.w_mzs_as IS '晚造米指数-砷(mg/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.w_mzs_pb IS '晚造米指数-铅(mg/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tzs_max IS '土壤综合指数'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mzs_max IS '稻米综合指数'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.s_tfj_max IS '综合指数分级'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.s_mfj_max IS '综合指数分级'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.h_tfj_max IS '环保97号文土壤指数分级'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.h_mfj_max IS '环保98号文稻米指数分级'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.s_pdtj IS '综合风险等级代码'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.h_pdtj IS '土壤环境质量类别代码'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.s_xtfx IS '综合风险等级'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.h_xtfx IS '土壤环境质量类别'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mzs_cd_max IS '单金属最大米指数'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mzs_as_max IS '单金属最大米指数'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mzs_pd_max IS '单金属最大米指数'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tzs_cd_fj IS '按土壤指数分级'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tzs_as_fj IS '按土壤指数分级'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tzs_pb_fj IS '按土壤指数分级'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mzs_cd_fj IS '按稻米指数分级'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mzs_as_fj IS '按稻米指数分级'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mzs_pb_fj IS '按稻米指数分级'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.s_cd_pdtj IS '单金属风险代码'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.s_cd_pdtj1 IS '单金属风险代码'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.s_pb_pdtj IS '单金属风险代码'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.s_cd_xtfx IS '单金属协同风险等级'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.s_as_xtfx IS '单金属协同风险等级'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.s_pb_xtfx IS '单金属协同风险等级'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.s_cd_fz IS '镉分风险分级'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.s_as_fz IS '砷分风险分级'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.cd_as_pdtj IS '镉-砷复合污染分级代码'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.cd_as_fhwr IS '镉-砷复合污染分级代码'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.wrlx IS '镉-砷复合污染分级'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.wrlx_pb IS '铅是否有风险'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.cec__cmol_ IS '阳离子交换容量(cmol/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tom_g_kg_ IS '土壤有机质(g/kg)'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mmax_cd IS '单金属稻米最大值'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mmax_as IS '单金属稻米最大值'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mmax_pb IS '单金属稻米最大值'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.bcf_cd IS '稻米富集系数'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.bcf_as IS '稻米富集系数'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.bcf_pb IS '稻米富集系数'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.nl_g_kg_ IS '粘粒'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.fl_g_kg_ IS '粘粒'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.sl_g_kg_ IS '粘粒'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.nl_zb IS '黏粒占比'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.fl_zb IS '粉粒占比'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.sl_zb IS '砂粒占比'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.trlx IS '土壤质地'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.dtpa_cd IS '土壤单金属提取态'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.lin_suan_er_qing_an IS '土壤单金属提取态'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.dtpa_pb IS '土壤单金属提取态'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.zb_cd IS '土壤单金v属提取态占比'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.zb_as IS '土壤单金属提取态占比'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.zb_pb IS '土壤单金属提取态占比'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tql_cr IS '土壤单金属全量'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tql_hg IS '土壤单金属全量'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.f_2_00mm IS '土壤机械组成数据>2.00mm粒径分布'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.\"2_1mm\" IS '土壤机械组成数据2-1mm粒径分布'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.\"1_0_5mm\" IS '土壤机械组成数据1-0.5mm粒径分布'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.\"0_5_0_25mm\" IS '土壤机械组成数据0.5-0.25mm粒径分布'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.\"0_25_0_05m\" IS '土壤机械组成数据0.25-0.05mm粒径分布'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.\"0_05_0_02m\" IS '土壤机械组成数据0.05-0.02mm粒径分布'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.\"0_02_0_002\" IS '土壤机械组成数据0.02-0.002mm粒径分布'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.f_0_002mm IS '土壤机械组成数据<0.002mm粒径分布'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.ph_fj IS 'pH值分级1'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.ph_fj_2 IS 'pH值分级2'")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.geom IS '几何位置信息'")
+    
+    # ### end Alembic commands ###
+
+
+def downgrade():
+    """将数据库降级到上一版本"""
+    # ### commands auto generated by Alembic - please adjust! ###
+    
+    # 移除五万亩调查数据表的comment
+    op.execute("COMMENT ON TABLE fifty_thousand_survey_data IS NULL")
+    
+    # 移除五万亩调查数据表的列comment
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.gid IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.id IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.dwmc IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.r_dwmc IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.lat IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.lon IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.xmc IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.zmc IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.cmc IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tql_cd IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tql_as IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tql_pb IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.ph IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.zzm_cd IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.zzm_as IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.zzm_pb IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.wzm_cd IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.wzm_as IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.wzm_pb IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tcb_cd IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tcb_as IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tcb_pb IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mcb_cd IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mcb_as IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mcb_pb IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tzs_cd IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tzs_as IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tzs_pb IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.z_mzs_cd IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.z_mzs_as IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.z_mzs_pb IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.w_mzs_cd IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.w_mzs_as IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.w_mzs_pb IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tzs_max IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mzs_max IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.s_tfj_max IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.s_mfj_max IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.h_tfj_max IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.h_mfj_max IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.s_pdtj IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.h_pdtj IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.s_xtfx IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.h_xtfx IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mzs_cd_max IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mzs_as_max IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mzs_pd_max IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tzs_cd_fj IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tzs_as_fj IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tzs_pb_fj IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mzs_cd_fj IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mzs_as_fj IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mzs_pb_fj IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.s_cd_pdtj IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.s_cd_pdtj1 IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.s_pb_pdtj IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.s_cd_xtfx IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.s_as_xtfx IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.s_pb_xtfx IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.s_cd_fz IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.s_as_fz IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.cd_as_pdtj IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.cd_as_fhwr IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.wrlx IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.wrlx_pb IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.cec__cmol_ IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tom_g_kg_ IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mmax_cd IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mmax_as IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.mmax_pb IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.bcf_cd IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.bcf_as IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.bcf_pb IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.nl_g_kg_ IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.fl_g_kg_ IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.sl_g_kg_ IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.nl_zb IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.fl_zb IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.sl_zb IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.trlx IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.dtpa_cd IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.lin_suan_er_qing_an IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.dtpa_pb IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.zb_cd IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.zb_as IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.zb_pb IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tql_cr IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.tql_hg IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.f_2_00mm IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.\"2_1mm\" IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.\"1_0_5mm\" IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.\"0_5_0_25mm\" IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.\"0_25_0_05m\" IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.\"0_05_0_02m\" IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.\"0_02_0_002\" IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.f_0_002mm IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.ph_fj IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.ph_fj_2 IS NULL")
+    op.execute("COMMENT ON COLUMN fifty_thousand_survey_data.geom IS NULL")
+    
+    # ### end Alembic commands ###

+ 10 - 6
reset_db.py

@@ -18,12 +18,16 @@ from sqlalchemy.ext.declarative import declarative_base
 logging.basicConfig(level=logging.INFO)
 logger = logging.getLogger(__name__)
 
-# 数据库连接信息
-DB_USER = "postgres"
-DB_PASSWORD = "scau2025"
-DB_HOST = "localhost"
-DB_PORT = "5432"
-DB_NAME = "soilgd"
+# 加载环境变量配置
+from dotenv import load_dotenv
+load_dotenv("config.env")
+
+# 从环境变量获取数据库连接信息,如果没有则使用默认值
+DB_USER = os.getenv("DB_USER", "postgres")
+DB_PASSWORD = os.getenv("DB_PASSWORD", "123456789Qq")
+DB_HOST = os.getenv("DB_HOST", "localhost")
+DB_PORT = os.getenv("DB_PORT", "5432")
+DB_NAME = os.getenv("DB_NAME", "soilgd")
 print(f"连接到数据库: {DB_USER}@{DB_HOST}:{DB_PORT}/{DB_NAME}")
 
 # 构建数据库连接URL

BIN
uninstall.txt