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

时间:2016-01-23 03:39:21

标签: 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

我遗漏了很多东西,但是可以添加任何可能相关的细节。以这种方式(在我看来)设置它的目的是做以下事情:

  • 每个传感器必须属于一个仪器,但不是每个仪器都必须有一个传感器
  • 所有工具都有数据(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上?我该如何修复和/或改进它?这不是有史以来最糟糕的DB设计吗?

1 个答案:

答案 0 :(得分:1)

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

如果您可以找到一种不需要该类的方法,或者使其成为独立模型而不是SensorData模型的扩展,那么您的问题就会消失。如果要保持模型不变,则可以向SensorData外键添加一个cascade子句,指示数据库删除孤立行而不是抱怨它。我没有测试它以确保这是正确的语法,但我认为你会这样做:

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