[英]How to update a Flask-SQLAlchemy one to many relationship
我知道有人问过类似的问题,但我找不到可行的解决方案。 我与这些模型有一对多的关系:
class User(UserMixin, db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True) # primary keys are required by SQLAlchemy
email = db.Column(db.String(100), unique=True)
password = db.Column(db.String(100))
name = db.Column(db.String(1000))
religions = db.relationship('Religion', backref='users')
relImp = db.Column(db.Integer)
sizes = db.relationship('Size', backref='users')
sizeImp = db.Column(db.Integer)
majors = db.relationship('Major', backref='users')
allMajors = db.Column(db.Boolean)
satMath = db.Column(db.Integer)
satEng = db.Column(db.Integer)
actMath = db.Column(db.Integer)
actEng = db.Column(db.Integer)
settings = db.relationship('Setting', backref='users')
settingImp = db.Column(db.Integer)
regions = db.relationship('Region', backref='users')
regionImp = db.Column(db.Integer)
states = db.relationship('State', backref='users')
stateImp = db.Column(db.Integer)
specPrefs = db.relationship('SpecPref', backref='users')
income = db.Column(db.Integer)
class Religion(db.Model):
__tablename__ = 'religions'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
code = db.Column(db.Integer)
name = db.Column(db.String(100))
class Size(db.Model):
__tablename__ = 'sizes'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
code = db.Column(db.Integer)
name = db.Column(db.String(100))
class Major(db.Model):
__tablename__ = 'majors'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
code = db.Column(db.Integer)
name = db.Column(db.String(100))
class Setting(db.Model):
__tablename__ = 'settings'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
code = db.Column(db.Integer)
name = db.Column(db.String(100))
class Region(db.Model):
__tablename__ = 'regions'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
code = db.Column(db.Integer)
name = db.Column(db.String(100))
class State(db.Model):
__tablename__ = 'states'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
code = db.Column(db.Integer)
name = db.Column(db.String(100))
class SpecPref(db.Model):
__tablename__ = 'specPrefs'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
code = db.Column(db.Integer)
name = db.Column(db.String(100))
当用户填写表格时,我想将所有回复添加到表格中。 如果有预先存在的响应,则应更新它们。 我尝试使用以下代码执行此操作:
form = Questionnaire(request.form)
#all of the below are WTForms selectMultiple fields
rels = []
for rel in form.relAffil.data:
rels.append(Religion(code=rel,name=dict(religionChoices).get(rel)))
sizes = []
for size in form.size.data:
sizes.append(Size(code=size,name=dict(sizeChoices).get(size)))
majors = []
for major in form.major.data:
majors.append(Major(code=major,name=dict(majorChoices).get(major)))
sets = []
for setting in form.setting.data:
sets.append(Setting(code=setting,name=dict(settingChoices).get(setting)))
regs = []
for reg in form.region.data:
regs.append(Region(code=reg,name=dict(regionChoices).get(reg)))
states = []
for state in form.state.data:
states.append(State(code=state,name=dict(stateChoices).get(state)))
specPrefs = []
for spec in form.specPref.data:
specPrefs.append(SpecPref(code=spec,name=dict(specPrefChoices).get(spec)))
updatedUser = User(id=current_user.id, religions = rels, relImp = form.relImp.data, sizes = sizes, sizeImp = form.sizeImp.data, majors = majors, allMajors = form.allMajors.data,
satMath = form.satMath.data, satEng = form.satEng.data, actMath = form.actMath.data, actEng = form.actEng.data, settings = sets, settingImp = form.settingImp.data, regions = regs,
regionImp = form.regionImp.data, states = states, stateImp = form.stateImp.data, specPrefs = specPrefs, income = form.income.data)
if request.method == 'GET':
return render_template('getStarted.html', form=form,name=current_user.name)
else: #if 'POST'
if form.validate():
db.session.merge(updatedUser)
db.session.commit()
当没有以前的数据时,它工作得很好。 但是当需要更新数据时(例如,用户之前填写了表单但想编辑并重新提交),它会输出sqlalchemy.exc.IntegrityError: Cannot insert the value NULL into column 'user_id', table 'dbo.majors'; column does not allow nulls. UPDATE fails. [SQL: UPDATE majors SET user_id=? WHERE majors.id = ?] [parameters: (None, 3)]
sqlalchemy.exc.IntegrityError: Cannot insert the value NULL into column 'user_id', table 'dbo.majors'; column does not allow nulls. UPDATE fails. [SQL: UPDATE majors SET user_id=? WHERE majors.id = ?] [parameters: (None, 3)]
sqlalchemy.exc.IntegrityError: Cannot insert the value NULL into column 'user_id', table 'dbo.majors'; column does not allow nulls. UPDATE fails. [SQL: UPDATE majors SET user_id=? WHERE majors.id = ?] [parameters: (None, 3)]
为什么? 如何正确更新表格?
对于将来在研究时偶然发现这个问题的任何人,这就是我解决它的方法:
#delete current data
Religion.query.filter(Religion.user_id == current_user.id).delete()
Size.query.filter(Size.user_id == current_user.id).delete()
Major.query.filter(Major.user_id == current_user.id).delete()
Setting.query.filter(Setting.user_id == current_user.id).delete()
Region.query.filter(Region.user_id == current_user.id).delete()
State.query.filter(State.user_id == current_user.id).delete()
SpecPref.query.filter(SpecPref.user_id == current_user.id).delete()
#now add all of the new data
db.session.add_all([Religion(code=rel,name=dict(religionChoices).get(rel),user_id = current_user.id) for rel in form.relAffil.data])
db.session.add_all([Size(code=size,name=dict(sizeChoices).get(size),user_id = current_user.id) for size in form.size.data])
db.session.add_all([Major(code=major,name=dict(majorChoices).get(major),user_id = current_user.id) for major in form.major.data])
db.session.add_all([Setting(code=setting,name=dict(settingChoices).get(setting),user_id = current_user.id) for setting in form.setting.data])
db.session.add_all([Region(code=reg,name=dict(regionChoices).get(reg),user_id = current_user.id) for reg in form.region.data])
db.session.add_all([State(code=state,name=dict(stateChoices).get(state),user_id = current_user.id) for state in form.state.data])
db.session.add_all([SpecPref(code=spec,name=dict(specPrefChoices).get(spec),user_id = current_user.id) for spec in form.specPref.data])
#update the user database with new data
updatedUser = User(id=current_user.id, relImp = form.relImp.data, sizeImp = form.sizeImp.data, allMajors = form.allMajors.data,
satMath = form.satMath.data, satEng = form.satEng.data, actMath = form.actMath.data, actEng = form.actEng.data, settingImp = form.settingImp.data,
regionImp = form.regionImp.data, stateImp = form.stateImp.data, income = form.income.data)
db.session.merge(updatedUser)
#TODO: reincrement after deleting?
#db.session.execute("DBCC CHECKIDENT (religions, RESEED, 0)") #doesn't work, does each user separately
db.session.commit()
本质上,我删除了表中的所有当前数据,然后手动将新数据重新插入到每个表中。 这似乎有效,但它弄乱了关系表中的 ID(因为它们自动递增,删除条目不会重置 ID)。 不过,就我的目的而言,这只是一个美学问题,所以这是我能想到的最好方法,尽管它并不漂亮。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.