はじめに
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 側で描画処理を行うよう修正 しました。
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)
// 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のレスポンスが正しくても、データをフロントで適切に描画しなければ意味がない
「データはあるのに表示されない」 という現象は、フロント側の処理不足が原因であることが多い。
✅ フロントエンドとバックエンドの「データの受け渡し」を意識することが大事