일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- Baekjoon
- 알고리즘 연습
- 파이썬
- web
- js
- 파이썬 알고리즘
- javascript
- 알고리즘 풀이
- DRF
- django rest framework
- java
- django widget
- Django
- django ORM
- 알고리즘 문제
- 장고
- es6
- MAC
- CSS
- 백준
- Git
- API
- Algorithm
- c++
- HTML
- form
- react
- 알고리즘
- PYTHON
- AWS
- Today
- Total
수학과의 좌충우돌 프로그래밍
[Django] django rest framework 를 위한 JSON 직렬화 본문
ModelSerializer 를 통한 JSON 직렬화
DRF 에서는 ModelSerializer 를 통해 JSONRenderer 에서 변환가능한 형태로 먼저 데이터를 변환합니다. Serializer 는 장고의 Form 과 유사하며 ModelSerializer는 장고의 ModelForm과 유사합니다.
둘의 결정적인 차이는 Form 은 html 을 생성하고 Serializer는 JSON 문자열을 생성하는 차이가 있습니다.
실습을 위하여 간단히 모델을 정의하였습니다.
# models.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=100)
message = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
update_at = models.DateTimeField(auto_now=True)
Form 을 사용하는 것과 유사하게 Serializer 를 만들어줍니다.
# serializers.py
from rest_framework import serializers
from .models import Post
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = '__all__'
urls 에 대해선 뒤에서 자세히 다뤄보도록 하겠습니다.
# config/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('core/', include('core.urls'), name='core'),
]
# core/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from . import views
router = DefaultRouter()
router.register(r'posts', views.PostViewSet)
urlpatterns = [
path('', include(router.urls)),
]
# views.py
from django.shortcuts import render
from rest_framework import viewsets
from .models import Post
from .serializers import PostSerializer
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
이에 대해서 실습을 진행하였습니다.
serializer = PostSerializer(post)
serializer.data
# {'id': 2, 'title': '제목 내용', 'message': '메세지 내용', 'created_at': '2019-11-18T18:52:57.489893Z', 'update_at': '2019-11-18T19:22:53.717588Z'}
type(serializer.data)
# <class 'rest_framework.utils.serializer_helpers.ReturnDict'>
PostSerializer 를 통해 Post 객체를 dict 타입으로 변환할 수 있습니다. 특이한 점은 직렬화된 데이터의 타입이 ReturnDict 입니다. 이는 순서있는 사전형을 의미하는 OrderedDict 를 상속받았습니다.
serializer = PostSerializer(Post.objects.all())
serializer.data
# 오류
serializer = PostSerializer(Post.objects.all(), many=True)
serializer.data
# [OrderedDict([('id', 2), ('title', '제목 내용'), ('message', '메세지 내용'), ('created_at', '2019-11-18T18:52:57.489893Z'), ('update_at', '2019-11-18T19:22:53.717588Z')]), OrderedDict([('id', 3), ('title', '임시제목'), ('message', 'ㅡㅏㅏ'), ('created_at', '2019-11-18T18:52:57.489893Z'), ('update_at', '2019-11-18T18:52:57.499208Z')])]
type(serializer.data)
<class 'rest_framework.utils.serializer_helpers.ReturnList'>
ModelSerializer 를 상속받은 PostSerializer 는 QuerySet 에 대해서도 변환을 지원해줍니다. 단 이 때는 직렬화 할 시에 many 의 인자를 True 로 넘겨줘야 합니다.
뷰에서의 JSON 응답
Django 스타일
JSON 포맷으로 직렬화된 문자열은 views 에서 클라이언트로 넘겨줘야 합니다. 넘기는 방식은 두 가지가 있습니다.
- json.dumps 를 통해 직렬화한 문자열을 HttpResponse 를 통해 응답
- json.dumps 가 내장되어 있는 JsonResponse 를 통해 응답
이 때 JsonResponse 는 장고의 DjangoJSONEncoder 를 사용하고 있으며, 이는 QuerySet 에 대한 직렬화를 제공하지 않습니다. 따라서 이를 커스튬하여 사용하도록 하겠습니다.
from django.core.serializers.json import DjangoJSONEncoder
from django.db.models.query import QuerySet
class MyJSONEncoder(DjangoJSONEncoder):
def default(self, obj):
if isinstance(obj, QuerySet):
return tuple(obj)
elif isinstance(obj, Post):
return {'id':obj.id, 'title': obj.title, 'message': obj.message }
return super().default(obj)
QuerySet 타입에 대해서는 tuple로 변환하고, Post 타입에 대해서는 dict로 변환해줍니다. 그 외에는 DjangoJSONEncoder 를 따릅니다.
이제 Http 응답을 생성하고 이를 확인해보았습니다.
from django.http import JsonResponse
data = Post.objects.all() # 직렬화할 QuerySet
encoder = MyJSONEncoder # DjangoJSONEncoder를 커스튬한 Encoder
safe = False # default = True 로서 변환할 데이터의 타입이 dict인지 확인합니다. dict 가 아닐 경우에는 False로 설정해주어야 합니다. QuerySet 은 dict 타입이 아니므로 False로 설정합니다.
json_dumps_params = {'ensure_ascii':False} # 한글 등의 유니코드는 16진수로 표현되므로 이를 False 로 바꿔주면 한글문자가 그대로 출력됩니다.
kwargs = {}
response = JsonResponse(data, encoder, safe, json_dumps_params, **kwargs)
response
# <JsonResponse status_code=200, "application/json">
response.content.decode('utf8')
# [{"id": 2, "title": "제목 내용", "message": "메세지 내용"}, {"id": 3, "title": "임시제목", "message": "ㅡㅏㅏ"}]
상태코드 200으로 성공했음을 확인할 수 있고 데이터도 정상적인 것을 확인할 수 있습니다.
DRF 스타일
queryset = Post.objects.all()
serializer = PostModelSerializer(queryset, many=True)
serializer.data
# [OrderedDict([('id', 2), ('title', '제목 내용'), ('message', '메세지 내용'), ('created_at', '2019-11-18T18:52:57.489893Z'), ('update_at', '2019-11-18T19:22:53.717588Z')]), OrderedDict([('id', 3), ('title', '임시제목'), ('message', 'ㅡㅏㅏ'), ('created_at', '2019-11-18T18:52:57.489893Z'), ('update_at', '2019-11-18T18:52:57.499208Z')])]
from rest_framework.response import Response
queryset = Post.objects.all()
serializer = PostSerializer(queryset, many=True)
response = Response(serializer.data)
print(response)
# <Response status_code=200, "text/html; charset=utf-8">
'웹프로그래밍 > DRF' 카테고리의 다른 글
[Django] filtering 과 Search (0) | 2019.12.29 |
---|---|
[Django] format 과 Renderer (0) | 2019.12.29 |
[Django] ViewSet 과 Router (9) | 2019.12.28 |
[Django] APIView, Mixins, generics APIView, ViewSet을 알아보자 (15) | 2019.12.27 |
[Django] django rest framework 를 위한 JSON 기초 (0) | 2019.11.16 |