Django JSON 직렬화

2022. 3. 22. 16:02강의 정리/Django REST Framework

반응형

 

장고(Django)를 배우기 시작한 입문자이시거나, 또는 배우고 싶은 생각이 있으신 분은 위 출처의 강의를 적극 추천드립니다!!!

 


 

Django JSON 직렬화(Serialization)


 

직렬화(serialization)

_모든 프로그래밍 언어의 통신에서 데이터는 필히 문자열로 표현되어야만 합니다.

  • 송신자(백엔드) : 객체를 문자열로 변환하여, 데이터 전송 -> 직렬화
  • 수신자(프론트엔드) : 수신한 문자열을 다시 객체로 변환하여, 활용 -> 비직렬화

_각 언어에서 모두 지원하는 직렬화 포맷 (JSON, XML 등)이 있고, 특정 언어에서만 지원하는 직렬화 포맷이 있습니다.

ex) 파이썬의 Pickle

 


 

JSON 변환


데이터는 같지만, 응답 형식이 다를 수는 있습니다.

 

_보통의 웹에서는 GET 요청에 대해 HTML 포맷으로 응답하고, POST 요청을 application/x-www-form-urlencoded 인코딩으로 요청하고, HTML 포맷으로 응답합니다.

 

_요즘의 API 서버에서는 대부분 JSON 인코딩으로 요청 / 응답합니다.

 

 


 

JSON 포맷과 PICKLE 포맷


JSON 포맷

  • 다른 언어 / 플랫폼과 통신할 때 주로 사용
  • 표준 라이브러리 json 제공 // 파이썬 기본 타입에 대해서는 지원을 하지만, Django나 커스텀 타입은 지원을 제공하지않음.
  • pickle에 비해서 직렬화를 지원하는 데이터 타입의 수가 적지만, 커스텀 Rule도 지정 가능

https://www.w3schools.com/python/python_json.asp

 

Python JSON

W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.

www.w3schools.com

 

 

Pickle 포맷

  • 파이썬 전용 포맷으로서 파이썬 시스템끼리만 통신할 때 사용 가능
  • 표준 라이브러리 pickle 제공 -> json 라이브러리가 유사한 사용 방법
  • 주의) 파이썬 버전 특성을 타는 경우가 있습니다

https://wayhome25.github.io/cs/2017/04/04/cs-04/

 

강의노트 04. 파이썬 pickle 모듈 · 초보몽키의 개발공부로그

패스트캠퍼스 컴퓨터공학 입문 수업을 듣고 중요한 내용을 정리했습니다. 개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.

wayhome25.github.io

 

 

_ json / pickle 모두 파이썬 기본 라이브러리로 제공이 됩니다. 

그러나 장고 타입 (Model / QuerySet 등)에 대해서는 직렬화 Rule이 없습니다. -> 오류 발생

 

 

_ 그러면 어떻게 해결 할 수 있을까요?  -> 직접 변환하는 방법이 있습니다.

QuerySet을 JSON 형식으로 직접 바꿔준 다음 json.dumps를 통해 json으로 써줍니다.

data = [
    {'id': post.id, 'title':post.title, 'content': post.content}
    for post in Post.objects.all()
]
    
json.dumps(data, ensure_ascii=False).encode('utf8') # ensure_ascii에 False값을 주면, json.dumps()값을 UTF-8로 수동으로 인코딩할 수 있다.

 

 

_DjangoJSONEncoder를 통해 아래 타입들에 대한 Rule을 추가로 구현할 수 있습니다.

  • datetime.datetime, datetime.date, datetime.time, datetime.delta
  • decimal.Decimal, uuid.UUID, Promise
import json
from django.core.serializers.json import DjangoJSONEncoder

 

 

_ 그러나 매번 직접 변환하기는 너무 번거로우니 -> 직접 변환 Rule을 지정하거나 DRF의 JSONRender, DRF의 serializers.py를 이용하는 방법들이 있습니다. -> 그러나 이러한 방법들을 Model에 대한 변환 Rule은 지원하지 않습니다 ㅠㅠ

 


 

ModelSerializer를 통한 JSON 직렬화


_Serializer / ModelSerializer은 Form / ModelForm과 유사합니다.

    -> 역할 면에서 Serializer은 POST 요청만 처리하는 Form

 

  • 둘의 공통점
    • 폼 필드 지정 혹은 모델로부터 읽어오기.
    • 입력된 데이터에 대한 유효성 검사를 통해 저장합니다.
  • 둘의 차이점
    • Form / ModelForm : Form태그가 포함된 HTML을 생성합니다.
    • Serializer / ModelSerializer : Form 데이터가 포함된 JSON 문자열을 생성합니다.

 

_ModelSerializer

from rest_framework.serializers import ModelSerializer

# Post모델에 대한 ModelSerializer 정의
class PostSerializer(ModelSerializer):
    class Meta:
        model = Post
        fields = '__all__'

post = Post.objects.first() # Post 타입

serializer = PostSerializer(post)
serializer.data # -> ReturnDict 타입

https://www.django-rest-framework.org/api-guide/serializers/

 

Serializers - Django REST framework

 

www.django-rest-framework.org

 

 

_ Model 객체나 쿼리셋에 대해 ReturnDict type으로 변환 할 수 있습니다.

from .serializers import PostSerializer
from .models import Post

# 한개의 모델만 넘기기
serializer = PostSerializer(Post.objects.first())
serializer.data # {'id': 1, 'message': '첫번째 포스팅' ... }

# 쿼리셋을 넘기기
serializer = PostSerializer(Post.objects.all(), many=True)
serializer.data # [OrderDict([('id', 1), ...)]), OrderDict([('id': 2), ...)]) ...]

 

_ Model 객체에 대해서는 필히 many=False(디폴트)를 지정해주어야 하고,

  쿼리셋 객체에 대해서는 필히 many=True를 지정해주어야 합니다.

 

-> 지정이 맞지 않으면 변환 에러가 발생하게 됩니다.

 

 


 

View에서의 JSON 응답


모든 View는 HttpResponse 타입의 응답을 해야 하고, 일반적으로 다음 2가지 방법을 사용합니다.

  1. 직접 json.dumps를 통해 직렬화된 문자열을 획득하여, HttpResponse를 통해 응답합니다.
  2. 1번을 정리하여 JsonResponse를 지원합니다.

 


 

DRF를 통한 JSON 응답


DRF Response를 활용합니다.

qs = Post.objects.all()

serializer = PostModelSerializer(qs, many=True)

from rest_framework.response import Response

response = Response(serializer.data) # Content-type : text/html이 디폴트 지정

 


_ Response에서는 "JSON 직렬화" 가 Lazy하게 동작합니다. 실제 응답 생성시에 .rendered_content 속성에 접근하며, 이 때 변환이 이루어집니다.

 

 


 

Response와 APIView


_ DRF의 모든 뷰는 APIView를 상속 받습니다. APIView를 통해서 Response에 다양한 속성이 지정됩니다.

from rest_framework.views import APIView

renderer_cls = APIView.renderer_classes[0]
renderer_obj = renderer_cls()
response.accepted_renderer = renderer_obj # JSON 변환을 위한 JSONRenderer 인스턴스

response.accepted_media_type = renderer_obj.media_type # 'application/json'
response.renderer_context = {'view': None, 'args': (), 'kwargs': {}, 'request': None}

response # <Response status_code=200, "application/json">

 


 

실제 DRF Serializer 사용


#views.py

from rest_framework import generics

class PostListAPIView(generics.ListAPIView): # 만약 list, create, detail, update, delete등을 모두 사용하려면 ViewSet을 이용
    queryset = Post.objects.all()
    serializer_class = PostSerializer

post_list = PostListAPIView.as_view()

 

 

#urls.py

urlpatterns = [
    path('public/', views.PostListAPIView.as_view()),
]

 


포스팅 조회 응답에 username 응답을 하려면?


_ author = FK(User) 필드가 있을 때, Serializer에서는 FK 키값으로 응답

   serializer.ReadOnlyField를 통해서 FK의 필드값을 읽어 올 수 있습니다.

 

 

#models.py

from django.conf import settings
from django.db import models

# Create your models here.

class Post(models.Model):
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    message = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

 

 

#serializers.py

from rest_framework import serializers
from .models import Post
class PostSerializer(serializers.ModelSerializer):
    username = serializers.ReadOnlyField(source='author.username') # 추가

    class Meta:
        model = Post
        fields = ['pk', 'username', 'title', 'cotnent'] # 'username' 추가

 

 

_ 또는 StringRelatedField, SlugRelatedField 등 뿐만 아니라, 중첩된 Serializer를 통해서도 구현 가능합니다.

 

#serializers.py

from django.contrib.auth import get_user_model
from rest_framework import serializers
from .models import Post
class AuthorSerializer(serializers.ModelSerializer):
    class Meta:
        model = get_user_model()
        fields = ['username']

class PostSerializer(serializers.ModelSerializer):
    author = AuthorSerializer()

    class Meta:
        model = Post
        fields = '__all__'

 

 


도움 받은 글들

https://sss20-02.tistory.com/65

 

[Django] JSON 직렬화 - Serializer

(Model)Form vs (Model)Serializer Django Djnago Rest Framework Form/ModelForm Serializer/ModelSerializer Model로부터 Field 읽어옴 유효성 검사 HTML Form 생성 JSON 문자열 생성 django와 django rest fra..

sss20-02.tistory.com

https://velog.io/@joje/JSON-%EC%A7%81%EB%A0%AC%ED%99%94-%EB%B0%8F-API-%EC%9D%91%EB%8B%B5-Django-vs-DRF

 

JSON 직렬화 및 API 응답 (Django vs DRF)

직렬화의 개념 및 방법에 대해서 알아본다. 또한 Django와 DRF에서 직렬화 룰을 추가하고 수행하는 예제를 살펴보고 JSON API 응답을 비교해본다.

velog.io

https://brownbears.tistory.com/82

 

[Django REST framework] ViewSet

ViewSets Django REST framework는 단일 클래스에서 관련있는 view들의 집합을 위해 logic의 결합을 허용합니다. 이를 ViewSet이라 합니다. 또한 다른 framework에서 resource 또는 controller같이 이름이 개념..

brownbears.tistory.com

 

반응형

'강의 정리 > Django REST Framework' 카테고리의 다른 글

DRF ViewSet과 Router  (0) 2022.07.13
DRF mixins 상속을 통한 APIView  (0) 2022.07.12
DRF로 APIView, Json 응답뷰 만들기  (0) 2022.07.11
Django JSON 응답뷰  (0) 2022.03.12
Django API와 REST  (0) 2022.03.10