## 経緯
ミニマムプロジェクトで動作確認したいときに毎回つくるのは心理的ハードルが高いので、[[🦉Toki]]でサクっと作れるようにしたい。
以下のような手順を想定。
<div class="link-card-v2">
<div class="link-card-v2-site">
<img class="link-card-v2-site-icon" src="https://publish-01.obsidian.md/access/35d05cd1bf5cc500e11cc8ba57daaf88/favicon-64.png" />
<span class="link-card-v2-site-name">Minerva</span>
</div>
<div class="link-card-v2-title">
📜2025-09-24 Django REST frameworkを学習してみる
</div>
<div class="link-card-v2-content">仕事でDjango REST frameworkを使う必要が生じ、機能が多く把握しきれなかったため、Django 4.2とDRF 3.16.1を用いて体系的な学習を開始した。環境構築では依存関係やバージョン選定、PostgreSQL導入、psycopg3の利用などに取り組み、SerializerやModelSerializerの実装、APIエンドポイント作成、Brunoによる動作確認までを段階的に実施した。</div>
<img class="link-card-v2-image" src="https://publish-01.obsidian.md/access/35d05cd1bf5cc500e11cc8ba57daaf88/Notes/attachments/activity.webp" />
<a data-href="📜2025-09-24 Django REST frameworkを学習してみる" class="internal-link"></a>
</div>
%%[[📜2025-09-24 Django REST frameworkを学習してみる]]%%
## 手順をスクリプト化
```console
mkdir drf-sandbox
cd drf-sandbox
uv init
uv add django==4.2 djangorestframework django-stubs django-types
```
## テンプレ
以下のコマンドで生成されるものはテンプレにしておきたい
```console
uv run django-admin startproject project .
cd project
uv run django-admin startapp app
rm main.py
```
```console
cd ..
uv run python manage.py makemigrations \
&& uv run python manage.py migrate
```
## ベースファイル
`settings.py` はこちらで作成したほうがいい。`rest_framework` を入れないといけないので。
`project/app/apps.py`
```python
from django.apps import AppConfig
class AppConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "project.app"
```
`project/app/models.py`
```python
from django.contrib.auth.models import User
from django.db import models
from rest_framework.fields import uuid
ANIMAL_KIND = (
("dog", "犬"),
("cat", "猫"),
("owl", "フクロウ"),
("gorilla", "ゴリラ"),
)
class Animal(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=100, blank=True, default="")
description = models.TextField()
proper = models.BooleanField(default=False)
kind = models.CharField(choices=ANIMAL_KIND, default="owl", max_length=32)
owner = models.ForeignKey(User, related_name="animals", on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ["created"]
```
`project/app/serializers.py`
```python
from django.contrib.auth.models import User
from rest_framework import serializers
from project.app.models import Animal
class AnimalSerializer(serializers.ModelSerializer):
class Meta:
model = Animal
fields = "__all__"
class UserSerializer(serializers.ModelSerializer):
animals = AnimalSerializer(many=True)
class Meta:
model = User
fields = ["id", "username", "animals"]
```
## データ初期化ファイル
```console
uv run python manage.py shell < init.py
```
`init.py`
```python
from django.contrib.auth.models import User
from django.db import transaction
from project.app.models import Animal
with transaction.atomic():
User.objects.all().delete()
User.objects.create_superuser(id=1, username="admin", password="password")
User.objects.bulk_create(
[
User(id=2, username="ミネルヴァ"),
User(id=3, username="オブシディア"),
User(id=4, username="ネオちゃん"),
]
)
with transaction.atomic():
Animal.objects.all().delete()
Animal.objects.bulk_create(
[
Animal(
name="みみぞう",
description="ピーッ!",
proper=True,
kind="owl",
owner_id=2, # ミネルヴァ
),
Animal(
name="タツヲ",
description="ウホ♡",
proper=True,
kind="gorilla",
),
Animal(
name="ポチ",
description="ワンワン!",
proper=False,
kind="dog",
owner_id=4, # ネオちゃん
),
]
)
```
## 動作確認コマンド
```console
curl -s "localhost:8000/users/" | jq
curl -s "localhost:8000/animals/" | jq
```