繁体   English   中英

如何更新 Flask-SQLAlchemy 一对多关系

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM