我有2个模型(sqlalchemy 0.9)相互引用(简化和整数作为id)
class Device(SyncableModel):
__tablename__ = 'devices'
...
id = db.Column(db.Integer, primary_key=True)
current_program_id = db.Column(db.Integer, db.ForeignKey('programs.id', use_alter=True, name='fk_current_program'))
current_program = relationship(
'Program', backref = backref('current_for_device', uselist=False),
primaryjoin="Device.current_program_id==Program.id",
post_update=True
)
programs = relationship(
'Program', backref='device', lazy='joined',
cascade="all, delete-orphan",
primaryjoin="Device.id==Program.device_id"
)
class Program(SyncableModel):
__tablename__ = 'programs'
...
id = db.Column(db.Integer, primary_key=True)
device_id = db.Column(db.Integer, db.ForeignKey('devices.id', ondelete='CASCADE'))
name = db.Column(db.String(64))
我需要做到这一点:
device = Device()
device.id = 1
program = Program()
program.id = 2
program.device_id = device.id
device.current_program_id = program.id
db.session.add_all([device, program,])
db.session.commit()
但我得到了:
IntegrityError: (IntegrityError) (1452, 'Cannot add or update a child row: a foreign key constraint fails (`cloud2`.`devices`, CONSTRAINT `fk_current_program` FOREIGN KEY (`current_program_id`) REFERENCES `programs` (`id`))') 'UPDATE devices SET created=%s, updated=%s, name=%s, rain_detected=%s, current_program_id=%s, timezone=%s, synced=%s WHERE devices.id = %s' (datetime.datetime(2015, 8, 11, 19, 48, 23), datetime.datetime(2015, 8, 11, 19, 48, 26), 'nWhosie', 0, '\xeaL\xff\x80\xe5\xffC2\x9a)\xe5\x86\xe4\xad}l', 'America/Chicago', datetime.datetime(2015, 8, 11, 19, 48, 27), '\xd4\xe3\x04;:\xa0M\xce\x95\x9a\xf9U\x05x"\x10')
注意:我在实际
中使用的不是int ID我认为使用post_update = True它会按预期工作。我做错了什么?
谢谢!
更新 正如@ gsb-eng所提到的,问题的根源应该是缺少明确的关系设置。但这是一个问题,因为对象是从词典列表中生成的,很难找到所有的关系。
更新2 最后,我能够在视察的帮助下修复关系:
def fix_relationships(objs):
for obj in objs:
insp = inspect(type(obj))
for relation in insp.relationships:
if relation.post_update:
# A relation to be set
relation_key = relation.key
if getattr(obj, relation_key):
# Relation had already been set
continue
foreign_key = relation.primaryjoin.left.key
target_class_name = relation.argument.arg
target_key = relation.primaryjoin.right.key
fk = getattr(obj, foreign_key)
if not fk:
# Nothing to set.
continue
for o in objs:
if o.__class__.__name__ == target_class_name \
and getattr(o, target_key) == fk:
setattr(obj, relation_key, o)
setattr(obj, foreign_key, None)
break
答案 0 :(得分:0)
当我观察到你的下面的错误时,它试图为我们的程序current_program_id='\xeaL\xff\x80\xe5\xffC2\x9a)\xe5\x86\xe4\xad}l'
插入这个值,这应该是它定义的整数值。
UPDATE devices SET created=%s, updated=%s, name=%s, rain_detected=%s, current_program_id=%s, timezone=%s, synced=%s WHERE devices.id = %s' (datetime.datetime(2015, 8, 11, 19, 48, 23), datetime.datetime(2015, 8, 11, 19, 48, 26), 'nWhosie', 0, '\xeaL\xff\x80\xe5\xffC2\x9a)\xe5\x86\xe4\xad}l', 'America/Chicago', datetime.datetime(2015, 8, 11, 19, 48, 27), '\xd4\xe3\x04;:\xa0M\xce\x95\x9a\xf9U\x05x"\x10')
理想情况下,它不应该触发UPDATE
查询,因为您没有提及该关系,device.current_program = program
定义了这两个对象之间的实际关系。您最好尝试运行它。 ...
device = Device()
device.id = 1
program = Program()
program.id = 2
device.current_program = program
device.programs = [program]
db.session.add_all([device, program,])
db.session.commit()