DRF 03 CRUDの適用


Intro

Article CRUDDjangoが作成したArticleモデルのCRUD OpenをHTMLではなくJSONに作成し、応答するRESTful APIサーバ!

🔵 Postmanインストール


A powerful GUI platform to make your API development faster & easier, from building API requests through testing, documentation and sharing.
→Postmanは開発したAPIをテストし、テスト結果を共有し、それによってAPIの開発効率を高めるプラットフォーム

collectionを使用すると、各サーバが検証するapiを格納できます.(保存:ctrl+s/実行:ctrl+enter)

🔵 ModelSerializerとは?


"The serializers in REST framework work very similarly to Django's Form and ModelForm classes."
→DjangoのformclassやModelFormとよく似ています.
# DRF의 serializers.py

from rest_framework import serializers
from .models import Article

class ArticleSerializer(serializers.ModelSerializer):
  
    class Meta:
        model = Article
        fields = ('id', 'title',)
# Django의 forms.py

from django import forms
from .models import Article, Comment

class ArticleForm(forms.ModelForm):
    
    class Meta:
        model = Article
        fields = ('title', 'content',)
ModelSerializerはほとんどSerializerの操作と似ていますが、3つの相違点があります.

  • It will automatically generate a set of fields for you, based on the model.
    モデルベースのフィールドを自動的に生成します.

  • It will automatically generate validators for the serializer, such as unique_together validators.
    シーケンス化器のデフォルト検証器を作成します.

  • It includes simple default implementations of .create() and .update() .
    基本.create()および.update()を含む.(今は心配いらない部分)
  • →ModelSerializerによりQuerySetと単一Model Instanceをシリアル化し、JSONで応答する.

    🔵 CRUDの適用


    Serializerの定義

  • many=True:コメントデータはクエリーセットとして入力されるため、以下のパラメータが必要です!
  • read_only=True:ArticleListSerializerを使用してarticleを作成する場合に要求されます.データで受信されていないデータフィールドは、読み取り専用として定義する必要があります.
  • # ./articles/serializers.py
    from rest_framework import serializers
    from .models import Article,Comment
    
    class ArticleListSerializer(serializers.ModelSerializer):
        '''
        시리얼라이저를 사용하는 이유 2가지
        1. 데이터베이스에서 가져온 쿼리셋을 JSON으로 바꿔서 응답해준다!
        2. 요청으로 받아온 JSON 형태의 데이터를 반대로 파이썬 객체로 만들어줌!
        '''
        comment_set = CommentSerializer(many=True, read_only=True)
        comment_count = serializers.IntegerField(source='comment_set.count',read_only=True)
        class Meta:
            model = Article
            fields = ('id','title','content','created_at','updated_at','comment_set','comment_count',)
    
    class ArticleSerializer(serializers.ModelSerializer):
        class Meta:
            model = Article
            fields = ('id','title','content','created_at','updated_at',)

    URLパスの設定


    RESTfulでパスを設定しましょう!(注:長い関数名は明示的に記述するためですが、推奨される関数名は含蓄のある短い関数名よりも長いですが、明示的な役割を果たす関数名です)
    # ./articles/urls.py
    
    urlpatterns = [
        path('', views.article_list_create),
        path('<int:article_pk>/', views.article_detail_update_delete),
    ]

    GET(LIST)


    article listインポート→Responseクラスを使用してシリアルデータに応答します.
  • views
  • Djangoと異なり、HTTP Methodを処理する@api_viewレコーダを追加しないとエラーが発生します.
    # ./articles/views.py
    from rest_framework.response import Response
    from rest_framework.decorators import api_view
    
    from .models import Article
    from .serializers import ArticleListSerializer
    
    @api_view(['GET'])
    def article_list_create(request):
        '''
        GET /api/v1/articles
        '''
        # 만약 method =='GET' 
        if request.method =='GET':
            # 1. 디비에 있는 모든 게시글을 가져온다.
    				# 2. 전송 가능한 형태(JSON)으로 바꿔준다.
    				# 3. 마지막으로 Response 함수를 이용하여 반환
            articles = Article.objects.all()
            serializer = ArticleListSerializer(articles,many=True) # 보내는 데이터가 여러개일 경우
            
    				return Response(data=serializer.data)
  • output
  • GET(DETAIL)


    単一モデルインスタンスのインポート(LISTはQuerSetオブジェクトをインポート)
  • views
  • # ./articles/views.py
    from rest_framework.response import Response
    from rest_framework.decorators import api_view
    
    from django.shortcuts import render,get_object_or_404
    from .models import Article
    from .serializers import ArticleSerializer
    
      
    @api_view(['GET'])
    def article_detail_update_delete(request,article_pk):
        article = get_object_or_404(Article,pk=article_pk)
    		'''
        GET /api/v1/articles/{article_pk}
        '''
        if request.method=='GET':
            serializer = ArticleSerializer(article) #JSON으로 만들기
            return Response(serializer.data)
  • 結果
  • POST(CREATE)


    要求データをサーバに送信し、ユーザーの要求に従って処理します.
  • view

  • 応答
    Django:request.GETrequest.POSTは、同様にHTMLデータをサーバに送信し、データを処理する.
    DRF:要求データはrequest.dataでインポートできます.

  • 応答メッセージ:200 statusがデフォルトです.DRF公式文書でカスタマイズ可能!

  • 検証:検証に失敗した場合は、raise_exception=Trueで例外処理を行い、どのフィールドが通過しなかったかを示します.

  • 同じURIを使用していますが、httpの方法によって機能が異なります!
  • # ./articles/views.py
    from rest_framework.response import Response
    from rest_framework.decorators import api_view
    
    from .models import Article
    from .serializers import ArticleListSerializer
    
    @api_view(['GET','POST'])
    def article_list_create(request):
        '''
        GET /api/v1/articles
    		POST /api/v1/articles
        '''
        # 만약 method =='GET' 
        if request.method =='GET':
            articles = Article.objects.all()
            serializer = ArticleListSerializer(articles,many=True)
    				return Response(data=serializer.data)
    
    		if request.method =='POST':
            # JSON을 python 데이터타입으로 변환
            serializer = ArticleListSerializer(data=request.data)
            # 유효성 검사
            if serializer.is_valid(raise_exception=True):
                serializer.save()
                return Response(data=serializer.data,status=status.HTTP_201_CREATED)
  • 結果
  • DELETE(DELETE)


    データを削除!
  • view

  • 応答
    DELETEの場合、サーバからリソースが削除されたため、応答はありません.(ただし、次のコードでは、削除された文章のpkを知ることができます)204No Content Statusコード.+その後、同じリクエストに対する404応答コードが返される!
  • # ./articles/views.py
    from rest_framework.response import Response
    from rest_framework.decorators import api_view
    
    from django.shortcuts import render,get_object_or_404
    from .models import Article
    from .serializers import ArticleSerializer
    
      
    @api_view(['GET','DELETE'])
    def article_detail_update_delete(request,article_pk):
        article = get_object_or_404(Article,pk=article_pk)
    		'''
        GET /api/v1/articles/{article_pk}
    		DELETE /api/v1/articles/{article_pk}
        '''
        if request.method=='GET':
            serializer = ArticleSerializer(article) #JSON으로 만들기
            return Response(serializer.data)
    		
    		elif request.method=='DELETE':
    				article.delete()
    				data={
                'article':article_pk
            }
    				return Response(data,status=status.HTTP_204_NO_CONTENT)
  • output
  • PUT(UPDATE) ⭐


    要求データをサーバに受信することによって、サーバを更新します.
    一般的にPUTとPATCHは別々に使用されるため、HTTPステータスコードも別々に応答する.
    PUT:リソース전부置換
    PATCH:リソース일부置換
    →patch英語の意味は厚めの布切れ、狭い地面などがあります.また、パッチを適用することは、ゲームの一部を更新することを意味します.したがって,PATCHは置換の一部である!
    大きく異なる
    # GET /api/v1/articles/1
    { 
    	"title" : "테스트",
    	"content" : "테스트데이터입니다" 
    }
    
    #PUT /api/v1/articles/1
    {
    	"title" : "수정!",
    }
    
    # result GET /api/v1/articles/1
    {
    	"title" : "수정!",
    	"content" : null
    }
    →PUTを使用する場合、すべてのフィールドにデータを入れない場合、フィールドはNULLで埋められます.
    #PATCH /api/v1/articles/1
    {
    	"title" : "수정!",
    }
    
    # GET /api/v1/articles/1
    {
    	"title" : "수정!",
    	"content" : "테스트데이터입니다" 
    }
    →PATCHフィールド値保持!
    ただし、ほとんどのサーバではPATCHはサポートされていません.そこで,本稿ではPUTを学習する.
  • view
  • 更新時、instanceキーワードが必要です.
  • # ./articles/views.py
    from rest_framework.response import Response
    from rest_framework.decorators import api_view
    
    from django.shortcuts import render,get_object_or_404
    from .models import Article
    from .serializers import ArticleSerializer
    
      
    @api_view(['GET','DELETE','PUT'])
    def article_detail_update_delete(request,article_pk):
        article = get_object_or_404(Article,pk=article_pk)
    		'''
        GET /api/v1/articles/{article_pk}
    		DELETE /api/v1/articles/{article_pk}
    		PUT /api/v1/articles/{article_pk}
        '''
        if request.method=='GET':
            serializer = ArticleSerializer(article) #JSON으로 만들기
            return Response(serializer.data)
    		
    		elif request.method=='DELETE':
    				article.delete()
    				data={
                'article':article_pk
            }
    				return Response(data,status=status.HTTP_204_NO_CONTENT)
    		
    		elif request.method == 'PUT':
            serializer = ArticleSerializer(instance=article, data=request.data)
            if serializer.is_valid():
                serializer.save()
            return Response(serializer.data)
  • output