12

category_id删除类别时如何将产品自动设置为默认值?例如1指向第一类。

class Product(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80))
    content = db.Column(db.Text(), unique=True)
    category_id = db.Column(db.Integer, db.ForeignKey('category.id'))
    atime = db.Column(db.DateTime())

    def __init__(self, name, content, category_id):
        self.name = name
        self.content = content
        self.category_id = category_id
        self.atime = datetime.now()

    def __repr__(self):
        return '<Product %r>' % self.id

class Category(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80))
    products = db.relationship('Product', backref='category', cascade="all, delete, delete-orphan")

    def __init__(self, *args, **kwargs):
        if len(kwargs) > 0:
            self.name = kwargs['name']

    def __repr__(self):
        return '<Category %r>' % self.name

我不想使用级联删除它们!

4

1 回答 1

24

这里需要在编排中执行两件事:

  1. 使用适当的引用操作定义外键
  2. 配置SA关系的级联选项

我认为最干净的方法是在删除其 Category: 时将其设置category_id为一个值:是该子句的可能引用操作之一,您可以将其添加到ForeignKey定义中:NULLSET NULLON DELETE

category_id = db.Column(db.Integer, db.ForeignKey('category.id', ondelete='SET NULL'))

以同样的方式您可以使用选项SET DEFAULT,但在这种情况下,您还需要为列配置默认值category_idcategory_id = Column(..., server_default=1)。请注意,这些实现在不同的 RDBMS 之间是不同的。

至于cascade选项:您应该基本上cascade="all, delete, delete-orphan"从您的products关系定义中删除。实际上,您要确保delete, delete-orphan不存在。

话虽如此,您确实需要测试您的代码以涵盖不同的场景,因为Category对象的两次不同删除可能会根据您的 RDBMS 和 SA 配置产生不同的结果:

# scenario-1: delete in session: SA might set category_id of all chilren Products to None
c1 = session.query(Category).get(1)
session.delete(c1)
session.commit()

# scenario-2: delete without loading an object into the session: SA will perform no additional logic
session.query(Category).filter(Category.id == 2).delete()
session.commit()

希望这一切都能为您指明正确的方向。像往常一样,使用echo=True或仅通过配置logging模块在您的测试代码中启用 SQL 日志记录,您将看到 SA 对您的数据库执行的操作。您在 SQL 中没有看到的其他更改是由 RDBMS 本身根据您的引用操作完成的。

于 2012-04-13T16:26:09.500 回答