0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Django API でデータが取得できても表示されない問題と解決方法

Posted at

はじめに

DjangoでAPIを利用してデータを取得するページを作った際に、「JSONデータがそのままブラウザに表示される」 という問題に遭遇しました。

エラー内容

今回、DjangoのAPI を利用してデータを取得するページを作ったところ、「JSONデータがそのままブラウザに表示される」 という問題に遭遇しました。

理想としては、フォームと取得データを組み合わせたページ表示を期待値としていました。
「なぜ?」という視点でデバッグを進めた結果、API のデータをフロントに適切に渡すための重要なポイントが見えてきた。

原因の特定

画面に表示されたJSON情報

  "obtained_batches": [
    {
      "id": 3,
      "name": "バッジA",
      "description": "3本の映画を視聴",
      "icon": "badges/tree-movie_YI1I6m6.jpeg"
    },
    {
      "id": 4,
      "name": "バッジB",
      "description": "1日3本の映画を視聴",
      "icon": "badges/Triple_Movie_Streak.jpg"
    }
  ],
  "unobtained_batches": []
}

問題の原因を特定するため、以下の3つの仮説を立てました。

🔹仮説1:ビューが JSON 形式でデータを返している
  → Djangoのビューで JsonResponse を使っているため
   HTML ではなく JSONデータのみをレスポンスとして
   返している 可能性。

🔹仮説2:フロントエンド側の処理が不足している
  → API からデータを取得した後、それを HTML に
   適用する処理が不足している 可能性。

🔹 仮説3:APIのエンドポイント設計の問題
  → もともとこのエンドポイントは「データのみを返す」
   仕様だった?

  → ページで表示するには、別途 HTML を適用する
  ビュー必要だったのでは?

修正対応

Django 側の修正(views.py)

問題は 「データ取得後のフロント側の処理が抜けていた」 ことだったため、以下のように JSON を取得後、JavaScript 側で描画処理を行うよう修正 しました。

views.py
from django.http import JsonResponse
from django.views import View
from .models import UserBatch, Batch

class BatchListView(View):
    def get(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            return JsonResponse({"error": "Unauthorized"}, status=401)

        user = request.user
        obtained_batches = UserBatch.objects.filter(user=user).values_list('batch', flat=True)
        obtained_batches_list = Batch.objects.filter(id__in=obtained_batches).values("id", "name", "description", "icon")
        unobtained_batches_list = Batch.objects.exclude(id__in=obtained_batches).values("id", "name", "description", "icon")

        return JsonResponse({
            "obtained_batches": list(obtained_batches_list),
            "unobtained_batches": list(unobtained_batches_list),
        })

フロントエンドの修正(JavaScript)

batch_list.js
// UI を更新する関数(取得済み・未取得のバッジを表示)
window.updateUI = function () {
    if (!window.apiData || typeof window.apiData !== "object") return;

    const obtainedBadgesElement = document.getElementById("obtained-badges");
    const unobtainedBadgesElement = document.getElementById("unobtained-badges");

    if (!obtainedBadgesElement || !unobtainedBadgesElement) return;

    // 取得済みバッジのリストを更新
    obtainedBadgesElement.innerHTML =
        window.apiData.obtained_batches.length > 0
            ? window.apiData.obtained_batches.map(badge => `
                <div class="badge-item">
                    <img src="${badge.icon || '/static/images/default_badge.png'}" class="badge-img" alt="${badge.name}">
                    <p class="badge-title">${badge.name}</p>
                </div>
            `).join("")
            : "<p>まだ取得済みのバッジはありません。</p>";

    // 未取得バッジのリストを更新
    unobtainedBadgesElement.innerHTML =
        window.apiData.unobtained_batches.length > 0
            ? window.apiData.unobtained_batches.map(badge => `
                <div class="badge-item badge-unobtained">
                    <img src="${badge.icon || '/static/images/default_badge.png'}" class="badge-img" alt="${badge.name}">
                    <p class="badge-title">${badge.name}</p>
                </div>
            `).join("")
            : "<p>未取得のバッジはありません。</p>";
};

// バッジデータ取得に失敗した場合、エラーメッセージを表示
function showError(message) {
    document.getElementById("obtained-badges").innerHTML = `<p class='text-danger'>${message}</p>`;
    document.getElementById("unobtained-badges").innerHTML = `<p class='text-danger'>${message}</p>`;
}

// APIからバッジデータを取得する関数
async function loadBatches() {
    try {
        const response = await fetch("/missions/user_batches", {
            method: "GET",
            credentials: "include",
            headers: {
                "Content-Type": "application/json",
                "Accept": "application/json"
            }
        });

        if (!response.ok) throw new Error(`API エラー: ${response.status} ${response.statusText}`);

        window.apiData = await response.json();
        updateUI();

    } catch (error) {
        showError("バッジデータの取得に失敗しました。");
    }
}

// ページロード時にバッジデータを取得
document.addEventListener("DOMContentLoaded", loadBatches);

修正結果

修正前
JSON がそのまま表示される
フロントエンドでデータを受け取れていない

修正後
updateUI() 関数を実装し、データを HTML に適用
バッジのリストが正常にレンダリングされるようになった

今回の学び

✅ APIを利用すると、データの流れが変わる
Djangoのテンプレートエンジンでは、バックエンドでデータを直接 HTML に埋め込むが、API ではデータ取得と描画を別々に考える必要がある。

✅ APIのレスポンスが正しくても、データをフロントで適切に描画しなければ意味がない
「データはあるのに表示されない」 という現象は、フロント側の処理不足が原因であることが多い。

✅ フロントエンドとバックエンドの「データの受け渡し」を意識することが大事

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?