python - 无法删除涉及继承模型和与 Flask-SQLAlchemy 的关系的行

标签 python mysql flask sqlalchemy flask-sqlalchemy

我(糟糕地)为自己设计了一个涉及许多关系和继承模型的数据库,如下所示:

class Instrument(db.Model):
    __tablename__ = 'instrument'

    id = db.Column(db.Integer, primary_key = True)
    sn = db.Column(db.String(24), unique = True, index = True)
    ...
    data            = db.relationship('Data', backref = 'Instrument', lazy = 'dynamic', cascade = 'all, delete')
    sensors         = db.relationship('Sensor', backref = 'Instrument', lazy = 'dynamic', cascade = 'all, delete')


class Sensor(db.Model):
    __tablename__ = 'sensors'

    id = db.Column(db.Integer, primary_key = True)
    sn = db.Column(db.String(24), unique = True, index = True)
    ...
    data = db.relationship('SensorData', backref = 'Sensor', lazy = 'dynamic', cascade = 'all, delete')
    instr_sn = db.Column(db.String(24), db.ForeignKey('instrument.sn'), index = True)

class SensorTypeB(Sensor):
    __tablename__ = 'sensor_type_b'

    id      = db.Column(db.Integer, db.ForeignKey('sensors.id'), primary_key = True)
    extracolumn = db.Column(db.Float)

    __mapper_args__ = {'polymorphic_identity': 'sensor_type_b'}

    def __init__(self, extracolumn = None, **kwargs):
        super(SensorTypeB, self).__init__(**kwargs)
        self.extracolumn = extracolumn

class Data(db.Model):
    __tablename__ = 'data'

    id  = db.Column(db.Integer, primary_key = True)
    timestamp   = db.Column(db.DateTime)
    value       = db.Column(db.Float)
    parameter   = db.Column(db.String(24), index = True)
    unit        = db.Column(db.String(24))
    flag        = db.Column(db.Boolean)
    instr_sn    = db.Column(db.String(24), db.ForeignKey('instrument.sn'), index = True)


class SensorData(Data):
    __tablename__ = 'sensor_data'

    id  = db.Column(db.Integer, db.ForeignKey('data.id'), primary_key = True)
    sensor_sn = db.Column(db.String(24), db.ForeignKey('sensors.sn'), index = True)

    __mapper_args__ = {'polymorphic_identity': 'sensor_data'}

    def __init__(self, sensor_sn, **kwargs):
        super(SensorData, self).__init__(**kwargs)

        self.sensor_sn  = sensor_sn

class MetSensorData(SensorData):
    __tablename__ = 'met_sensor_data'

    id  = db.Column(db.Integer, db.ForeignKey('sensor_data.id'), primary_key = True)
    raw = db.Column(db.Float)

    __mapper_args__ = {'polymorphic_identity': 'met_sensor_data'}

    def __init__(self, raw = None, **kwargs):
        super(MetSensorData, self).__init__(**kwargs)

        self.raw = raw

为简洁起见,我省略了一大块……但可以添加任何可能相关的细节。以这种方式设置它的目的(在我看来)是为了执行以下操作:

  • 每个传感器都必须属于一个仪器,但不是每个仪器都必须有一个传感器
  • 所有 Instruments 都有数据(Instrument.data)
  • 所有传感器都有数据(Sensor.data)
  • 传感器模型的子类有数据(SensorTypeB.data)

一切都按预期工作,直到我尝试从数据库中删除数据点。它在使用 SQLite3 的单元测试中工作得非常好,但是一旦我将它移动到 MySQL,一切都会因类型错误而中断:

IntegrityError: (_mysql_exceptions.IntegrityError) (1451, 'Cannot delete or update a parent row: a foreign key constraint fails (`db_name`.`met
_sensor_data`, CONSTRAINT `met_sensor_data_ibfk_1` FOREIGN KEY (`id`) REFERENCES `sensor_data` (`id`))') [SQL: u'DELETE FROM sensor_data WHE
RE sensor_data.id = %s'] [parameters: (3L,)]

为什么这只发生在 MySQL 而不是 SQLite 上?我该如何修复和/或改进它?这不是有史以来最糟糕的数据库设计吗?

最佳答案

您得到的错误是告诉您您正在尝试删除 SensorData 行,但在这样做时,MetSensorData 中引用它的条目将是孤儿,并且由于 SQLAlchemy 配置 SensorDataMetSensorData 之间关系的方式,MetSensorData 中的孤儿是不允许的。

如果您能找到不需要该类的方法,或者使其成为独立模型而不是 SensorData 模型的扩展,那么您的问题就会消失。如果您想保持模型不变,那么您可以向 SensorData 外键添加一个级联子句,指示数据库删除孤立行而不是提示它。我尚未对其进行测试以确保这是正确的语法,但我认为您可以按如下方式进行:

id  = db.Column(db.Integer, db.ForeignKey('sensor_data.id', ondelete='CASCADE'), primary_key = True)

关于python - 无法删除涉及继承模型和与 Flask-SQLAlchemy 的关系的行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34959326/

相关文章:

python - Django InspectDB 为 MySQL Mediumblob 生成 TextField

python - 查询的值在 Jinja 中显示为元组,但应该是单个字符串

python - 检测 flask 是否正在通过 gunicorn 运行?

php - Web 应用程序转换为桌面应用程序

php - SQL 语法错误 SELECT

python - 如何解码python flask中的dataTables Editor表单?

python - 连接 pandas 数据框时出错

python - 如何将 PyTorch 中的 torchscript 模型转换为普通的 nn.Module?

python - 在输出之前打印 pexpect 是带有\r\n 的单行,而不是实际的 CR/LF 输出

python - django.db.utils.InterfaceError : (0, '' )