Python SQLAlchemy从多对多关系中删除

Python SQLAlchemy从多对多关系中删除,python,sqlite,flask,sqlalchemy,flask-sqlalchemy,Python,Sqlite,Flask,Sqlalchemy,Flask Sqlalchemy,(我正在使用SQLAlchemy、SQLite3、Flask-SQLAlchemy、Flask和Python) 我正在实现一个待办事项列表提要,用户可以在其中创建一篇文章(类文章),并将任务(类任务)附加到每篇文章。每个任务可以有许多帖子。每个帖子可以有很多任务。我对SQLAlchemy和从表中删除有问题。有趣的是: 当用户删除的任务中包含零篇帖子(task.posts.count()==0)时,从数据库中删除是成功的 当用户删除包含一个或多个帖子的任务(task.posts.count()>

(我正在使用SQLAlchemy、SQLite3、Flask-SQLAlchemy、Flask和Python)

我正在实现一个待办事项列表提要,用户可以在其中创建一篇文章(
类文章
),并将任务(
类任务
)附加到每篇文章。每个任务可以有许多帖子。每个帖子可以有很多任务。我对SQLAlchemy和从表中删除有问题。有趣的是:

  • 当用户删除的任务中包含零篇帖子(
    task.posts.count()==0
    )时,从数据库中删除是成功的
  • 当用户删除包含一个或多个帖子的任务(
    task.posts.count()>0
    )时,从数据库中删除会抛出错误
以下是错误:

sqlalchemy.exc.InvalidRequestError: This Session's transaction has been rolled back due to a previous exception during flush. 
To begin a new transaction with this Session, first issue Session.rollback().
Original exception was: DELETE statement on table 'tasks_posts' expected to delete 1 row(s); Only 0 were matched.
以下是Post&Task Models&tasks\u posts表:

class Post(db.Model):
    __tablename__ = 'posts'
    id = db.Column(db.Integer, primary_key=True)
    body = db.Column(db.Text)
    tasks = db.relationship('Task', secondary='tasks_posts', \
            backref=db.backref('post', lazy='joined'), \
            lazy='dynamic', cascade='all, delete-orphan', \
            single_parent=True)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'))

class Task(db.Model):
    __tablename__ = 'tasks'
    id = db.Column(db.Integer, primary_key=True) 
    title = db.Column(db.String(24))
    description = db.Column(db.String(64))
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    posts = db.relationship('Post', secondary='tasks_posts', \
            backref=db.backref('task', lazy='joined'), \
            lazy='dynamic', cascade='all, delete-orphan', \
            single_parent=True)

tasks_posts = db.Table('tasks_posts',\
        db.Column('task_id', db.Integer, db.ForeignKey('tasks.id')),\
        db.Column('post_id', db.Integer, db.ForeignKey('posts.id'))\
        )
以下是查看功能:

@main.route('/edit-task/delete/<int:id>', methods=['GET', 'POST'])
def delete_task(id):
    task = Task.query.get_or_404(id)
    db.session.delete(task)
    db.session.commit()
    return redirect(url_for('.user', username=current_user.username))
@main.route('/edit task/delete/',方法=['GET','POST'])
def delete_任务(id):
task=task.query.get\u或\u 404(id)
db.session.delete(任务)
db.session.commit()
返回重定向(url_for('.user',username=current_user.username))
我假设问题在于我没有正确实施:

  • SQLAlchemy的“级联”特性
  • 多对多关系
  • 或者查看功能
以下是堆栈跟踪:

File "...venv/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File ".../venv/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File ".../venv/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File ".../venv/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File ".../venv/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File ".../venv/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File ".../venv/lib/python2.7/site-packages/flask/app.py", line 1473, in full_dispatch_request
    rv = self.preprocess_request()
  File ".../venv/lib/python2.7/site-packages/flask/app.py", line 1666, in preprocess_request
    rv = func()
  File ".../app/auth/views.py", line 12, in before_request
    if current_user.is_authenticated:
  File ".../venv/lib/python2.7/site-packages/werkzeug/local.py", line 342, in __getattr__
    return getattr(self._get_current_object(), name)
  File ".../venv/lib/python2.7/site-packages/werkzeug/local.py", line 301, in _get_current_object
    return self.__local()
  File ".../venv/lib/python2.7/site-packages/flask_login.py", line 47, in <lambda>
    current_user = LocalProxy(lambda: _get_user())
  File ".../venv/lib/python2.7/site-packages/flask_login.py", line 858, in _get_user
    current_app.login_manager._load_user()
  File ".../venv/lib/python2.7/site-packages/flask_login.py", line 389, in _load_user
    return self.reload_user()
  File ".../venv/lib/python2.7/site-packages/flask_login.py", line 351, in reload_user
    user = self.user_callback(user_id)
  File ".../app/models.py", line 235, in load_user
    return User.query.get(int(user_id))
  File ".../venv/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 829, in get
    return self._get_impl(ident, loading.load_on_ident)
  File ".../venv/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 853, in _get_impl
    self.session, key, attributes.PASSIVE_OFF)
  File ".../venv/lib/python2.7/site-packages/sqlalchemy/orm/loading.py", line 152, in get_from_identity
    state._load_expired(state, passive)
  File ".../venv/lib/python2.7/site-packages/sqlalchemy/orm/state.py", line 474, in _load_expired
    self.manager.deferred_scalar_loader(self, toload)
  File ".../venv/lib/python2.7/site-packages/sqlalchemy/orm/loading.py", line 664, in load_scalar_attributes
    only_load_props=attribute_names)
  File ".../venv/lib/python2.7/site-packages/sqlalchemy/orm/loading.py", line 219, in load_on_ident
    return q.one()
  File ".../venv/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2528, in one
    ret = list(self)
  File ".../venv/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2571, in __iter__
    return self._execute_and_instances(context)
  File ".../venv/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2584, in _execute_and_instances
    close_with_result=True)
  File ".../venv/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2575, in _connection_from_session
    **kw)
  File ".../venv/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 893, in connection
    execution_options=execution_options)
  File ".../venv/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 898, in _connection_for_bind
    engine, execution_options)
  File ".../venv/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 313, in _connection_for_bind
    self._assert_active()
  File ".../venv/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 214, in _assert_active
    % self._rollback_exception
InvalidRequestError: This Session's transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: DELETE statement on table 'tasks_posts' expected to delete 1 row(s); Only 0 were matched.
文件“…venv/lib/python2.7/site packages/flask/app.py”,第1836行,调用__
返回self.wsgi_应用程序(环境,启动响应)
wsgi_应用程序中的文件“../venv/lib/python2.7/site packages/flask/app.py”第1820行
响应=self.make\u响应(self.handle\u异常(e))
文件“../venv/lib/python2.7/site packages/flask/app.py”,第1403行,在句柄中
重放(exc_类型、exc_值、tb)
wsgi_应用程序中的文件“../venv/lib/python2.7/site packages/flask/app.py”第1817行
response=self.full\u dispatch\u request()
文件“../venv/lib/python2.7/site packages/flask/app.py”,第1477行,完整发送请求
rv=自身处理用户异常(e)
文件“../venv/lib/python2.7/site packages/flask/app.py”,第1381行,在handle\u user\u异常中
重放(exc_类型、exc_值、tb)
文件“../venv/lib/python2.7/site packages/flask/app.py”,第1473行,完整发送请求
rv=self.preprocess_请求()
文件“../venv/lib/python2.7/site packages/flask/app.py”,第1666行,在预处理请求中
rv=func()
文件“../app/auth/views.py”,第12行,在请求之前
如果当前用户已通过身份验证:
文件“../venv/lib/python2.7/site packages/werkzeug/local.py”,第342行,位于__
返回getattr(self.\u get\u current\u object(),name)
文件“../venv/lib/python2.7/site packages/werkzeug/local.py”,第301行,位于当前对象中
返回self.\uuu local()
文件“../venv/lib/python2.7/site packages/flask_login.py”,第47行,在
当前用户=本地代理(lambda:\u get\u user())
文件“../venv/lib/python2.7/site packages/flask_login.py”,第858行,在_get_user中
当前应用程序登录管理器。加载用户()
文件“../venv/lib/python2.7/site packages/flask\u login.py”,第389行,在加载用户中
返回self.reload_user()
文件“../venv/lib/python2.7/site packages/flask_login.py”,第351行,在reload_user中
user=self.user\u回调(user\u id)
文件“../app/models.py”,第235行,加载用户
返回User.query.get(int(User\u id))
get中的文件“../venv/lib/python2.7/site packages/sqlalchemy/orm/query.py”,第829行
返回self.\u get\u impl(识别,加载。加载到识别)
文件“../venv/lib/python2.7/site packages/sqlalchemy/orm/query.py”,第853行,在
self.session、key、attributes.PASSIVE(关闭)
文件“../venv/lib/python2.7/site packages/sqlalchemy/orm/loading.py”,第152行,在get_from_identity中
状态。\加载\过期(状态,被动)
文件“../venv/lib/python2.7/site packages/sqlalchemy/orm/state.py”,第474行,在加载中
self.manager.deferred\u标量\u加载器(self,toload)
文件“../venv/lib/python2.7/site packages/sqlalchemy/orm/load.py”,第664行,在load\u scalar\u属性中
仅\u加载\u道具=属性\u名称)
文件“../venv/lib/python2.7/site packages/sqlalchemy/orm/loading.py”,第219行,在加载标识中
返回q.one()
文件“../venv/lib/python2.7/site packages/sqlalchemy/orm/query.py”,第2528行,一个
ret=列表(自身)
文件“../venv/lib/python2.7/site packages/sqlalchemy/orm/query.py”,第2571行,在__
返回self.\u执行\u和\u实例(上下文)
文件“../venv/lib/python2.7/site packages/sqlalchemy/orm/query.py”,第2584行,在_execute_和_实例中
用_结果=真关闭_)
文件“../venv/lib/python2.7/site packages/sqlalchemy/orm/query.py”,第2575行,位于来自会话的连接中
**千瓦)
文件“../venv/lib/python2.7/site packages/sqlalchemy/orm/session.py”,第893行,连接中
执行选项=执行选项)
文件“../venv/lib/python2.7/site-packages/sqlalchemy/orm/session.py”,第898行,位于用于绑定的连接中
引擎、执行(可选)
文件“../venv/lib/python2.7/site packages/sqlalchemy/orm/session.py”,第313行,在用于绑定的连接中
self.\u assert\u active()
文件“../venv/lib/python2.7/site packages/sqlalchemy/orm/session.py”,第214行,在激活状态下
%self.\u回滚\u异常
InvalidRequestError:由于刷新期间的前一个异常,此会话的事务已回滚。要使用此会话开始新事务,请首先发出Session.rollback()。最初的例外情况是:表“tasks\u posts”上的DELETE语句预期删除1行;只有0个匹配。

好的,我认为这里发生的一些事情可能会导致您的问题。首先是错误消息本身。这意味着数据库认为它应该删除某些内容,但它不在那里。我相信这是由您的
删除所有孤儿和
单亲家长=True
造成的

这告诉sqlalchemy,
Post
Task
都有一个单独的
class Post(ModelBase):
    __tablename__ = 'posts'
    id = Column(Integer, primary_key=True)
    body = Column(Text)
    user_id = Column(Integer, ForeignKey('users.id'))


class Task(ModelBase):
    __tablename__ = 'tasks'
    id = Column(Integer, primary_key=True)
    title = Column(String(24))
    description = Column(String(64))
    user_id = Column(Integer, ForeignKey('users.id'))
    posts = relationship(
        'Post', 
         secondary='tasks_posts', 
         backref='tasks')
class Post(db.Model):
    __tablename__ = 'posts'
    id = db.Column(db.Integer, primary_key=True)
    body = db.Column(db.Text)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    tasks = db.relationship('Task', secondary='tasks_posts', backref='post', lazy='dynamic')

class Task(db.Model):
    __tablename__ = 'tasks'
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(24))
    description = db.Column(String(64))
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'))

tasks_posts = db.Table('tasks_posts',
        db.Column('task_id', db.Integer, db.ForeignKey('tasks.id')),
        db.Column('post_id', db.Integer, db.ForeignKey('posts.id'))
        )