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

ここでは、オーケストレーションで実行する必要があることが 2 つあります。

  1. 適切な参照アクションで外部キーを定義する
  2. SA 関係のカスケード オプションを構成する

最もクリーンな方法は、 Category が削除されたときに を値に設定することだと思います:category_idは、句の可能な参照アクションの 1 つであり、 ForeignKey定義に追加できます。NULLSET NULLON DELETE

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

同様にオプションを使用できますSET DEFAULTが、この場合、列のデフォルト値も構成する必要がありcategory_idますcategory_id = Column(..., server_default=1)。これらの実装は RDBMS によって異なることに注意してください。

cascadeオプションについて: 基本的に、関係定義cascade="all, delete, delete-orphan"から を削除する必要があります。products実際、delete, delete-orphanそこにないことを確認する必要があります。

Categoryそうは言っても、 RDBMS と SA の構成によっては、オブジェクトの 2 つの異なる削除によって異なる結果が生じる可能性があるため、さまざまなシナリオをカバーするためにコードをテストする必要があります。

# 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いつものように、モジュールを使用して、またはモジュールを構成するだけで、テスト コードで SQL ログを有効にするloggingと、SA がデータベースに対して何を行っているかがわかります。SQL に表示されなかったその他の変更は、Referential Action を指定して RDBMS 自体によって行われました。

于 2012-04-13T16:26:09.500 に答える