python - 使用 SQLAlchemy 在关联表中插入数据时出现 IntegrityError

标签 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")

它链接到另外 2 个表:

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: (raised as a result of Query-invoked autoflush; consider using a session.no_autoflush block if this flush is occurring prematurely) (sqlite3.IntegrityError) NOT NULL constraint failed: association.team_id [SQL: u'INSERT INTO association (user_id, role) VALUES (?, ?)'] [parameters: (1, u'point guard')]

你知道我该如何解决吗?

最佳答案

导致 autoflush 的行是

t.users.append(a)

你还没有定义你的 relationship loading strategies , 所以它们默认为 "select" .由于您是第一次访问 Team.users 关系属性,它将发出一个 SELECT 以获取相关对象。

您还间接地对 session 进行了更改

a.user = User.query.filter_by(id=current_user.id).first()

由于save-update cascade , 默认情况下,将新的 Association 实例也放置到 session 中。

为了保持数据库和 session 的状态一致,SQLAlchemy 必须 flush您在发出查询之前对 DB 所做的更改,因此半初始化的 Association 在与 Team 实例关联之前被发送到 DB。

可能的解决方案:

  1. Temporarily disable the autoflush feature对于那个特定的追加,因为你知道你正在添加一个新的 Association:

    with db.session.no_autoflush:
        t.users.append(a)
    

    不过,SELECT 仍会发出。

  2. 逆向操作。不是将 Association 实例附加到 Team.users 集合,而是将 Team 分配给 Association.team:

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

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

    或者使用 db.noload(Team.users) 根本不加载它们选项。

注意

db.session.add(t)

是多余的。获取的 Team 实例已经在 session 中——否则 Team.users 的延迟加载 could not have proceeded首先。

关于python - 使用 SQLAlchemy 在关联表中插入数据时出现 IntegrityError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48188660/

相关文章:

python - 向 PyQt5 QGroupBox 中的按钮添加功能

python+MySQLdb, simple select 相比平面文件访问速度太慢

python - SQLAlchemy 是否支持 postgres 的 UPDATE.....FROM 语法?

python - 将 python 对象转换为列表的列表

python - SQLAlchemy 从查询结果中访问列类型

python - sqlalchemy 查询 : select using list of tuples

python - 动态创建对象的 Doctest

Python 以字符串形式请求 CA 证书

当additionalProperties 设置为 false 时,python jsonschema 验证失败

python - 使用分隔符将文件中的多行存储到变量