Flask SQLAlchemy 多对多关联对象错误

Posted

技术标签:

【中文标题】Flask SQLAlchemy 多对多关联对象错误【英文标题】:Flask SQLAlchemy Many to Many association object error 【发布时间】:2017-08-30 17:43:59 【问题描述】:

我正在使用基于项目管理的 python 3.4、Flask 和 SQLAlchemy 进行项目。我有以下需要以多对多关系相互链接的类。用户和项目模块分别按预期运行。 用户模型代码包含在下面

class User(db.Model):
__tablename__='users'
    id = db.Column(db.Integer, primary_key =True)
    firstname = db.Column(db.String(80))
    lastname = db.Column(db.String(80))
    email = db.Column(db.String(35), unique =True)
    username = db.Column(db.String(80), unique= True)
    password = db.Column(db.String(80))
    organisation_id = db.Column(db.Integer, db.ForeignKey('organisations.id'))
    organisation = db.relationship('Organisation', backref='users')
    is_admin = db.Column(db.Boolean)

    def __init__(self, firstname, lastname, email, username, password, organisation_id, is_admin=False):
        self.firstname = firstname
        self.email = email
        self.lastname = lastname
        self.password = password
        self.is_admin = is_admin
        self.username = username
        organisation_id = organisation_id

项目的代码是

class Project(db.Model):
    __tablename__ ="projects"
    id = db.Column(db.Integer, primary_key=True)
    code = db.Column(db.String(80), unique=True)
    name = db.Column(db.String(80))
    owner = db.Column(db.Integer, db.ForeignKey('users.id'))
    description = db.Column(db.Text)
    start = db.Column(db.DateTime)
    finish = db.Column(db.DateTime)
    cycle_id = db.Column(db.Integer, db.ForeignKey('reportingcycles.id'))
    cycle= db.relationship('ReportingCycle', backref='project')
    org_id = db.Column(db.Integer, db.ForeignKey('organisations.id'))
    organisation= db.relationship('Organisation', backref='project')
    status = db.Column(db.Boolean)
    users = db.relationship("UserProject", backref="project")

    def __init__(self, code, name, description, owner, start, finish, cycle, organisation, status):
        self.code = code
        self.name = name
        self.owner = owner
        self.description = description
        self.start = start
        self.finish = finish
        self.status = status
        self.org_id= organisation.id
        self.cycle_id= cycle.id

我已根据此链接Association Object 中的 SQLAlchemy 教程创建了一个关联对象 关联类的代码是

class UserProject(db.Model):
    __tablename__ = 'user_project'
    project_id = db.Column(db.Integer, db.ForeignKey('projects.id'), primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True)
    role_id = db.Column(db.Integer)

    user = db.relationship("User", backref="project_assocs")

当我尝试通过键入以下代码在命令行中测试这种关系时

prj = Project.query.first()
usr = User.query.first()
asso = UserProject(role_id =1)
asso.user = usr
prj.users.append(asso)

我在尝试将这些更改提交到数据库时收到以下错误。

/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/sql/crud.py:692: SAWarning:列 'user_project.project_id' 被标记为 表 'user_project' 的主键,但没有 Python 端或 指示服务器端默认生成器,也未指示 'autoincrement=True' 或 'nullable=True',并且没有明确的值 通过了。主键列通常可能不存储 NULL。注意 从 SQLAlchemy 1.1 开始,必须指明 'autoincrement=True' 显式地用于复合(例如多列)主键,如果 AUTO_INCREMENT/SERIAL/IDENTITY 行为是预期的 主键中的列。 CREATE TABLE 语句受以下因素影响 这种变化在大多数后端也是如此。 util.warn(msg) Traceback(大多数 最近通话最后一次):文件“”,第 1 行,在文件中 “/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/orm/attributes.py”, 第 237 行,在 get return self.impl.get(instance_state(instance), dict_) 文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/orm/attributes.py”, 第 584 行,在获取 值 = self.callable_(状态,被动)文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/orm/strategies.py”, 第 557 行,在 _load_for_state return self._emit_lazyload(session, state, ident_key, passive) File "", line 1, in File “/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/orm/strategies.py”, 第 635 行,在 _emit_lazyload 结果 = q.all() 文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/orm/query.py”, 第 2703 行,总共 返回列表(自我)文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/orm/query.py”, 第 2854 行,在 iter 中 self.session._autoflush() 文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/orm/session.py”, 第 1375 行,在 _autoflush 中 util.raise_from_cause(e) 文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/util/compat.py”, 第 203 行,在 raise_from_cause 中 reraise(类型(异常),异常,tb=exc_tb,原因=原因)文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/util/compat.py”, 第 187 行,在加注中 提高价值文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/orm/session.py”, 第 1365 行,在 _autoflush self.flush() 文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/orm/session.py”, 第 2139 行,齐平 self._flush(对象)文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/orm/session.py”, 第 2259 行,在 _flush transaction.rollback(_capture_exception=True)文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/util/langhelpers.py”, 第 66 行,在 退出 compat.reraise(exc_type,exc_value,exc_tb)文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/util/compat.py”, 第 187 行,在加注中 提高价值文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/orm/session.py”, 第 2223 行,在 _flush flush_context.execute() 文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/orm/unitofwork.py”, 第 389 行,执行中 rec.execute(self) 文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/orm/unitofwork.py”, 第 548 行,执行中 uow 文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/orm/persistence.py”, 第 181 行,在 save_obj 中 映射器,表,插入)文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/orm/persistence.py”, 第 835 行,在 _emit_insert_statements 执行(语句,参数)文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/engine/base.py”, 第 945 行,执行中 返回方法(self,multiparams,params)文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/sql/elements.py”, 第 263 行,在 _execute_on_connection 返回 connection._execute_clauseelement(self, multiparams, params) 文件 “/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/engine/base.py”, 第 1053 行,在 _execute_clauseelement 中 编译_sql,蒸馏_参数文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/engine/base.py”, 第 1189 行,在 _execute_context 上下文)文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/engine/base.py”, 第 1394 行,在 _handle_dbapi_exception 中 exc_info 文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/util/compat.py”, 第 203 行,在 raise_from_cause 中 reraise(类型(异常),异常,tb=exc_tb,原因=原因)文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/util/compat.py”, 第 186 行,在加注中 raise value.with_traceback(tb) 文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/engine/base.py”, 第 1182 行,在 _execute_context 上下文)文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/sqlalchemy/engine/default.py”, 第 470 行,在 do_execute 中 cursor.execute(语句,参数)文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/pymysql/cursors.py”, 第 146 行,执行中 结果 = self._query(查询)文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/pymysql/cursors.py”, 第 296 行,在 _query 中 conn.query(q) 文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/pymysql/connections.py”, 第 781 行,查询中 self._affected_rows = self._read_query_result(unbuffered=unbuffered) 文件 “/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/pymysql/connections.py”, 第 942 行,在 _read_query_result 中 result.read() 文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/pymysql/connections.py”, 第 1138 行,已读 first_packet = self.connection._read_packet() 文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/pymysql/connections.py”, 第 906 行,在 _read_packet 中 packet.check_error() 文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/pymysql/connections.py”, 第 367 行,在 check_error 中 err.raise_mysql_exception(self._data)文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/pymysql/err.py”, 第 120 行,在 raise_mysql_exception 中 _check_mysql_exception(errinfo) 文件“/home/ubuntu/workspace/colp/venv/lib/python3.4/site-packages/pymysql/err.py”, 第 112 行,在 _check_mysql_exception 中 raise errorclass(errno, errorvalue) sqlalchemy.exc.IntegrityError: (由于查询调用自动刷新而引发;考虑使用 session.no_autoflush 块,如果此刷新过早发生) (pymysql.err.IntegrityError) (1452, '不能添加或更新子行: 外键约束失败 (colp.user_project, CONSTRAINT user_project_ibfk_1 外键 (project_id) 引用 projects (id))') [SQL: 'INSERT INTO user_project (user_id, role_id) VALUES (%s, %s)'] [参数:(1, 1)]

知道我在这段代码中做错了什么

【问题讨论】:

关联表中role_id的意义是什么?如果它不是强制性的,那么你会在下面看到我的答案。 @Pradeepb 我需要有 role_id。实际上,它应该是为每个项目中的每个用户定义权限的第三个外键。 【参考方案1】:

我想出了一个受@Pradeepb 先前响应启发的解决方法,他发现代码只有在定义了新对象时才有效。不确定它是最好的,但它有效。 这是通过添加构造函数来修改 UserProject 类来实现的

class UserProject(db.Model):
    __tablename__ = 'user_project'
    project_id = db.Column(db.Integer, db.ForeignKey('projects.id'), primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True)
    role_id = db.Column(db.Integer)
    user = db.relationship("User", backref="parent_assocs")
    project = db.relationship("Project", backref="assoc")

def __init__(self, project, user, role):
    self.project_id = project.id
    self.user_id = user.id
    self.role_id = role.id

使用数据库中的现有资源添加关联,我使用了代码

prj = Project.query.first()
usr = User.query.first()
asso = UserProject(project = prj, user=usr, role_id =1)

【讨论】:

【参考方案2】:

在分析了错误的问题后,我知道,它只有在你创建一个新用户(对象),一个新/现有项目(对象),然后如果你关联,它就会正常工作。当我这样做时,我得到了它的工作:

prj = Project(status=True //with other parameters) or prj = Project.query.first()
usr = User(is_admin=True //with other parameters)
asso = UserProject(role_id =1)
asso.user = usr
prj.users.append(asso)

但是如果我尝试对现有对象做同样的事情,我会得到和你一样的错误。可能这有助于进一步调查:)

【讨论】:

这很有用;我发现使用不同的方法添加现有数据是成功的。 太好了。您可以将其发布为您问题的答案。

以上是关于Flask SQLAlchemy 多对多关联对象错误的主要内容,如果未能解决你的问题,请参考以下文章

使用flask-restplus在flask-SQLAlchemy中创建多对多关联表时出错

Flask SQLAlchemy 多对多插入重复条目

Flask SQLAlchemy 数据库多对多

Flask-SQLAlchemy 配置,处理对象-关系,一对多,多对多

Flask Marshmallow/SqlAlchemy:序列化多对多关系

SQLAlchemy 使用关联配置与自我的多对多关系