Djangoroidの奮闘記

python,django,angularJS1~三十路過ぎたプログラマーの奮闘記

Django REST Frameworkに再挑戦 その2

概要

Django REST Frameworkに再挑戦 その2

参考サイト

www.django-rest-framework.org

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'),
...
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
...

今の所、シンプルでわかりやすい。