みなさんこんにちは!ヒロポンです!
最近個人開発でDjangoRestFrameworkでapiを作ってReactと連携させてます!
今回はそんなDjangoRestFramworkからCreateApiViewの使い方と、効かないときに試してみることを書いていきます!
CreateApiViewの超絶ミニマムな使い方
from rest_framework import generics
from .serializers import TodoSeriarizer
class CreateTodoViewSet(generics.CreateAPIView):
serializer_class = TodoSeriarizer
超絶シンプルに書くと上記の4行で終わります。
シリアライザーを作って、generics.CreateAPIViewを継承したクラスのシリアライザークラスにシリアライザーをセットするだけ。
DjangoRestFrameWorkのCreateApiViewの使い方
TodoModelが下記のような感じであったとします。
from django.db import models
from django.contrib.auth.models import User
# Todoは保持しているユーザー、タイトル、created,updatedを持っている。
class Todo(models.Model):
user = models.ForeignKey(User, related_name='user', on_delete=models.CASCADE, default=1)
title = models.CharField(max_length=100)
done = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
ものすごくシンプルなModelですね!
ユーザーに紐づくTodoでです!
このTodoのシリアライザーが下記です。
from rest_framework import serializers
from core.models import Todo
class TodoSeriarizer(serializers.ModelSerializer):
created = serializers.DateTimeField(format='%Y-%m-%d', read_only=True)
updated = serializers.DateTimeField(format='%Y-%m-%d', read_only=True)
class Meta:
model = Todo
fields = ['id', 'user', 'title', 'created', 'updated']
extra_kwargs = {'user': {'write_only': True}}
createdとupdatedはModel側で自動更新の設定をしています。
またuserは今後ログインしているユーザーをバックエンド側で紐づけるので、write_onlyとしておきます。
っで!!!!
djangoのviewはどんな感じかというと。
下記。
from django.shortcuts import render
from core.models import Todo
from rest_framework import viewsets,generics
from .serializers import TodoSeriarizer
class TodoViewSet(viewsets.ModelViewSet):
queryset = Todo.objects.all()
serializer_class = TodoSeriarizer
class CreateTodoViewSet(generics.CreateAPIView):
serializer_class = TodoSeriarizer
viewsets.ModelViewSetを継承したTodoViewSetは、上記のコードだけでCRUD全てを持つことができます。
ここで本題のgenerics.CreateApiViewのミニマムな使い方ですが。
下記のやり方でできます。
class CreateTodoViewSet(generics.CreateAPIView):
serializer_class = TodoSeriarizer
たった2行。
この2行でうまく動かなければ、原因は他にあります。
DjangoRestFrameworkのgenericsはrouterが使えない
今回CreateApiViewを作りましたが、これを作ったら次にしないといけないのはルーティングです。
ですが、genericsはrouterに直接追加できません。
from django.urls import include, path
from rest_framework.routers import DefaultRouter
from .views import TodoViewSet,CreateTodoViewSet
app_name = 'todo'
router = DefaultRouter()
# api/todo/
router.register('', TodoViewSet)
router.register('create', CreateTodoViewSet)
urlpatterns = [
path('', include(router.urls))
]
上記のようなコードを書くと下記のような実行時エラーが出ます。
Exception in thread django-main-thread:
Traceback (most recent call last):
File "C:\Users\Hiroshi\Desktop\todoapp\todoApp\env\lib\site-packages\django\urls\resolvers.py", line 590, in url_patterns
iter(patterns)
TypeError: 'module' object is not iterable
じゃあどうすればいいのか?
routerを使わずに追加します。
from django.urls import include, path
from rest_framework.routers import DefaultRouter
from .views import TodoViewSet,CreateTodoViewSet
app_name = 'todo'
router = DefaultRouter()
# api/todo/
router.register('', TodoViewSet)
urlpatterns = [
path('', include(router.urls), name='crud'),
path('create/', CreateTodoViewSet.as_view(),name='create')
]
generics系のクラス(createApiViewとかとか)を継承したクラスはas_view()というメソッドを持ってます。
これをpath関数にぶん投げます。
また同じシリアライザーを複数のviewで共有する場合、name属性を指定する必要があります。
DjangoRestFrameworkのCreateApiViewが効かないときに試してみること
上記のコードでローカルサーバーは立ち上がります。
ですが、正しくTodoの追加はできません。
http://localhost:8000/api/todo/create/にアクセスすると下記のような画面になって、postができません。
この原因はシンプルにルーティングのミスです。
viewsets.ModelViewSetを継承したviewを作ってrouterに追加した場合下記のようなルーティングが生成されます。
- get => 指定したパス/
- post => 指定したパス/
- get => 指定したパス/<id>
- put => 指定したパス/<id>
- delete => 指定したパス/<id>
今回作成したルーティングは下記のような感じでした。
from django.urls import include, path
from rest_framework.routers import DefaultRouter
from .views import TodoViewSet,CreateTodoViewSet
app_name = 'todo'
router = DefaultRouter()
# api/todo/
router.register('', TodoViewSet)
router.register('create', CreateTodoViewSet)
urlpatterns = [
path('', include(router.urls))
]
TodoViewSetと同じ階層にcreateがあるのが味噌です。
今回上手くいかなかったパスは下記。
localhost:8000/api/todo/create
はい。ルーティングのミスです。
todo/createのcreate部分がidとみなされてdelete,put,getのみ有効とされているためpostメソッドが呼べないのです!
コメント