Django REST Frameworkに再挑戦 その2
概要
Django REST Frameworkに再挑戦 その2
参考サイト
www.codingforentrepreneurs.com
Serializing Objects in the python shell
- python manage.py shell でデータの挙動などを試してみる。
>>> from posts.models import Post >>> from posts.api.serializers import PostSerialier >>> obj = Post.objects.first() >>> print(obj) # test2 >>> obj # <Post: test2> >>> obj.id # 2 # modelのインスタンスを、PostSerializerに代入してみる。 # 予想される挙動としては、Serializeされたobjが出力されるはず。 # つまりJson形式に変換されたobjが出力される。 >>> obj_data = PostSerializer(obj) >>> obj_data.data # dataプロパティで、表示される。 {'publish': '2017-01-01', 'content': 'testtest2', 'id': 2, 'slug': 'test2', 'title': 'test2'} >>> obj_data PostSerializer(<Post: test2>): id = IntegerField(label='ID', read_only=True) title = CharField(max_length=120) slug = SlugField(max_length=50, validators=[<UniqueValidator(queryset=Post.objects.all())>]) content = CharField(style={'base_template': 'textarea.html'}) publish = DateField() >>> obj_data.data['content'] # 'testtest2'
- さらにshellでdataを入力してみる。
>>> data = { ... "title": "Yeahh buddy", ... "content": "New content", ... "publish": "2017-1-4", ... } >>> new_item = PostSerializer(data=data) #上記のデータを代入 >>> new_item.data # エラーが出てしまう。 AssertionError: When a serializer is passed a `data` keyword argument you must call `.is_valid()` before attempting to access the serialized `.data` representation. You should either call `.is_valid()` first, or access `.initial_data` instead. # .is_valid()をつけるか、.initial_dataで呼び出すかどちかが必要とのこと。 >>> new_item.initial_data {'publish': '2017-1-4', 'content': 'New content', 'title': 'Yeahh buddy'} # is_validをしてみる。 >>> if new_item.is_valid(): ... new_item.save() ... else: ... print(new_item.errors) ... {'slug': ['This field is required.']} # slugが必須だという表示がされてerrorが出てしまう。そのため、slugをdataに挿入して再度is_validにトライ。 >>> data = { ... "title": "Yeahh buddy", ... "content": "New content", ... "publish": "2017-1-4", ... "slug": "yeah-buddy", ... } >>> new_item = PostSerializer(data=data) >>> if new_item.is_valid(): ... new_item.save() ... else: ... print(new_item.errors) ... <Post: Yeahh buddy> >>> new_item.data {'publish': '2017-01-04', 'content': 'New content', 'id': 3, 'slug': 'yeah-buddy', 'title': 'Yeahh buddy'}
Retrieve API View aka Detail View (検索API, 詳細View)
- posts/api/views.py を編集する。RetrieveAPIViewを追記する。
from rest_framework.generics import ListAPIView, RetrieveAPIView from posts.models import Post from .serializers import PostSerializer class PostListAPIView(ListAPIView): queryset = Post.objects.all() serializer_class = PostSerializer #def get_queryset() class PostDetailAPIView(RetrieveAPIView): queryset = Post.objects.all() serializer_class = PostSerializer
- posts/api/urls.py を編集する。
urlpatterns = [ ... url(r'^(?P<pk>\d+)/$', PostDetailAPIView.as_view(), name='detail'), ...
http://127.0.0.1:8000/api/posts/3/ などにアクセスすると個別のアイテムのviewが出てくる。
http://127.0.0.1:8000/api/posts/4/のように存在しないアイテムのpkを指定すると、
"detail": "Not found."
と表示される。posts/api/views.pyを少し編集して、lookup_fieldという項目を追記してみる。
class PostDetailAPIView(RetrieveAPIView): queryset = Post.objects.all() serializer_class = PostSerializer lookup_field = 'slug' # 以下のように、slugをurl内にセットするか、.lookup_fieldをちゃんと設定しろと言われる。 Expected view PostDetailAPIView to be called with a URL keyword argument named "slug". Fix your URL conf, or set the `.lookup_field` attribute on the view correctly.
- urls.pyをslugで検索できるように、編集する。
urlpatterns = [ url(r'^$', PostListAPIView.as_view(), name='list'), ... url(r'^(?P<slug>[\w-]+)/$', PostDetailAPIView.as_view(), name='detail'), ... ]
- DetailView用に、別のseralizer classを定義してみる。posts/api/serializers.pyを編集する。
# list 用のserializer class PostListSerializer(ModelSerializer): class Meta: model = Post fields = [ 'title', 'slug', 'content', 'publish', ] # Detail用のserializer class PostDetailSerializer(ModelSerializer): class Meta: model = Post fields = [ 'id', 'title', 'slug', 'content', 'publish', ]
- posts/api/views.pyを少し編集する。
... from .serializers import PostDetailSerializer, PostListSerializer class PostDetailAPIView(RetrieveAPIView): queryset = Post.objects.all() serializer_class = PostDetailSerializer lookup_field = 'slug' class PostListAPIView(ListAPIView): queryset = Post.objects.all() serializer_class = PostListSerializer ...
今の所、シンプルでわかりやすい。