Sqlalchemy在Flask应用程序中意外删除级联

时间:2017-12-06 15:51:20

标签: python flask sqlalchemy flask-sqlalchemy psycopg2

当我从数据库中删除某个项目时,我得到了一个存储级联删除(我还没有配置)。删除与删除的项目对应的类别条目。我该如何阻止这种情况发生?

这是我的数据库设置:

from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy import create_engine


Base = declarative_base()


class User(Base):
    """Object holding information about individual registered users"""

    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    name = Column(String(250), nullable=False)
    email = Column(String(250), nullable=False)
    picture = Column(String(250))


class Category(Base):
    """Object holding information about item categories"""

    __tablename__ = 'category'
    id = Column(Integer, primary_key=True)
    name = Column(String(250), nullable=False)


class Item(Base):
    """Object holding information about individual catalog items"""

    __tablename__ = 'item'
    id = Column(Integer, primary_key=True)
    name = Column(String(250), nullable=False)
    description = Column(String(5000), nullable=False)
    category_id = Column(Integer, ForeignKey('category.id'))
    category = relationship("Category")
    user_id = Column(Integer, ForeignKey('user.id'))
    user = relationship("User")


engine = create_engine('postgresql+psycopg2://********:********'
                       + '/itemcatalog.db', echo=False)
Base.metadata.create_all(engine)

这里是触发删除的代码:

@app.route('/item/<int:item_id>/delete/', methods=['GET', 'POST'])

def delete_item(item_id):
    item = session.query(Item).filter_by(id=item_id).one()

    if request.method == 'POST':
        session.delete(item)
        session.commit()
        flash('Item Successfully Deleted')
        return redirect(url_for('show_catalog'))
    else:
        return render_template('deleteitem.html', item=item,
                               username=login_session['username'],
                               picture=login_session['picture'])

预期的行为仅适用于其&#34; id&#34;要删除,并且对其他表没有任何更改。

我得到的实际结果是删除项目,并删除与该项目对应的类别表中的条目。

更新:

我采取的步骤是:

  1. 在数据库中创建新项目
  2. 删除该项
  3. 显示此内容的日志(和删除)如下。

    添加新项目:

    2017-12-06 19:32:16 UTC [5383-22] vagrant@itemcatalog.db LOG:  statement: SELECT category.id AS category_id, category.name AS category_name 
        FROM category
    2017-12-06 19:32:16 UTC [5383-23] vagrant@itemcatalog.db LOG:  statement: INSERT INTO item (name, description, category_id, user_id) VALUES ('Coffee', 'tasty beverage', 3, 2) RETURNING item.id
    2017-12-06 19:32:16 UTC [5383-24] vagrant@itemcatalog.db LOG:  statement: COMMIT
    2017-12-06 19:32:16 UTC [5383-25] vagrant@itemcatalog.db LOG:  statement: BEGIN
    2017-12-06 19:32:16 UTC [5383-26] vagrant@itemcatalog.db LOG:  statement: SELECT category.id AS category_id, category.name AS category_name 
        FROM category ORDER BY category.name ASC
    2017-12-06 19:32:16 UTC [5383-27] vagrant@itemcatalog.db LOG:  statement: SELECT item.id AS item_id, item.name AS item_name, item.description AS item_description, item.category_id AS item_category_id, item.user_id AS item_user_id 
        FROM item ORDER BY item.name ASC
    

    删除新项目:

    2017-12-06 19:33:14 UTC [5383-30] vagrant@itemcatalog.db LOG:  statement: SELECT item.id AS item_id, item.name AS item_name, item.description AS item_description, item.category_id AS item_category_id, item.user_id AS item_user_id 
        FROM item 
        WHERE item.id = 7
    2017-12-06 19:33:14 UTC [5383-31] vagrant@itemcatalog.db LOG:  statement: SELECT category.id AS category_id, category.name AS category_name 
        FROM category 
        WHERE category.id = 3
    2017-12-06 19:33:14 UTC [5383-32] vagrant@itemcatalog.db LOG:  statement: SELECT item.id AS item_id, item.name AS item_name, item.description AS item_description, item.category_id AS item_category_id, item.user_id AS item_user_id 
        FROM item 
        WHERE 3 = item.category_id
    2017-12-06 19:33:14 UTC [5383-33] vagrant@itemcatalog.db LOG:  statement: UPDATE item SET category_id=NULL WHERE item.id = 5
    2017-12-06 19:33:14 UTC [5383-34] vagrant@itemcatalog.db LOG:  statement: UPDATE item SET category_id=NULL WHERE item.id = 6
    2017-12-06 19:33:14 UTC [5383-35] vagrant@itemcatalog.db LOG:  statement: DELETE FROM item WHERE item.id = 7
    2017-12-06 19:33:14 UTC [5383-36] vagrant@itemcatalog.db LOG:  statement: DELETE FROM category WHERE category.id = 3
    2017-12-06 19:33:14 UTC [5383-37] vagrant@itemcatalog.db LOG:  statement: COMMIT
    2017-12-06 19:33:14 UTC [5383-38] vagrant@itemcatalog.db LOG:  statement: BEGIN
    2017-12-06 19:33:14 UTC [5383-39] vagrant@itemcatalog.db LOG:  statement: SELECT category.id AS category_id, category.name AS category_name 
        FROM category ORDER BY category.name ASC
    2017-12-06 19:33:14 UTC [5383-40] vagrant@itemcatalog.db LOG:  statement: SELECT item.id AS item_id, item.name AS item_name, item.description AS item_description, item.category_id AS item_category_id, item.user_id AS item_user_id 
        FROM item ORDER BY item.name ASC
    

    从日志中我可以看到它的行为不符合我的要求,但我不知道要改变什么来阻止这种行为。

2 个答案:

答案 0 :(得分:0)

我无法重现您描述的行为。如果我将数据库设置放入model.py,然后运行以下命令:

from model import engine, User, Category, Item
from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)

s = Session()

c = Category(id=1, name='Misc')
u = User(id=1, name='example', email='example@example.com')

s.add(c)
s.add(u)
s.commit()

i1 = Item(id=1, name='foo', description='foo desc', category=c,
          user=u)
i2 = Item(id=2, name='bar', description='bar desc', category=c,
          user=u)

s.add(i1)
s.add(i2)
s.commit()

然后删除其中一项:

>>> item = s.query(Item).filter_by(id=2).one()
2017-12-06 12:11:34,608 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2017-12-06 12:11:34,609 INFO sqlalchemy.engine.base.Engine SELECT item.id AS item_id, item.name AS item_name, item.description AS item_description, item.category_id AS item_category_id, item.user_id AS item_user_id 
FROM item 
WHERE item.id = %(id_1)s
2017-12-06 12:11:34,609 INFO sqlalchemy.engine.base.Engine {'id_1': 2}
>>> s.delete(item)
>>> s.commit()
2017-12-06 12:11:44,915 INFO sqlalchemy.engine.base.Engine DELETE FROM item WHERE item.id = %(id)s
2017-12-06 12:11:44,916 INFO sqlalchemy.engine.base.Engine {'id': 2}
2017-12-06 12:11:45,014 INFO sqlalchemy.engine.base.Engine COMMIT

您可以看到postgresql只执行了一个DELETE语句,如果我们检查引用的Category是否仍然存在:

>>> s.query(Category).get(1)
2017-12-06 12:12:58,968 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2017-12-06 12:12:58,970 INFO sqlalchemy.engine.base.Engine SELECT category.id AS category_id, category.name AS category_name 
FROM category 
WHERE category.id = %(param_1)s
2017-12-06 12:12:58,971 INFO sqlalchemy.engine.base.Engine {'param_1': 1}
<model.Category object at 0x7f42dfab1550>

如果您看到不同的行为,是否可以使用可重现问题的特定步骤更新您的问题?

答案 1 :(得分:0)

感谢您的回复,并对此表示抱歉。我的错误是愚蠢的...我创建了一个新的数据库设置文件用于测试目的,忘记在我的主app.py文件中更新它的路径。