使用SQLAlchemy在关联表中插入数据时的IntegrityError

时间:2018-01-10 13:35:48

标签: python sqlalchemy

我正在尝试在此关联表中插入角色数据:

class Association(db.Model):
    __tablename__ = 'associations'
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True)
    team_id = db.Column(db.Integer, db.ForeignKey('teams.id'), primary_key=True)
    role = db.Column(db.String)
    user = db.relationship("User", back_populates="teams")
    team = db.relationship("Team", back_populates="users")

它与另外两个表相关联:

class User(db.Model, UserMixin):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String)
    username = db.Column(db.String, nullable=False, unique=True, index=True)
    password_hash = db.Column(db.String)
    teams = db.relationship("Association", back_populates="user")

class Team(db.Model):
    __tablename__ = 'teams'
    id = db.Column(db.Integer, primary_key = True)
    name = db.Column(db.String)
    player = db.Column(db.String)
    users = db.relationship("Association", back_populates="team")

但是,当我尝试在关联表中插入角色时:

t = Team.query.filter_by(id=team_name1_id).first()
a = Association(role=form.role.data)
a.user = User.query.filter_by(id=current_user.id).first()
t.users.append(a)
db.session.add(t)
db.session.commit()

我收到此错误:

  

IntegrityError :(由于Query-invoked autoflush引发;   如果发生此刷新,请考虑使用session.no_autoflush块   过早地)(sqlite3.IntegrityError)NOT NULL约束失败:   association.team_id [SQL:u'INSERT INTO关联(user_id,role)   VALUES(?,?)'] [参数:(1,u'point guard')]

你知道我该怎么办呢?

1 个答案:

答案 0 :(得分:5)

导致autoflush的行是

education: *defaultEd

您尚未定义relationship loading strategies,因此默认为"select"。由于您是第一次访问t.users.append(a) 关系属性,它将发出SELECT以获取相关对象。

您还在

中间接更改了会话
Team.users

save-update cascade引起,默认情况下为on,将新的a.user = User.query.filter_by(id=current_user.id).first() 实例放置到会话中。

为了保持数据库和会话的状态一致,SQLAlchemy必须flush在发出查询之前对数据库进行Temporarily disable the autoflush feature更改,因此在关联之前将半数初始化Association发送到数据库使用Association实例。

可能的解决方案:

  1. eager load针对该特定附加内容,因为您知道自己正在添加新的Team

    Association

    但仍会发出SELECT。

  2. 撤消操作。不是将with db.session.no_autoflush: t.users.append(a) 个实例附加到Association集合,而是将Team.users分配给Team

    Association.team
  3. 当您获取# Instead of t.users.append(a): a.team = t # Mr. 实例时,一个不太明显的解决方案是db.noload(Team.users)关系的内容,因此不需要SELECT:

    Team

    或者根本不使用could not have proceeded选项加载它们。

  4. 请注意

    t = db.session.query(Team).options(db.joinedload(Team.users)).first()
    

    是多余的。提取的db.session.add(t) 实例已在会话中 - 否则首先是Team {{3}}的延迟加载。