DjangoでAPIを実装する方法2(Django REST framework)
DjangoでAPIを実装する方法(Django REST framework)の続きです。
以前作成した以下のモジュールに「Django REST framework」を組み込みます。
DjangoでListViewを用いて検索画面を実装する方法
目次
条件
- Django 2.1.7
- Python 3.7.0
- djangorestframework 3.9.2
実装
settings.py
INSTALLED_APPSに「rest_framework」を追加します。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'search.apps.SearchConfig',
"bootstrap4",
'rest_framework', # 追加
]
APIのページネーションを設定するため、以下を追記します。
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10
}
urls.py
プロジェクトのurls.py
以下を追記します。
from rest_framework.schemas import get_schema_view
schema_view = get_schema_view(title='ListSample API')
urlpatterns = [
・・・
path('api-auth/', include('rest_framework.urls')), # API認証
path('schema/', schema_view), # APIスキーマ
]
アプリケーションのurls.py
以下を追記します。
from django.urls import include
from rest_framework.routers import DefaultRouter
# Create a router and register our viewsets with it.
router = DefaultRouter()
router.register('posts', views.PostViewSet)
router.register('users', views.UserViewSet)
urlpatterns = [
・・・
# APIのルート
path('api/', include(router.urls)),
]
models.py
以下のようなモデルとします。
「related_name=’posts’,」を追記します。
from django.db import models
from django.urls import reverse
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
def __str__(self):
return self.username + ":" + self.email
class Post(models.Model):
"""投稿モデル"""
class Meta:
db_table = 'post'
title = models.CharField(verbose_name='タイトル', max_length=255)
text = models.CharField(verbose_name='内容', max_length=255, default='', blank=True)
author = models.ForeignKey(
'search.CustomUser',
on_delete=models.CASCADE,
related_name='posts', # 追記
)
created_at = models.DateTimeField(verbose_name='登録日時', auto_now_add=True)
updated_at = models.DateTimeField(verbose_name='更新日時', auto_now=True)
def __str__(self):
return self.title + ',' + self.text
@staticmethod
def get_absolute_url(self):
return reverse('search:index')
views.py
以下を追記します。
from search.models import Post
from search.serializers import PostSerializer, UserSerializer
from rest_framework.decorators import api_view
from rest_framework.response import Response
from search.models import CustomUser
from rest_framework import permissions
from search.permissions import IsOwnerOrReadOnly
from rest_framework import renderers
from rest_framework import viewsets
from rest_framework.decorators import action
class PostViewSet(viewsets.ModelViewSet):
"""
This viewset automatically provides `list`, `create`, `retrieve`,
`update` and `destroy` actions.
Additionally we also provide an extra `highlight` action.
"""
queryset = Post.objects.all()
serializer_class = PostSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,
IsOwnerOrReadOnly,)
@action(detail=True, renderer_classes=[renderers.StaticHTMLRenderer])
def highlight(self, request, *args, **kwargs):
post = self.get_object()
return Response(post.highlighted)
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
class UserViewSet(viewsets.ReadOnlyModelViewSet):
"""
This viewset automatically provides `list` and `detail` actions.
"""
queryset = CustomUser.objects.all()
serializer_class = UserSerializer
@api_view(['GET'])
def api_root(request, format=None):
return Response({
'users': reverse('user-list', request=request, format=format),
'posts': reverse('post-list', request=request, format=format),
})
serializers.py
アプリケーションのディレクトリに「serializers.py」を新規作成します。
APIのシリアライズおよびリレーションなどを記述します。
from rest_framework import serializers
from search.models import Post
from search.models import CustomUser
class PostSerializer(serializers.HyperlinkedModelSerializer):
author = serializers.ReadOnlyField(source='author.username')
url = serializers.HyperlinkedRelatedField(
view_name="post-detail",
read_only=True,
lookup_field='id'
)
class Meta:
model = Post
fields = ('url', 'id', 'author',
'title', 'text', 'created_at', 'updated_at',)
class UserSerializer(serializers.HyperlinkedModelSerializer):
# posts = serializers.HyperlinkedIdentityField(many=True, view_name='post-detail', read_only=True)
posts = PostSerializer(many=True, read_only=True)
url = serializers.HyperlinkedRelatedField(
view_name="user-detail",
read_only=True,
lookup_field='id'
)
class Meta:
model = CustomUser
fields = ('url', 'id', 'username', 'email', 'posts')
permissions.py
アプリケーションのディレクトリに「permissions.py」を新規作成します。
API処理の許可について記述します。
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
Custom permission to only allow owners of an object to edit it.
"""
def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request,
# so we'll always allow GET, HEAD or OPTIONS requests.
if request.method in permissions.SAFE_METHODS:
return True
# Write permissions are only allowed to the owner of the post.
return obj.owner == request.user
実行結果
APIルート
http://127.0.0.1:8000/api/
Post一覧
http://127.0.0.1:8000/api/posts/
ユーザ一覧
http://127.0.0.1:8000/api/users/
APIスキーマ
http://127.0.0.1:8000/schema/
通常の画面
APIに加えて、通常の画面も使用できます。
サンプルソース
GitHubに当該記事のサンプルソースを公開しています。
参考
Django REST framework:Nested relationships
https://www.django-rest-framework.org/api-guide/relations/#nested-relationships








