[Django] REST API 2

Jingi·2024년 4월 15일
0

Web

목록 보기
24/40
post-thumbnail

Comment

Comment 모델 정의

  • Commnet 클래스 정의 및 데이터베이스 초기화
    class Comment(models.Model):
        article = models.ForeignKey(Article, on_delete=models.CASCADE)
        content = models.TextField()
        created_at = models.DateTimeField(auto_now_add = True)
        updated_at = models.DateTimeField(auto_now = True)

GET - List

  • 댓글 목록 조회를 위한 CommentSerializer

    from .models import Article, Comment
    
    class CommentSerializer(serializers.ModelSerializer):
        class Meta:
            model = Comment
            fields = '__all__'
  • url 작성

    urlpatterns = [
        path('comments/', views.comment_list),
    ]
  • view 함수 작성

    from .models import Article, Comment
    from .serializers import ArticleListSerializer, ArticleSerializer, CommentSerializer
    
    @api_view(['GET'])
    def comment_list(request):
        comments = Comment.objects.all()
        serializer = CommentSerializer(comments, many=True)
        return Response(serializer.data)

GET - Detail

  • 단일 댓글 조회를 위한 url 및 view 함수 작성

    # articles/urls.py
    urlpatterns = [
        ...,
        path('comments/<int:comment_pk>/', views.comment_detail),
    ]
    # articles/views.py
    
    @api_view(['GET'])
    def comment_detail(request, comment_pk):
        comment = Comment.objects.get(pk=comment_pk)
        serializer = CommentSerializer(comment)
        return Response(serializer.data)

POST

  • 단일 댓글 생성을 위한 url 및 view 함수 작성

    # articles/urls.py
    urlpatterns = [
        ...,
        path('comments/<int:article_pk>/comments/', views.comment_create),
    ]
    # articles/views.py
    
    @api_view(['GET'])
    def comment_create(request, article_pk):
        article = Article.objects.get(pk=article_pk)
        serializer = CommentSerializer(data=request.data)
        if serializer.is_valid(raise_exception=True):
            serializer.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)
  • serializer 인스턴스의 save() 메서드는 특정 serializer 인스턴스를 저장하는 과정에서 추가 데이터를 받을 수 있음

    # articles/views.py
    
    @api_view(['GET'])
    def comment_create(request, article_pk):
        article = Article.objects.get(pk=article_pk)
        serializer = CommentSerializer(data=request.data)
        if serializer.is_valid(raise_exception=True):
            serializer.save(article = article)
        return Response(serializer.data, status=status.HTTP_201_CREATED)
  • 데이터를 전송 받은 시점에 유효성 검사에서 제외시키고, 데이터 조회시에는 출력 하는 필드

    # articles/serializers.py
    
    class CommentSerializer(serializers.ModelSerializer):
        class Meta:
            model = Comment
            fields = '__all__'
            read_only_fields = ('articles',
            )

DELETE & PUT

  • 단일 댓글 삭제 및 수정을 위한 view 함수 작성

    # articles/views.py
    @api_view(['GET', 'DELETE', 'PUT'])
    def comment_detail(request, comment_pk):
        comment = Comment.objects.get(pk=comment_pk)
        if request.method == 'GET':
            serializer = CommentSerializer(comment)
            return Response(serializer.data)
        elif request.method == 'DELETE':
            comment.delete()
            return Response(status=status.HTTP_204_NO_CONTENT)
    
        elif request.method == 'PUT':
            serializer = Commentserializer(comment, data = request.data)
            if serializer.is_valid(raise_exception = True):
                serializer.save()
                return Response(serializer.data)

응답 데이터 재구성

댓글 조회 시 게시글 출력 내역 변경

  • 댓글 조회 시 게시글 번호만 제공해주는 것이 아닌 '게시글의 제목'까지 제공하기

  • 필요한 데이터를 만들기 위한 serializer는 내부에서 추가 선언이 가능

    # articles/serializers.py
    
    class CommentSerializer(serializers.ModelSerializer):
        class ArticleTitleserializer(serializers.Modelserializer):
            class Meta:
                model = Article
                fields = ('title',)
        
        article = ArticleTitleserializer(read_only=True)
    
        class Meta:
            model = Comment
            fields = '__all__'

역참조 데이터 구성

Article -> Comment 간 역참조 관계를 활용한 JSON 데이터 재구성

  • 단일 게시글 조회시 해당 게시글에 작성된 댓글 목록도 함께 붙여서 응답
  • 단일 게시글 조회시 해당 게시글에 작성된 댓글 개수도 함께 붙여서 응답

단일 게시글 + 댓글 목록

  • Nested realtionships (역참조 매니저 활용)

    • 모델 관계 상으로는 참조하는 대상은 참조되는 대상의 표현에 포함되거나 중첩될 수 있음

    • 이러한 중첩된 관계는 serializers를 필드로 사용하여 표현 가능

      # articles/serializers.py
      class CommentSerializer(serializers.ModelSerializer):
          class Meta:
              model = Comment
              fields = '__all__'
              read_only_fields = ('article',)
      
      class ArticleSerializer(serializers.Modelserializer):
          comment_set = CommentSerializer(many = True, read_only = True)
          class Meta:
              model = Article
              fields = ('title',)

단일 게시글 + 댓글 개수

  • 'source' argument

    • 필드를 채우는 데 사용할 속성의 이름

    • 점 표기법을 사용하여 속성을 탐색 할 수 있음

      # articles/serializers.py
      class ArticleSerializer(serializers.Modelserializer):
          comment_set = CommentSerializer(many = True, read_only = True)
          comment_count = serializers.IntegerField(source = 'comment_set.count', read_only = True)
      
          class Meta:
              model = Article
              fields = ('title',)

읽기 전용 필드 지정 이슈

  • 특정 필드를 override 혹은 추가한 경우 read_only_fields는 동작하지 않음

  • 이런 경우 새로운 필드에 read_only 키워드 인자로 작성해야함

    # articles/serializers.py
    class ArticleSerializer(serializers.Modelserializer):
        comment_set = CommentSerializer(many = True)
        comment_count = serializers.IntegerField(source = 'comment_set.count')
    
        class Meta:
            model = Article
            fields = '__all__'
            read_only_fields = ('comment_set', 'comment_count')

API 문서화

OpenAPI Specification

  • RESTful API를 설명하고 시각화하는 표준화된 방법
    • API에 대한 세부사항을 기술할 수 있는 공식 표준
  • Swagger, Redoc
    • OAS 기반 API에 대한 문서를 생성하는데 도움을 주는 오픈소스 프레임워크

drf-spectacular 라이브러리

  • DRF 위한 OpenAPI 3.0 구조 생성을 도와주는 라이브러리

  • 설치 및 등록

    • pip install drf-spectacular

      # settings.py
      
      INSTALLED_APPS = [
          
          ...,
          'drf_spectacular',
      
      ]
  • 관련 설정 코드 입력(OpenAPI 구조 자동 생성 코드)

    # settings.py
    REST_FRAMEWORK = {
        'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
    }
    # drf/urls.py
    from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView
urlpatterns = [
    path("admin/", admin.site.urls),
    path('api/v1/', include('articles.urls')),
    path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
    path('api/schema/swagger-ui/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
    path('api/schema/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'),
]

```

설계 우선 접근법

  • OAS의 핵심 이점
  • API를 먼저 설꼐하고 명세를 작성한 후, 이를 기반으로 코드를 구현하는 방식
  • API의 일관성을 유지하고, API 사용자는 더 쉽게 API를 이해하고 사용할 수 있음
  • 또한, OAS를 사용하면 API가 어떻게 작동하는 지를 시각적으로 보여주는 문서를 생성할 수 있으며, 이는 API를 이해하고 테스트하는데 매우 유용
  • 이런 목적으로 사용되는 도구가 Swagger-UI 또는 ReDoc

get_object_or_404()

  • 모델 manager objects에서 get()을 호출하지만, 해당 객체가 없을 땐 기존 DoesNotExist 예외 대신 Http404를 raise 함

get_list_or_404()

  • 모델 manager objects에서 filter()의 결과를 반환하고, 해당 객체 목록이 없을 땐 Http404를 raise 함
profile
데이터 분석에서 백엔드까지...

0개의 댓글