使用SQLAlchemy和SQLite插入数据时project_id字段不存在错误求助
问题描述
我正在开发一个记录工时的简易应用,采用SQLAlchemy和SQLite作为数据库。以下是我的model.py代码:
from infra.base import Base from sqlalchemy.orm import relationship from sqlalchemy import Column, String, Integer, Float, ForeignKey # class TaskFact - main table class TaskFact(Base): __tablename__ = 'task_fact' task_id = Column(Integer, primary_key=True, autoincrement=True) task_date = Column(String) task_description = Column(String) task_hours = Column(Float) is_ccr = Column(Integer) project_id = Column(String, ForeignKey('project_dim.project_id')) def __repr__(self): return f'{self.date} - {self.task_description} - {self.project_code_fk}' # class ProjectDim - project dimension table class ProjectDim(Base): __tablename__ = 'project_dim' project_id = Column(String, primary_key=True) project_alias = Column(String, nullable=False) project_official_name = Column(String, nullable=True) project_category = Column(String, nullable=True) project_corporate_segment = Column(String, nullable=True) tasks = relationship('TaskFact', backref='tasks')
我编写了TaskFactRepository类用于向TaskFact表插入数据:
from .models import * from infra.database_factory import DatabaseFactory class TaskFactRepository: def insert_new_task(self, date: str, description: str, hour: float, is_ccr: str, project_code_fk: str) -> None: """ inserts a new task in the task table :param date: date of the task :type date: str :param description: description of the task :type description: str :param hour: time spent in the task :type hour: float :param is_ccr: indication if the activity is CCR :type is_ccr: str :param project_code_fk: code of the project related to task :type project_code_fk: str """ with DatabaseFactory() as db: try: data = TaskFact( task_date=date, task_description=description, task_hours=hour, is_ccr=is_ccr, project_id=project_code_fk ) db.session.add(data) db.session.commit() except Exception as e: db.session.rollback() raise e
但执行测试代码时触发错误:sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) table task_fact has no column named project_id。测试代码如下:
from repository.task_fact_repository import TaskFactRepository from repository.project_repository import ProjectDimensionRepository # create repo object db_proj = ProjectDimensionRepository() db_task = TaskFactRepository() # test task insertion db_task.insert_new_task( date='2023-01-03', description='XXXXXXXXXXXXXXXXXXXXXXXXXXX', hour=9.5, is_ccr='True', project_code_fk='XXXXXXXXX' )
请问我哪里遗漏了?
问题分析与解决
出现这个错误的核心原因是SQLite数据库中的task_fact表实际没有project_id列,和你的模型定义不一致。以下是具体排查和修复步骤:
1. 同步数据库表与模型结构
SQLAlchemy不会自动修改已存在的数据库表结构。如果是先创建了task_fact表,之后才在TaskFact模型中添加project_id字段,旧表不会自动新增该列。
解决方式:
- 开发阶段快速修复:直接删除现有的SQLite数据库文件(如
app.db),然后重新运行表初始化逻辑(调用Base.metadata.create_all(engine)),会根据最新模型生成包含project_id列的新表。 - 需保留数据时:通过SQLite工具(如sqlite3命令行、DB Browser for SQLite)执行SQL手动添加列:
ALTER TABLE task_fact ADD COLUMN project_id VARCHAR;
2. 检查数据库初始化逻辑
确保DatabaseFactory初始化时,已正确导入所有模型类(TaskFact和ProjectDim),并且执行了Base.metadata.create_all(engine)来创建所有表。如果模型未被正确加载,create_all不会生成对应的列。
3. 修复数据类型不匹配问题
TaskFact模型中is_ccr是Integer类型,但插入时传入的是字符串'True',后续会触发类型错误。需修改传入值为整数:
# 测试代码中把is_ccr='True'改为 is_ccr=1 # 用1表示True,0表示False
额外优化建议
TaskFact的__repr__方法引用了不存在的self.date和self.project_code_fk,会导致AttributeError,修正为:def __repr__(self): return f'{self.task_date} - {self.task_description} - {self.project_id}'ProjectDim中的relationship定义的backref='tasks'易混淆,建议改为更清晰的名称,比如backref='project',这样TaskFact实例可通过task.project直接关联到对应ProjectDim对象。
内容的提问来源于stack exchange,提问作者Ícaro Augusto Maccari Zelioli
相关产品推荐
相关产品推荐

