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
, CONSTRAINTuser_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 配置,处理对象-关系,一对多,多对多