【Django】モデル・テーブル・レコードを削除する完全ガイド|DROP / DELETE / migrate の使い分け

スポンサードリンク



Django · Database Operations · 2026 Edition

Django で「データを削除したい」と一口に言っても、実は レコード(データ行)を消すのと テーブル(モデル)そのものを消すのは全く別の操作です。本記事では、レコード削除(delete())、テーブル削除(drop table + migrate)、全データのリセット(flush)の使い分けを、実際の家計簿アプリのモデルを例に、手順とハマりどころを含めて完全解説します。所要時間 15 分。

user@sinyblog:~/article 01_concepts.mdレコード削除 vs テーブル削除 — 何が違うのか?

まず最初に、Django で「削除」と言ったときに混同されがちな 3 種類の操作を整理しておきます。

操作 消えるもの 使うコマンド 使う場面
レコード削除 テーブル内のデータ行(テーブル定義は残る) Model.objects.delete() (ORM) 古いデータを消す、ユーザー操作で削除、テスト用データのクリーンアップ
テーブル削除 テーブル定義そのもの(中身もろとも) drop table + migrate 操作 不要になったモデルの撤去、設計変更で古いテーブルを除去
全データリセット 全テーブルのデータのみ(定義は残る) python manage.py flush テスト前の DB クリーンアップ、開発環境のリセット
どれが必要か迷ったら

「特定のレコード(行)を消したい」→ パターン1(レコード削除)。「もう使わないモデル(テーブル)自体を消したい」→ パターン2(テーブル削除)。「テスト前にデータだけ全部消したい」→ パターン3(flush)。本記事ではこの 3 パターンを順に解説します。

user@sinyblog:~/article 02_sample_models.mdサンプルモデル(家計簿アプリ)

本記事の例では、以下 3 つのモデルを持つ家計簿アプリ(kakeibo)を題材にします。データベースは SQLite3 です。

python— kakeibo/models.py


from django.db import models
from datetime import datetime


class Category(models.Model):
    class Meta:
        verbose_name = "カテゴリ"
        verbose_name_plural = "カテゴリ"

    category_name = models.CharField(max_length=255, unique=True)

    def __str__(self):
        return self.category_name


class Kakeibo(models.Model):
    class Meta:
        verbose_name = "家計簿"
        verbose_name_plural = "家計簿"

    date = models.DateField("日付", default=datetime.now)
    category = models.ForeignKey(Category, on_delete=models.PROTECT, verbose_name="カテゴリ")
    money = models.IntegerField("金額", help_text="単位は日本円")
    quantity = models.IntegerField(verbose_name="数量", default=0)
    memo = models.CharField(verbose_name="メモ", max_length=500)

    def __str__(self):
        return self.memo


class User(models.Model):
    class Meta:
        verbose_name = "ユーザテーブル"
        verbose_name_plural = "ユーザテーブル"

    user_name = models.CharField(max_length=255, unique=True)
    address = models.CharField(max_length=255, unique=True)

    def __str__(self):
        return self.user_name

user@sinyblog:~/article 03_delete_records.md【パターン1】レコードを削除する — delete() の全パターン

テーブル定義はそのままに、データ行(レコード)だけを消したい場合は、Django の ORM が提供する delete() メソッドを使います。これが最もよく使う「削除」操作です。

① 単一レコードを削除

主キー(pk) で対象を絞り込んで削除します。

python— shell or view


from kakeibo.models import Kakeibo

# pk=5 のレコードを取得して削除
record = Kakeibo.objects.get(pk=5)
record.delete()
# (1, {'kakeibo.Kakeibo': 1}) ← 削除件数と内訳が返る
DoesNotExist 例外に注意

get() は対象が存在しないと DoesNotExist 例外を投げます。本番コードでは filter().first() + None チェック、または try/except で囲むのが安全です。

② 条件で複数レコードを一括削除

filter() で絞り込んだ QuerySet にそのまま delete() を呼ぶと、SQL の DELETE 文 1 発で一括削除 されます。Python のループで 1 件ずつ消すより圧倒的に高速です。

python— 一括削除


# 2024 年以前の家計簿レコードを全削除
from datetime import date
Kakeibo.objects.filter(date__lt=date(2024, 1, 1)).delete()

# 金額が 100 円未満のレコードを削除
Kakeibo.objects.filter(money__lt=100).delete()

# 特定カテゴリのレコードを削除
Kakeibo.objects.filter(category__category_name="食費").delete()

③ 全レコードを削除

テーブル内のすべてのレコードを削除する場合は all().delete() を使います。テーブル定義は残る ので、再度データを INSERT できる状態が保たれます。

python— 全件削除


# Kakeibo テーブルの全レコードを削除
Kakeibo.objects.all().delete()
本番環境では削除前に必ず件数確認

削除前に .count() で件数を確認するクセをつけると事故を防げます。filter の条件ミスで全削除…という事故は意外と多いです。

python— 削除前の安全確認


# まず削除対象の件数を確認
qs = Kakeibo.objects.filter(date__lt=date(2024, 1, 1))
print(f"削除対象: {qs.count()} 件")

# 想定通りの件数なら実行
qs.delete()

④ 関連レコード(ForeignKey)の連動削除

ForeignKey を持つモデルでは、親レコードを削除したときに子レコードがどうなるかを on_delete オプションで制御します。サンプルの Kakeibo モデルでは on_delete=models.PROTECT を指定しているので、参照されている Category は削除できません。

on_delete オプション 挙動
CASCADE 親を削除すると、参照している子レコードも自動削除
PROTECT 子レコードが残っている場合、親の削除を拒否(ProtectedError)
SET_NULL 親削除時、子の外部キーを NULL に置換(null=True 必須)
SET_DEFAULT 親削除時、子の外部キーをデフォルト値に置換
DO_NOTHING 何もしない(DB 側の制約に委ねる、上級者向け)
python— PROTECT の例


from kakeibo.models import Category

# Category("食費") が Kakeibo に参照されていると…
Category.objects.filter(category_name="食費").delete()
# → django.db.models.deletion.ProtectedError 発生!

# 先に子レコード(Kakeibo)を削除してから親を消す必要がある
Kakeibo.objects.filter(category__category_name="食費").delete()
Category.objects.filter(category_name="食費").delete()  # OK

user@sinyblog:~/article 04_drop_table.md【パターン2】テーブル(モデル)ごと削除する

こちらは少し重い操作で、「もう使わないモデルを撤去したい」場合の手順です。サンプルでは User テーブルが不要になったケースで進めます。

先に必ずバックアップ

本番 DB で実施する場合は、必ずスナップショット or dumpdata でバックアップを取ってから始めてください。途中失敗するとリカバリーが面倒です。

Step 1. 現状の整合確認

まず makemigrations で「変更なし」状態であることを確認します。

bash— 整合確認


python manage.py makemigrations
# No changes detected ← この状態にしてから次へ進む

python manage.py showmigrations
# kakeibo
#  [X] 0001_initial
#  [X] 0002_auto_20181204_1157
#  [X] 0003_kakeibo_quantity
#  [X] 0004_user

Step 2. Migrations 履歴を fake で巻き戻す

--fake オプション付きの migrate で、実 DB を変更せずに履歴だけ巻き戻します。

bash— 履歴を巻き戻す


python manage.py migrate --fake kakeibo zero
# Operations to perform:
#   Unapply all migrations: kakeibo
# Running migrations:
#   Unapplying kakeibo.0004_user... FAKED
#   Unapplying kakeibo.0003_kakeibo_quantity... FAKED
#   Unapplying kakeibo.0002_auto_20181204_1157... FAKED
#   Unapplying kakeibo.0001_initial... FAKED

python manage.py showmigrations
# kakeibo
#  [ ] 0001_initial
#  [ ] 0002_auto_20181204_1157
#  [ ] 0003_kakeibo_quantity
#  [ ] 0004_user
# ↑ [X] が [ ] に変わっていれば OK

Step 3. Migrations ファイルを物理削除

kakeibo/migrations/ 配下の __init__.py 以外xxxx.py ファイル(0001_initial.py など)を全て削除します。

bash— 削除確認


python manage.py showmigrations
# kakeibo
#  (no migrations) ← この状態になれば OK

Step 4. 実 DB から該当テーブルを DROP

SQLite3 の場合は dbshell から drop table で物理削除します。他の DB(PostgreSQL / MySQL)でも同等のコマンドで OK。

bash— SQLite3 dbshell


python manage.py dbshell

sqlite> .tables
auth_group                  django_content_type
auth_group_permissions      django_migrations
auth_permission             django_session
auth_user                   kakeibo_category
auth_user_groups            kakeibo_kakeibo
auth_user_user_permissions  kakeibo_user      ← これを消す
django_admin_log

sqlite> drop table kakeibo_user;
sqlite> .tables
# kakeibo_user が消えていることを確認

Step 5. models.py / admin.py から該当モデルの定義を削除

models.py から class User(models.Model): 全体を削除。admin.pyviews.py から User を参照している箇所も合わせて削除します。

Step 6. Migrations を再生成して整合をとる

bash— 再生成と整合化


# User を除いた状態で初期マイグレーションを再生成
python manage.py makemigrations
# Migrations for 'kakeibo':
#   kakeibo\migrations\0001_initial.py
#     - Create model Category
#     - Create model Kakeibo

# 既存テーブル(Category, Kakeibo)は実 DB に存在するので fake で履歴だけ進める
python manage.py migrate --fake-initial
# Applying kakeibo.0001_initial... FAKED

# 最終確認
python manage.py showmigrations
# kakeibo
#  [X] 0001_initial

python manage.py makemigrations kakeibo
# No changes detected in app 'kakeibo'

python manage.py runserver
# 起動して画面が問題なく動けば完了

user@sinyblog:~/article 05_flush_reset.md【パターン3】全データをリセットする — flush と DB 再生成

「テスト前に全データをまっさらにしたい」「開発環境のシードデータを入れ直したい」場合は、テーブル定義を残したままデータだけ消す flush コマンドが便利です。

flush — 全テーブルのデータを削除(構造は残る)

bash— データだけ全削除


python manage.py flush
# You have requested a flush of the database.
# This will IRREVERSIBLY DESTROY all data currently in the database
# Are you sure you want to do this?
#   Type 'yes' to continue, or 'no' to cancel: yes

テーブル構造はそのまま残るため、再度 INSERT できる状態が保たれます。スーパーユーザーも消えるので、必要なら再作成します。

DB ファイル削除 + 再生成(SQLite3 限定の最終手段)

SQLite3 の場合、開発環境なら DB ファイルを物理削除してから再 migrate するのが最速です。

bash— DB を完全初期化


# DB ファイルを削除
rm db.sqlite3        # macOS / Linux
del db.sqlite3       # Windows

# 全テーブルを再生成
python manage.py migrate

# スーパーユーザー再作成
python manage.py createsuperuser
本番環境では絶対やらない

DB ファイル削除は 開発環境専用 の操作です。本番では flush でも復元不可能。必ず事前バックアップ + 確認手順を徹底してください。

user@sinyblog:~/article 06_troubleshoot.mdよくあるトラブルと対処

症状 原因 対処
ProtectedError で削除できない ForeignKey の on_delete=PROTECT で参照中 先に子レコードを削除する。または on_delete=CASCADE に変更
django.db.utils.OperationalError: no such table migrate されていない or テーブルが手動 DROP された python manage.py migrate を実行
テーブル削除後に showmigrations が不整合 履歴と実 DB がズレている migrate --fake で履歴を実 DB に合わせる
delete() したのに件数が 0 のまま QuerySet を変数に入れる前に .delete() を呼んだ等の論理ミス .count() で対象件数を確認してから実行
大量データの delete() が遅い シグナル処理 + ForeignKey の連動チェック _raw_delete()(Django内部API)、または SQL 直接実行を検討

user@sinyblog:~/article 99_summary.mdまとめ — 用途別チートシート

用途別の選び方を一覧で振り返ります。

やりたいこと 使うコマンド
1 件だけ消したい Model.objects.get(pk=N).delete()
条件で複数消したい Model.objects.filter(...).delete()
あるテーブルの全レコード消したい Model.objects.all().delete()
全テーブルのデータだけ消したい python manage.py flush
不要モデル(テーブル)ごと撤去したい パターン2の Step 1〜6 を順に実施
開発環境を完全初期化したい DB ファイル削除 + python manage.py migrate

「削除」と一括りにしても、消したいレベル(レコード / テーブル / DB全体) によって使うコマンドが全く違います。本記事のパターンを使い分けて、安全かつ意図通りの削除を実現してください。

本記事は 2019 年 5 月に「Djangoで不要になったテーブルを削除する方法」として初版を公開し、2026 年 5 月にレコード削除(delete())の章と全データリセット(flush)の章を追加して、3 種類の削除パターンを完全カバーする総合ガイドに再構成しました。元のテーブル削除手順は維持しつつ、検索者の本命ニーズである「レコード削除」を最初に配置しています。運営者(現役 IT エンジニア・15 年以上の業界経験)。

おすすめの記事