简体   繁体   English

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

[英]How to update a Flask-SQLAlchemy one to many relationship

I know similar questions have been asked, but I could not find a working solution.我知道有人问过类似的问题,但我找不到可行的解决方案。 I have a one to many relationship with these models:我与这些模型有一对多的关系:

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))

When a user fills out the form, I would like to add all of the responses to the tables.当用户填写表格时,我想将所有回复添加到表格中。 If there are pre-existing responses, they should be updated.如果有预先存在的响应,则应更新它们。 I tried doing that with the following code:我尝试使用以下代码执行此操作:

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()

When there is no previous data, it works just fine.当没有以前的数据时,它工作得很好。 But when data needs to be updated (eg a user filled out the form before but wants to edit and resubmit it), it outputs 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)] 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)] Why is that? 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)]为什么? How do I properly update the tables?如何正确更新表格?

To anyone in the future who stumbles upon this question while researching, this is how I solved it:对于将来在研究时偶然发现这个问题的任何人,这就是我解决它的方法:

        #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()

Essentially, I delete all the current data in the tables and reinsert the new data into each table manually.本质上,我删除了表中的所有当前数据,然后手动将新数据重新插入到每个表中。 This seems to work, but it messes up the IDs in the relationship tables (since they auto-increment, deleting entries does not reset the IDs).这似乎有效,但它弄乱了关系表中的 ID(因为它们自动递增,删除条目不会重置 ID)。 For my purposes, though, it is only an aesthetic problem, so this is the best way I could come up with, though it's not pretty.不过,就我的目的而言,这只是一个美学问题,所以这是我能想到的最好方法,尽管它并不漂亮。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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