riceshop のデータ移行・データベース運用に関する運用者向けドキュメントです。次の 3 つを扱います。
clear_orders 管理コマンドこのドキュメントは旧
specs/41_本番データ移行用管理コマンド 実装手順書.md(Ver.2.0) を、現行のdashboard/views.py(import_old_data_view)/dashboard/management/commands/clear_orders.py/.gitignoreと照合して再構成したものです。⚠️ 本書の操作は既存データを破壊的に置き換えるものを含みます。 実行前に必ず DB バックアップを取得してください。
開発環境と本番環境の DB 構造を常に一致させ、デプロイ時のエラーを防ぐため、以下の原則を守ります。
0001_initial.py などはソースの一部としてコミットします。makemigrations は開発環境でのみ実行する。 変更履歴は開発者の手元で生成・テストします。makemigrations を実行しない。 本番は Git から取得したマイグレーションを migrate で適用するだけです(→ operations/本番デプロイ)。実装メモ: 現行
.gitignoreでは、マイグレーションを除外する記述(*/migrations//!*/migrations/__init__.py)がコメントアウトされています。つまりマイグレーションファイルは意図どおり Git 管理対象です。
| 担当 | 操作 |
|---|---|
| 開発者(ローカル) | models.py 編集 → docker compose -f docker-compose.dev.yml exec app python manage.py makemigrations → migrate で動作確認 → マイグレーションを含めて git commit / git push |
| 運用管理者(本番) | git pull → docker compose up -d --build(entrypoint.sh が migrate を自動実行) |
旧システムからエクスポートした SQL ファイルをアップロードし、顧客(User)とお届け先(Destination)を一括取り込みする機能です。dashboard:import(/management/import/)の専用画面から行います(import_old_data_view)。
INSERT INTO 文を正規表現で解析し、テーブル名で振り分ける。
販売システムユーザー → ユーザー候補(3 列以上)顧客名簿 → お届け先候補(15 列以上)取り込みは transaction.atomic() の中で、先に既存データを削除してから新規作成します。削除対象は以下です。
Package(梱包)User に紐づく全 OrderDestinationUser(is_staff=False かつ is_superuser=False)その後、SQL から読み取ったユーザーを create_user(..., is_staff=False) で作成し、顧客名簿 のデータからお届け先を作成します。フィールドのマッピングは次のとおりです。
取り込み先(Destination) |
変換ルール |
|---|---|
name |
顧客名簿 の名称列 |
postal_code |
郵便番号列(空なら空文字) |
address |
住所の複数列を結合 |
phone |
電話番号列(空なら空文字) |
delivery_method |
旧「配送区分」が 持帰り なら TEWATASHI、それ以外は YAMATO |
shipping_zone |
旧「配送区分」が 遠地 なら ENCHI、それ以外は NORMAL |
⚠️ 列順依存: 上表は読みやすさのため列名ベースで示していますが、実装は列名(ヘッダ)を見ているわけではなく、
old_dest_data[1]/[4]/[5..8]/[10]/[13]/[14]のように INSERT 文の列位置(順序)に固定で読み取ります。旧 SQL の列順が変わると取り込みが壊れるため、移行元 SQL は現行の列順(old_data/旧システム顧客データ.sqlのINSERT INTO 顧客名簿 (...)と同じ並び)であることが前提です。
⚠️ 注意: この操作は一般顧客の既存アカウント・お届け先・注文・梱包をすべて削除してから取り込みます(スタッフ/スーパーユーザーは対象外)。初期移行を想定した機能であり、運用開始後の追加取り込みには適しません。実行前に必ず DB バックアップを取得してください。
transaction.atomic()で囲まれているため、取り込み処理の途中例外は DB レベルではロールバックされます。
Issue #9 対応済み:
dashboard/views.pyはdjango.shortcuts.redirectを import 済みで、取り込み後のredirect('dashboard:import')はNameErrorにならず実行できます。ただし、取り込み自体が既存の顧客・お届け先・注文・パッケージを全置換する破壊的処理であることは変わらないため、実行前のDBバックアップは必須です。
補足(移行元データ): リポジトリには移行元の SQL ファイルとして
old_data/旧システム顧客データ.sqlが含まれます(販売システムユーザー/顧客名簿の INSERT を含む実データ。ダミーのサンプルではありません)。.gitignoreにold_data/*がありますが、このファイルは既に Git 追跡済みのためリポジトリに含まれます(今後追加する dump は無視されます)。
注文・引当・梱包データを全削除し、在庫の total_ordered_kg を 0 にリセットする管理コマンドです。送料モデルの移行など、注文系をまっさらにしたい場合に使います。
docker compose exec app python manage.py clear_orders # 本番
docker compose -f docker-compose.dev.yml exec app python manage.py clear_orders # 開発
実装の詳細・削除対象テーブル・yes 確認・**途中失敗時の非原子性(TRUNCATE はロールバック不可)**については development/補足資料 §1.2 を参照してください。
⚠️ 注意: 破壊的かつ復元不可能です。本番では原則実行せず、必要な場合も実行前に DB バックアップ/スナップショットを取得してください(→ operations/本番デプロイ §5)。
本書の操作(旧データ移行の全置換、clear_orders)はいずれも既存データを失います。本番 DB は docker-compose.yml の named volume riceshop_db_data に保持されるため、実行前に MySQL のダンプ取得を推奨します。
年度締め画面からの取得(Issue #20):
/management/year-end/の「DBバックアップを確認しました」チェックボックス付近に「今すぐDBバックアップを取得してダウンロード」ボタンがあり、サーバー上での手動操作なしにブラウザへダンプをダウンロードできます(成功すると同チェックボックスが自動でチェックされる)。内部的には下記と同じmysqldumpをアプリコンテナ内から実行しています。詳細は features/管理者向け補助機能 §2.1.1。以下の手順は、ボタンが使えない場合やサーバー上で直接取得したい場合の手動手順です。
docker compose exec db sh -c 'mysqldump -u root -p"$MYSQL_ROOT_PASSWORD" "$MYSQL_DATABASE"' > backup_$(date +%Y%m%d).sql
⚠️ 環境変数の展開位置に注意:
$MYSQL_ROOT_PASSWORD/$MYSQL_DATABASEをdocker compose exec db mysqldump ...のように直接書くと、これらはホスト側シェルで先に展開されます。サーバーのシェルにenv.productionの値が入っていない場合は空文字になり、認証に失敗します。上記のようにsh -c '...'でコンテナ内のシェルに展開させるか、事前にホストでset -a; . env.production; set +aしてから実行してください(env_fileはコンテナにのみ環境変数を渡し、ホストシェルには入りません)。
(down -v で named volume を消すと本番 DB も失われる点は 本番デプロイ §6 を参照。)
取得した .sql ダンプから DB を復元する手順です。対象テーブルを上書きするため、実行前に流し込むファイルが正しいバックアップであることを確認してください。
アプリを停止する(復元中の書き込みによる不整合を防ぐため):
docker compose stop app
バックアップを流し込む(ファイルが存在し空でないことを先に確認します。cat ... | docker compose exec ... のようにパイプでつなぐと、cat がファイル不在で失敗しても mysql が空入力のまま正常終了し、復元されていないのに成功したように見えるため、リダイレクトを使います):
test -s backup_20260101.sql
docker compose exec -T db sh -c 'mysql -u root -p"$MYSQL_ROOT_PASSWORD" "$MYSQL_DATABASE"' < backup_20260101.sql
mysqldumpは既定で--opt(--add-drop-tableを含む)が有効なため、ダンプには各テーブルのDROP TABLE IF EXISTSが含まれています。対象データベースを事前に空にする必要はありません。環境変数の展開位置に関する注意点は §4 と同じで、sh -c '...'によりコンテナ内シェルで展開させています。-Tはdocker compose execの擬似 TTY 割り当てを無効化するオプションで、標準入力のリダイレクトを正しく渡すために必要です。
マイグレーション状態を確認する(バックアップ取得時点とコードのバージョンが食い違っていると、スキーマが一致しない可能性があります)。手順1で app を停止しているため docker compose exec app は使えません。--no-deps で db の起動待ちをスキップしつつ、エントリポイント(migrate を自動実行する entrypoint.sh)を使わない一時コンテナで確認します:
docker compose run --rm --no-deps --entrypoint python app manage.py showmigrations
未適用のマイグレーションが表示された場合、バックアップ取得時点に近いコードへ戻すか、migrate で追いつかせるかを状況に応じて判断してください。
アプリを再開し、動作確認する:
docker compose start app
clear_orders の実装詳細 → development/補足資料元資料: specs/41_本番データ移行用管理コマンド 実装手順書.md (Ver.2.0) を現行コード(dashboard/views.py の import_old_data_view, dashboard/management/commands/clear_orders.py, .gitignore, docker-compose.yml)と照合して再構成
関連: README, specs棚卸し表, Issue #1