読者です 読者をやめる 読者になる 読者になる

SQLのDELETE文を、DjangoのQuerySet APIで書いてみた

Django Python

前々回はSELECT、前回はINSERT, UPDATEだったので、今回はDELETEを書いてみます。

なお、ベースのアプリは前回のものを引き継ぎます。

 

環境

 

DELETE

全件削除
Deletion.objects.all().delete()
#=> DELETE FROM "runner_deletion"

 

条件に一致したレコードのみ削除
Deletion.objects.filter(name='foo').delete()
#=> 'DELETE FROM "runner_deletion" WHERE "runner_deletion"."name" = %s' - PARAMS = ('foo',)

 

ON DELETE時の挙動

ModelのForeignKeyでon_delete設定時の挙動が気になったため、各パターンを試してみました。

 

Modelの用意

親Model(xxxKey)と、それを外部キー指定した子Model(Deletion)を用意します。

また、on_deleteパターン数分、子Modelでmodels.ForeignKey()列を用意します。
Model field reference - #django.db.models.ForeignKey.on_delete | Django documentation | Django

class CascadeKey(models.Model):
    name = models.CharField(max_length=100)

class ProtectKey(models.Model):
    name = models.CharField(max_length=100)

class SetNullKey(models.Model):
    name = models.CharField(max_length=100)

class SetDefaultKey(models.Model):
    name = models.CharField(max_length=100)

class SetKey(models.Model):
    name = models.CharField(max_length=100)

class DoNothingKey(models.Model):
    name = models.CharField(max_length=100)

class Deletion(models.Model):
    name = models.CharField(max_length=200)
    cascade_row = models.ForeignKey(CascadeKey, on_delete=models.CASCADE)
    protect_row = models.ForeignKey(ProtectKey, on_delete=models.PROTECT)
    set_null_row = models.ForeignKey(SetNullKey,
                                     null=True,
                                     on_delete=models.SET_NULL)
    set_default_row = models.ForeignKey(SetDefaultKey,
                                        default=9,
                                        on_delete=models.SET_DEFAULT)
    set_key_row = models.ForeignKey(SetKey,
                                    default=10,
                                    on_delete=models.SET(11))
    do_nothing_row = models.ForeignKey(DoNothingKey, on_delete=models.DO_NOTHING)

 

DELETEの実行
CASCADE
# 事前データ
#=> Deletion_model: [{'cascade_row_id': 3, 'name': 'foo', 'id': 5}]  *関係する部分のみ

CascadeKey.objects.all().delete()
#=> Deletion_model: []

 

PROTECT
# 事前データ
#=> Deletion_model: [{'id': 6, 'protect_row_id': 1, 'name': 'foo'}]

ProtectKey.objects.all().delete() #=> ここでエラーを吐く
# django.db.models.deletion.ProtectedError: ("Cannot delete some instances of model 'ProtectKey'
# because they are referenced through a protected foreign key:
# 'DeleteOn.protect_row'", [<DeleteOn: DeleteOn object>])

 

SET_NULL
# 事前データ
#=> Deletion_model: [{'name': 'foo', 'id': 6, 'set_null_row_id': 1}]

SetNullKey.objects.all().delete()
#=> Deletion_model: [{'name': 'foo', 'id': 6, 'set_null_row_id': None}]

 

SET_DEFAULT
#=> Deletion_model: [{'id': 8, 'name': 'foo', 'set_default_row_id': 11}]

# Modelでは、'default=9' の設定あり
SetDefaultKey.objects.filter(name='set_default').delete()
#=> Deletion_model: [{'id': 8, 'name': 'foo', 'set_default_row_id': 9}]

 

SET
#=> Deletion_model: [{'id': 9, 'name': 'foo', 'set_key_row_id': 3}]

# Modelでは`on_delete=models.SET(11)`の設定あり
SetKey.objects.filter(name='set_row').delete()
#=> Deletion_model: [{'id': 9, 'name': 'foo', 'set_key_row_id': 11}]

 

DO_NOTHING
#=> Deletion_model: [{'do_nothing_row_id': 4, 'id': 11, 'name': 'foo'}]

DoNothingKey.objects.filter(name='do_nothing').delete()
#=> Deletion_model: [{'do_nothing_row_id': 4, 'id': 11, 'name': 'foo'}]

 

ソースコード

GitHubに追加してあります。今回のメインはdelete.pyとなります。