Django Rest Framework チュートリアル 

2023/08/29に公開

やること

Django Rest Framework(今後DRFと呼称)でapiを作成し、user情報を確認する。

環境

  • python version 3.9.17
  • Django version 4.2.3
  • Django Rest Framework version 3.14.0
  • Docker上での開発

ディレクトリ構造

/drfTest
├── drfTest/
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   ├── wsgi.py
├── manage.py

前準備

DRFを導入し、accountsというアプリを作成しておく。
するとディレクトリ構造としてはこうなる

ディレクト構造
./drfTest/
├── accounts/
│   ├── admin.py
│   ├── apps.py
│   ├── models.py
│   ├── tests.py
│   ├── views.py
├── drfTest/
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   ├── wsgi.py
├── db.sqlite3
├── manage.py

ユーザーモデルの作成

from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from django.db import models

class CustomUserManager(BaseUserManager):
    def create_user(self, email, password=None, **extra_fields):
        if not email:
            raise ValueError("The Email field must be set")
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, password=None, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')

        return self.create_user(email, password, **extra_fields)

class CustomUser(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(unique=True)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    date_joined = models.DateTimeField(auto_now_add=True)
    password = models.CharField(max_length=128)

    objects = CustomUserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['password']

    def __str__(self):
        return self.email

上記コードを入力したらターミナルで

terminal
python manage.py makemigrations
python manage.py migrate

上記コマンドを入力し、マイグレーションする。

ユーザ作成

ターミナルでユーザーを作成する。

terminal
python manage.py createsuperuser --email admin@example.com --password 1234

このコマンドで下記のユーザができる

シリアライザーとViewSetの作成

accountsフォルダ内にserializers.pyを作成する。
その後、下記のコードを入力する。

accounts/serializers.py
from rest_framework import serializers
from .models import CustomUser


class CustomUserSerializer(serializers.ModelSerializer):
    class Meta:
        model = CustomUser
        fields = ['id', 'email', 'password']
        extra_kwargs = {'password': {'write_only': True}}

    def create(self, validated_data):
        user = CustomUser(
            email=validated_data['email'],
            username=validated_data['username']
        )
        user.set_password(validated_data['password'])
        user.save()
        return user

serializers.pyの補足

  • extra_kwargsで何をしているか?
    • passwordフィールドをwrite_onlyにすることで、クライアントはpasswordの情報を書き込むことはできるが、読み取りができなくなる。
  • 'create'メソッドとは?
    • API経由で新しいデータを作成するメソッド。DRF側で作成されているため、別の名前では機能しない
accounts/views.py
from django.shortcuts import render
from .models import CustomUser
from rest_framework import viewsets
from rest_framework import permissions
from .serializers import CustomUserSerializer

class CustomUserViewSet(viewsets.ModelViewSet):
    queryset = CustomUser.objects.all()
    serializer_class = CustomUserSerializer
    permission_classes = [permissions.IsAuthenticated]

views.pyの補足

  • permission_classesとはなにか?
    • このデータにアクセスできる権限の設定。

ルーティングの設定

下記コードを記述

drfTest/urls.py
from django.urls import include, path
from rest_framework import routers
from accounts import views

router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)

urlpatterns = [
    path('', include(router.urls)),
    path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
    ]

ページネーションの設定

drfTest/settings.py
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 10
}

また、settings.pyにrest-frameworkを追加する

drfTest/settings.py
INSTALLED_APPS = [
    ...
+    'rest_framework',
]

テストしてみる

terminal
python manage.py runserver 8001

上記コマンドでDjangoサーバーを起動して、
http://localhost:8001/users にアクセスすると作成したすべてのユーザーをGETすることができる。

また、http://localhost:8001/users/1 にアクセスするとことで id = 1のユーザのみを取得することが可能である。

改善するとしたら?

  • usersでアクセスしたらすべてのユーザーが表示されてしまうので、それができないようにする。
  • idをUUIDにすることで推測をできなくさせ、自身の情報だけを見られるようにする。

参考

最初に書いたものと同じだが改めて記す。

https://www.django-rest-framework.org/tutorial/quickstart/

Discussion