ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
| この記事の要点 |
|
4 つのアプローチ
| 方法 | 用途 | 長所 | 短所 |
|---|---|---|---|
1. JsonResponse 直接 | 小規模 API、単純レコード | 追加依存ゼロ、最速 | フィールド指定が手動 |
2. django.core.serializers | QuerySet 丸ごと | 標準同梱 | 独特なラップ形式 |
3. DRF ModelSerializer | ★ 本格 API | 宣言的、バリデーション付き | パッケージ追加 |
4. 自作 to_dict() | カスタム整形 | 柔軟 | メンテ負担 |
方法1: JsonResponse で直接返す
from django.http import JsonResponse
from .models import Book
def book_detail(request, pk):
book = Book.objects.get(pk=pk)
return JsonResponse({
'id': book.id,
'title': book.title,
'isbn': book.isbn,
'published_at': book.published_at.isoformat(), # date → ISO 文字列
'author': {
'id': book.author.id,
'name': book.author.name,
},
})
# QuerySet をリストで返す
def book_list(request):
qs = Book.objects.select_related('author').all()
data = [{
'id': b.id,
'title': b.title,
'author': b.author.name,
} for b in qs]
return JsonResponse({'count': len(data), 'results': data})
# ↑ safe=False が必要な場合は: JsonResponse(data, safe=False)
safe=False の話
JsonResponse はデフォルトで辞書のみ受け付けます。リストを直接返したい場合は safe=False を付けます:
return JsonResponse([{'a': 1}, {'b': 2}], safe=False)
# safe=True (既定) で list を渡すと TypeError 発生
# JSON Hijacking 対策で禁止されている、ラップ推奨:
return JsonResponse({'data': [{'a': 1}, {'b': 2}]})
方法2: django.core.serializers
from django.core import serializers
from django.http import HttpResponse
from .models import Book
def book_list_json(request):
qs = Book.objects.all()
data = serializers.serialize('json', qs, fields=('title', 'isbn'))
return HttpResponse(data, content_type='application/json')
# 出力例
# [
# {"model": "library.book", "pk": 1,
# "fields": {"title": "Python入門", "isbn": "9784..."}},
# ...
# ]
独自のフォーマット(model / pk / fields)でラップされるため、フロント側が普通の JSON を期待していると扱いにくい点に注意。fixture 形式に近い。
方法3: Django REST Framework(推奨)
pip install djangorestframework
# settings.py
INSTALLED_APPS += ['rest_framework']
ModelSerializer
# serializers.py
from rest_framework import serializers
from .models import Book, Author
class AuthorSerializer(serializers.ModelSerializer):
class Meta:
model = Author
fields = ['id', 'name', 'birth_date']
class BookSerializer(serializers.ModelSerializer):
author = AuthorSerializer(read_only=True) # ネスト表示
author_id = serializers.PrimaryKeyRelatedField(
queryset=Author.objects.all(), source='author', write_only=True
)
# 計算項目
is_recent = serializers.SerializerMethodField()
class Meta:
model = Book
fields = ['id', 'title', 'isbn', 'published_at',
'author', 'author_id', 'is_recent']
read_only_fields = ['id']
def get_is_recent(self, obj):
from datetime import date
return (date.today() - obj.published_at).days < 90
# views.py
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .serializers import BookSerializer
@api_view(['GET'])
def book_list(request):
qs = Book.objects.select_related('author').all()
ser = BookSerializer(qs, many=True)
return Response(ser.data)
@api_view(['POST'])
def book_create(request):
ser = BookSerializer(data=request.data)
ser.is_valid(raise_exception=True)
ser.save()
return Response(ser.data, status=201)
ViewSet + Router でフル CRUD
from rest_framework import viewsets
from rest_framework.routers import DefaultRouter
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.select_related('author')
serializer_class = BookSerializer
router = DefaultRouter()
router.register(r'books', BookViewSet)
urlpatterns = router.urls
# → /books/ (GET, POST), /books/<id>/ (GET, PUT, PATCH, DELETE) 自動生成
Date / UUID / Decimal の扱い
Python 標準の json.dumps() は date / datetime / Decimal / UUID をそのままシリアライズできません:
import json
from datetime import date
from decimal import Decimal
from uuid import uuid4
data = {'d': date.today(), 'p': Decimal('123.45'), 'u': uuid4()}
# ❌ TypeError: Object of type date is not JSON serializable
json.dumps(data)
# ✅ Django 標準のエンコーダを使う
from django.core.serializers.json import DjangoJSONEncoder
json.dumps(data, cls=DjangoJSONEncoder)
# {"d": "2025-01-15", "p": "123.45", "u": "..."}
# JsonResponse は内部で DjangoJSONEncoder を使うので OK
from django.http import JsonResponse
JsonResponse(data) # 動く
各型の出力フォーマット
| Python 型 | JSON 出力 |
|---|---|
date | "2025-01-15" |
datetime | "2025-01-15T10:00:00+09:00" |
time | "10:00:00" |
timedelta | "3 12:00:00" |
Decimal | "123.45"(文字列) |
UUID | "550e8400-e29b-41d4-a716-446655440000" |
Promise (lazy) | str() 評価後の文字列 |
ネスト関係の扱い
# Author → Book[]
class AuthorWithBooksSerializer(serializers.ModelSerializer):
books = BookSerializer(many=True, read_only=True) # related_name='books' で逆参照
class Meta:
model = Author
fields = ['id', 'name', 'books']
# 出力
# {
# "id": 1, "name": "村上春樹",
# "books": [
# {"id": 11, "title": "...", "isbn": "..."},
# {"id": 12, "title": "...", "isbn": "..."}
# ]
# }
# depth で簡易ネスト(書き込みは不可)
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
depth = 1 # ForeignKey が自動ネスト
SerializerMethodField で計算項目
class BookSerializer(serializers.ModelSerializer):
days_since_published = serializers.SerializerMethodField()
author_name = serializers.CharField(source='author.name', read_only=True)
full_url = serializers.SerializerMethodField()
class Meta:
model = Book
fields = ['id', 'title', 'author_name',
'days_since_published', 'full_url']
def get_days_since_published(self, obj):
from datetime import date
return (date.today() - obj.published_at).days
def get_full_url(self, obj):
request = self.context.get('request')
return request.build_absolute_uri(f'/books/{obj.id}/') if request else None
パフォーマンス: N+1 を避ける
# ❌ N+1: author を毎回 SELECT
qs = Book.objects.all()
BookSerializer(qs, many=True).data
# SELECT * FROM book;
# SELECT * FROM author WHERE id=1; ← N 回
# SELECT * FROM author WHERE id=2;
# ...
# ✅ select_related (1:1, ForeignKey)
qs = Book.objects.select_related('author')
# ✅ prefetch_related (1:N, M:N)
qs = Author.objects.prefetch_related('books')
# ✅ さらに細かく
qs = Author.objects.prefetch_related(
Prefetch('books', queryset=Book.objects.filter(is_published=True))
)
ページネーション
# settings.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 20,
}
# 出力
# {
# "count": 145,
# "next": "http://localhost:8000/books/?page=2",
# "previous": null,
# "results": [ ... ]
# }
# Cursor 方式(大量データ向け)
class BookCursor(CursorPagination):
ordering = '-published_at'
page_size = 50
カスタム to_dict() アプローチ
# models.py に直接生やす
class Book(models.Model):
title = models.CharField(max_length=200)
isbn = models.CharField(max_length=13)
def to_dict(self, *, with_author=False):
d = {
'id': self.id,
'title': self.title,
'isbn': self.isbn,
}
if with_author:
d['author'] = self.author.to_dict()
return d
# views.py
def book_list(request):
qs = Book.objects.select_related('author')
return JsonResponse({'results': [b.to_dict(with_author=True) for b in qs]})
FAQ
Q: JsonResponse と HttpResponse の違いは?
A: JsonResponse は内部で json.dumps(cls=DjangoJSONEncoder) を呼び、Content-Type: application/json を自動付与します。素の HttpResponse だと両方手動。
Q: 日付のタイムゾーンが UTC で返ってしまう
A: settings.py の TIME_ZONE と USE_TZ=True を確認。表示用に Asia/Tokyo へ変換するには django.utils.timezone.localtime()。
Q: DRF を入れずに JWT 認証だけ追加したい
A: PyJWT で自前実装が可能ですが、djangorestframework-simplejwt 経由が圧倒的に安全・速いです。
ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
子ページはありません
- 環境構築とプロジェクト/アプリの作成
- MVC(MVT)のそれぞれの使い方と説明
- データベースへの接続と操作
- Django Administration
- git管理
- エラー一覧
- バージョンの確認方法
- ログ出力方法
- SQLのログ出力方法
- ログのローテート設定
- settings.pyの定数にアクセスする方法
- 本番環境へのインストールとアプリのデプロイ(apache編)
- 本番環境へのインストールとアプリのデプロイ(nginx編)
- djangoアプリの本番の開始URLを変更する
- 静的(static)ファイルの置き場所と読み込み(画像、css、js )
- CSRFトークンをAjaxで使用する方法
- ajaxの使用例(POST編)
- ファイルのアップロードとファイルの名前
- クイックスタート/チュートリアル
- ログイン機能
- テンプレート側のログイン判定
- ビュー側のログイン判定
- 管理者ユーザーの作成/判定と管理画面
- モデルのjson化とレスポンス
- runserverでポートを指定する方法
- cronによるバッチ実行
- テンプレートで利用する共通のcontextを定義する方法
- プログラムが本番サーバーで反映されない場合の対処法
- APIの作成
- cron用コマンド・ファイルの作成
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript base URL 取得方法|window.location.origin と SSR/Node.js 対応
- 4 YouTube Data API v3 エラー一覧|403/400/404 の主要原因と切り分け
- 5 Spring Frameworkのアノテーション一覧
- 6 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 7 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- IPv6とは|128bitアドレス・コロン16進表記/::省略・リンクローカル・SLAAC・デュアルスタック NEW 2026-06-22 12:34:44
- VPNとは|暗号トンネル・サイト間/リモートアクセス・IPsec/SSL-VPN/WireGuardを解説 NEW 2026-06-22 12:19:10
- MAC アドレスフィルタリングの仕組みと限界 | ネットワーク入門 NEW 2026-06-22 12:19:10
- HTTP/3 (QUIC) とは UDP ベースの低遅延 Web 通信 | ネットワーク入門 NEW 2026-06-22 12:17:25
- WebRTC とは ブラウザ間 P2P の音声・映像・データ通信 | ネットワーク入門 NEW 2026-06-22 12:17:25
- WebSocket とは 全二重リアルタイム通信 ws/wss | ネットワーク入門 NEW 2026-06-22 12:17:25
- gRPC とは HTTP/2 + Protocol Buffers の高速 RPC | ネットワーク入門 NEW 2026-06-22 12:17:25
- HTTP/2 とは 多重化・HPACK・バイナリフレーム | ネットワーク入門 NEW 2026-06-22 12:17:25
- Web通信プロトコル入門 HTTP/2・HTTP/3・WebSocket・gRPC・WebRTC | ネットワーク入門 NEW 2026-06-22 12:17:25
- CDN とは エッジキャッシュ・TTL・Cloudflare/CloudFront | ネットワーク入門 NEW 2026-06-22 12:17:24
- 証明書と認証局(CA)とは|X.509・信頼チェーン・DV/OV/EV・失効(CRL/OCSP)を解説 NEW 2026-06-22 12:17:24
- HAProxy とは frontend/backend と設定例 | ネットワーク入門 NEW 2026-06-22 12:17:24
- ファイアウォールとは|パケットフィルタ・ステートフル・DMZ・次世代FW(L4/L7)を解説 NEW 2026-06-22 12:17:24
- TLS/SSLの仕組み|ハンドシェイク・暗号スイート・前方秘匿性・証明書検証をわかりやすく解説 NEW 2026-06-22 12:17:24
- iptables/nftablesとは|テーブル・チェーン・ルール例・永続化をLinux視点で解説 NEW 2026-06-22 12:17:24
コメントを削除してもよろしいでしょうか?