장고를 이용하여 get 요청을 보냈을 때 json response 형식에 대해 공부하여 정리하고자 한다.
http client인 httpie
를 이용하여 아래의 그림의 actor
형식을 목표로 코드를 작성하도록 한다. 우선 해당 내용의 데이터 모델은 다:다
혹은 1:다
에서 "다"의 데이터를 가져올 때 사용할 수 있다. 아래의 json response의 "actor":["승우", "강호", "태희"]
와 같이 한 key값
에 리스트형식으로 들어가게 하는 것을 목표로 한다.
해당 코드
# models.py
from django.db import models
from django.db.models.deletion import CASCADE
from django.db.models.fields import DateField, IntegerField
from django.db.models.fields.related import ForeignKey
# Create your models here.
class Movie(models.Model):
title = models.CharField(max_length=45)
release_date = models.DateField()
running_time = models.IntegerField()
class Meta:
db_table = "movies"
class Actor(models.Model):
first_name = models.CharField(max_length=45)
last_name = models.CharField(max_length=45)
date_of_birth = models.DateField()
movies = models.ManyToManyField(Movie, related_name='actors')
class Meta:
db_table = "actors"
# views.py
import json
from django.http import JsonResponse
from django.views import View
from movies.models import Movie, Actor
class MoviesView(View):
def get(self, request):
results = []
movies = Movie.objects.all()
for movie in movies:
actor_arr = []
actors = movie.actors.all()
for i in actors:
actor_arr.append(i.first_name)
results.append({
'title' : movie.title,
'release_date' : movie.release_date,
'running_time' : movie.running_time,
'actor' : actor_arr
})
return JsonResponse({'results':results}, status=200)
여기서 확인해야할 부분은 movie입장에서 actor를 가져올 때이다. 코드를 하나하나 풀어보자.
results = []
movies = Movie.objects.all()
for movie in movies:
actor_arr = []
actors = movie.actors.all()
for i in actors:
actor_arr.append(i.first_name)
results.append({
'title' : movie.title,
'release_date' : movie.release_date,
'running_time' : movie.running_time,
'actor' : actor_arr
})
return JsonResponse({'results':results}, status=200)
위와 같은 방법으로 for문을 이중으로 돌려 그 값만 가져오고 그 값을 빈 리스트에 넣게되면 json으로 reponse될 때 "actor":["승우", "강호", "태희"]
와 같이 한 리스트에 값들이 모두 들어가게 된다.
만약 위에처럼 한 컬럼의 값들이 합쳐서 나오는게 아닌 모두 따로 딕셔너리형태로 나오길 원한다면 다음과 같이 코드를 작성할 수 있다.
그 외의 코드
# views.py
class MoviesView(View):
def get(self, request):
movies = Movie.objects.all()
results = []
for movie in movies:
results.append({
'title' : movie.title,
'release_date' : movie.release_date,
'running_time' : movie.running_time,
'actor' : list(movie.actors.values('first_name'))
})
return JsonResponse({'results':results}, status=200)
value값이 하나하나 딕셔너리에 들어가서 {first_name": "승우"}
로 반환되는 걸 확인할 수 있다.
values_list로 가져오면 안될까?
아까 for문을 중첩해서 하나의 리스트의 값들로 가져올 때 만약 actors를 all()이 아닌 values_list로 가져올 순 없을까? 딕셔너리의 값들을 리스트로 가져오는 것이니 뭔가 그럴듯 해보인다! 변경된 부분만 보자면 아래와 같다. 애초에 가져올 때 values_list의 'first_name'을 찾아 가져오고 append할 때는 그 값만 넣어주는 것으로 변경했다.
views.py
for movie in movies:
actors = movie.actors.values_list('first_name')
actor_arr = []
for i in actors:
actor_arr.append(i)
결과
그렇게 하게되면 값들이 하나의 리스트안에 담기는 것이 아닌 값들이 각각의 리스트에 들어있는 것을 확인 할 수 있다.
그 이유는 values_list는 이렇게 하나의 컬럼에서 여러개의 값을 가져올 때가 아닌 'first_name'과 'last_name'과 같이 2개 이상의 컬럼에서 값을 가져올 때 사용하기 때문이다.
views.py
actors = movie.actors.values_list('first_name', 'date_of_birth')