Django×Supabase×GASをつかってスプレッドシートのデータを登録したい。

# Supabase → Django(Pyenv) → GAS スプレッドシート連携フロー

> **Django×Supabase×GASをつかってスプレッドシートのデータの登録方法を教えてほしいとなったのでメモ**:
>
> * **OS**: Windows 11 (WSL2) / macOS / Linux
> * **エディタ**: Cursor (VS Code ベース)
> * **DB**: Supabase (PostgreSQL)
> * **バックエンド**: Django 5.x（Pyenv で隔離）
> * **同期**: GAS
>
> 所要時間: 20–40 分

---

## 0. 事前準備

| 作業                | チェックポイント                                                                                                                                    |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| Supabase プロジェクト作成 | ダッシュボード → **Project → Settings → Database**<br>**Host / Port / User / Password** をメモ。<br>Network Restrictions は `0.0.0.0/0` にするとローカルから接続可能。 |
| Python & Pyenv    | macOS/Linux: `brew install pyenv`<br>Windows ネイティブ: [pyenv-win](https://github.com/pyenv-win/pyenv-win)  または **WSL2** 推奨                    |
| Google アカウント      | GAS でスプレッドシートが操作できるアカウント                                                                                                                    |

---

## 1. Supabase 接続情報を控える

ダッシュボード上部の **Connect** → *Direct connection* を開きます。

```txt
postgresql://postgres:<YOUR-PASSWORD>@db.<PROJECT-REF>.supabase.co:5432/postgres
```

| 変数       | 例                                   | `.env` でのキー                     |
| -------- | ----------------------------------- | ------------------------------- |
| Host     | `db.<project-ref>.supabase.co`      | `SUPABASE_HOST`                 |
| Port     | `5432`                              | `SUPABASE_PORT`                 |
| DB       | `postgres`                          | `SUPABASE_DB_NAME`              |
| User     | `postgres`                          | `SUPABASE_DB_USER`              |
| Pass     | `<YOUR-PASSWORD>`                   | `SUPABASE_DB_PASSWORD`          |
| URL      | `https://<project-ref>.supabase.co` | `SUPABASE_URL` (Settings › API) |
| anon key | `********`                          | `SUPABASE_KEY` (Settings › API) |

> **セキュリティ**: `.env` は必ず `.gitignore` に追加し、Git へはコミットしません。

---

## 2. Pyenv + Django 環境構築

```bash
# ルートフォルダ（例: recruit_app）を作成して移動
mkdir recruit_app && cd $_

# Pyenv で Python を取得
pyenv install 3.12.3
pyenv local 3.12.3

# 仮想環境
python -m venv .venv
source .venv/bin/activate       # Windows: .venv\Scripts\Activate.ps1

# パッケージ
pip install --upgrade pip wheel
pip install django psycopg2-binary python-dotenv
```

---

## 3. Django プロジェクト / アプリ & モデル作成

```bash
django-admin startproject config .   # manage.py が直下にできる
python manage.py startapp sheets     # アプリ名は自由
```

### `sheets/models.py`

```python
from django.db import models

class Recruit(models.Model):
    sheet_name = models.TextField()
    status     = models.TextField()
    name       = models.TextField()

    class Meta:
        db_table = "recruit"   # Supabase で作られるテーブル名
```

### `config/settings.py` 追記

```python
from pathlib import Path
import os
from dotenv import load_dotenv

load_dotenv()

INSTALLED_APPS += [
    "sheets",
]

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        "NAME"    : os.getenv("SUPABASE_DB_NAME"),
        "USER"    : os.getenv("SUPABASE_DB_USER"),
        "PASSWORD": os.getenv("SUPABASE_DB_PASSWORD"),
        "HOST"    : os.getenv("SUPABASE_HOST"),
        "PORT"    : os.getenv("SUPABASE_PORT", "5432"),
    }
}
```

### .env (例)

```env
SUPABASE_HOST=db.********.supabase.co
SUPABASE_PORT=5432
SUPABASE_DB_NAME=postgres
SUPABASE_DB_USER=postgres
SUPABASE_DB_PASSWORD=********
SUPABASE_URL=https://********.supabase.co
SUPABASE_KEY=********
```

---

## 4. マイグレーション → Supabase にテーブル作成

```bash
python manage.py makemigrations sheets
python manage.py migrate
```

Supabase ダッシュボードの **Table Editor** に `recruit` が現れれば成功です。

---

## 5. GAS でスプレッドシート → Supabase へ同期

### 5‑1. スクリプトエディタを開く

シート上部メニュー **拡張機能 › Apps Script** で新規プロジェクトを追加し、`Code.gs` に下記を貼り付けます。

```javascript
/**
 * スプレッドシートの行データを Supabase recruit テーブルへ同期
 * 3 行目以降 → 一括 INSERT (必要なら UPSERT も可)
 */
function syncRecruit() {
  /* === ① 設定 === */
  const SUPABASE_URL = "https://<PROJECT-REF>.supabase.co/rest/v1/recruit"; // ← rest/v1/<テーブル名>
  const SUPABASE_KEY = "<YOUR-ANON-KEY>";                                  // anon か service_role
  const SHEET        = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const HEADER_ROW   = 2;   // ヘッダー
  const DATA_START   = 3;   // データ開始

  /* === ② データ取得 === */
  const sheetName = SHEET.getName(); // 2つ目のシート名にはシート名をいれたい。
  const lastRow   = SHEET.getLastRow();
  const lastCol   = SHEET.getLastColumn();
  if (lastRow < DATA_START) return;

  const headers = SHEET.getRange(HEADER_ROW, 1, 1, lastCol).getValues()[0].map(v => (v+"").trim());
  const rows    = SHEET.getRange(DATA_START, 1, lastRow - DATA_START + 1, lastCol).getValues();

  const payload = rows.filter(r => r.join("") !== "").map(r => {
    const rec = { sheet_name: sheetName };
    headers.forEach((h,i)=>{ if(h) rec[h]=r[i]; });
    return rec;
  });
  if (!payload.length) return;

  /* === ③ Supabase へ送信 === */
  const options = {
    method : "post",                       // 全行 INSERT なら post
    contentType: "application/json",
    headers: {
      apikey: SUPABASE_KEY,
      Authorization: "Bearer "+SUPABASE_KEY,
      Prefer: "return=minimal"           // patch の場合は resolution=merge-duplicates を付与
    },
    payload: JSON.stringify(payload),
    muteHttpExceptions: true,
  };
  const res = UrlFetchApp.fetch(SUPABASE_URL, options);
  Logger.log(res.getResponseCode()+": "+res.getContentText());
}
```

> **ポイント**
>
> * Supabase の REST エンドポイントは `https://<project>.supabase.co/rest/v1/<table>`。
> * anon key で **RLS 有効**かつ `recruit` に `enable row level security;` ＋ ポリシー適用済みが前提。
> * 既存行を更新したい場合は `method:"patch"` にし、`Prefer:"resolution=merge-duplicates"` を付ける。

### 5‑2. スケジューラ（トリガー）設定（任意）

Apps Script エディタ左側 **トリガー › +** で関数 `syncRecruit` を 15 分毎などに設定すると自動同期が可能です。

---

## 6. 動作確認フロー

1. **Supabase** で `recruit` テーブルが空であることを確認。
2. スプレッドシートにデータ行を入力。
3. Apps Script ▶︎ 実行 ▶︎ `syncRecruit`
4. Supabase の Data/Editor でレコードが入っていれば OK。
5. Django 管理画面 (`/admin`) からも同じデータが読み出せることを確認。

---

## 7. 今後の予定

1. 登録するカラムを増やす。
2. DjangoでCRUDをできるようにする。
3. スプレッドシートとDBを５分ごとに同期する。 
---