저는 Django에서 ajax를 자주 사용합니다. 한번 써보니까 헤어나오지를 못해요... ajax 최고! 입니다.
그런데 장고에서 Django에서 ajax로 회신을 보낼때 JsonResponse함수를 써서 보냅니다.
예를 들자면 아래와 같습니다.
-------------------------------------------------------------------------------------------------
from django.http import JsonResponse
data = [{"이름":"킬리만자로","나이":"6억"},{"이름":"사슴","나이":"3살"}]
return JsonResponse(data, safe=False)
-------------------------------------------------------------------------------------------------
JsonResponse함수를 쓸때, 저 data에 int, str, list, dict, tuple를 넣어보면 문제없이 회신이 됩니다.
그런데 우리는 회신을 보낼때 웹서비스니까 주로 DB데이터를 보내겠죠?
Product라는 DB모델의 모든 데이터를 회신하라고 해보겠습니다.
-------------------------------------------------------------------------------------------------
data = Product.object.all()
return JsonResponse(data, safe=False)
-------------------------------------------------------------------------------------------------
에러발생!
TypeError: Object of type 'QuerySet' is not JSON serializable
이런 에러가 뜹니다. DB를 조회해서 집어넣은 변수의 Type은 QuerySet이라고 하는데 JSON으로 변환이 안되나봅니다.
그럼 QuerySet을 list로 바꾸면 되겠죠? 아래처럼 하면 됩니다.
-------------------------------------------------------------------------------------------------
data = Product.object.all()
data = list(data.values())
return JsonResponse(data, safe=False)
-------------------------------------------------------------------------------------------------
이렇게 값을 뽑아서 list화 해주면 됩니다. ※ .values()를 꼭 해주세요.
그런데 저렇게 DB들이 아니라 DB한개만 회신하려면 어떻게 하면 될까요? 예를 들어 중복값이 없는 DB라서 항상 하나만 회신을 하게 된다면? 위 방법을 응용하면 중복없는 값으로 필터링해서 보내면 되겠죠.
-------------------------------------------------------------------------------------------------
data = Product.object.filter(pk=1)
data = list(data.values())
return JsonResponse(data, safe=False)
-------------------------------------------------------------------------------------------------
실제로 저는 위 방법을 썼었는데... 만약 DB하나만 가져와서 이것저것 하고 나서 그 결과값을 회신 하려는데, QuerySet을 사용하려고 다시 저렇게 필터링을 하면 낭비잖아요? 그래서 그 DB한개를 그대로 보낼 방법을 찾아봤습니다.
DB여러개가 QuerySet이니까 DB한개는 Query라고부르면 되겠지요? 제가 용어 같은거 잘모르니까 양해 바랍니다.
아래처럼 해봅니다.
-------------------------------------------------------------------------------------------------
data = Product.object.get(pk=1)
data = list(data.values())
return JsonResponse(data, safe=False)
-------------------------------------------------------------------------------------------------
이렇게 하면 value가 작동을 안합니다. values가 QuerySet에는 있고 Query에는 없나봅니다. 실패죠... 다른 방법을 써봅시다.
-------------------------------------------------------------------------------------------------
data = Product.object.get(pk=1)
data = list(data)
return JsonResponse(data, safe=False)
-------------------------------------------------------------------------------------------------
object is not iterable 라고 나오네요... 안됩니다. 또 실패... 그냥 list로는 안되나 봐요...
구글링을 하다가 불곰님의 블로그에서 답을 찾았습니다. (https://brownbears.tistory.com/276)
불곰님 블로그의 두번째 방법을 써봅시다.
-------------------------------------------------------------------------------------------------
from django.forms.models import model_to_dict
data = Product.object.get(pk=1)
data = model_to_dict(data)
return JsonResponse(data, safe=False)
-------------------------------------------------------------------------------------------------
이렇게 하니까 이미지파일필드가 없는 DB에서는 잘됩니다.
그런데... 이미지파일 필드가 있으면 JSON으로 못바꾼다고 오류가 나네요.
print명령어로 data를 살펴봅시다.
{'id': 1, 'product_name': 'ABC', 'product_partno': '헤이맨', 'product_cost': 200, 'photo': <ImageFieldFile: None>}
분명 dict Type인데 이미지파일 필드는 값이 {'photo': <ImageFieldFile: None>}로 나옵니다. 왜 저럴까요...
이 방법은 안되겠습니다.
불곰님 블로그의 첫번째 방법을 써봅시다.
-------------------------------------------------------------------------------------------------
data = Product.object.get(pk=1)
data = data.__dict__
return JsonResponse(data, safe=False)
-------------------------------------------------------------------------------------------------
이렇게 하니까 Type이 ModelState라면서 JSON으로 못 바꾼다고 오류가 납니다.
print명령어로 data를 또 살펴봅시다.
{'_state': <django.db.models.base.ModelState object at 0x00000251BAF4B518>, 'id': 1, 'product_name': 'ABC', 'product_partno': '헤이맨', 'product_cost': 200, 'photo': ''}
불곰님 말씀대로 '_state':<django.불라불라~~>' 이런것도 붙어있긴 한데...
이미지파일 필드가 {'photo': ''} 이런식으로 나오네요. 경로값이 나오는 거죠. (None이니까 경로값이 비어있습니다.)
제가 원하는게 이겁니다. Django의 모델에서 이미지파일 필드는 파일의 경로가 있으면 됩니다.
근데... 딱보면 분명히 아름다운 dict Type이고 type()로 확인해봐도 dict가 맞는데...
왜 ModelState라고 뜨면서 JSON으로 바꿔지기를 거부하는 걸까요... 여기서부터는 구글링으로도 못 찾았습니다...
혹시나... '_state':<django.불라불라~~>' 때문인것 같아서 dict에서 저걸 지워봤습니다.
-------------------------------------------------------------------------------------------------
data = Product.object.get(pk=1)
data = data.__dict__
data = del data['_state']
return JsonResponse(data, safe=False)
-------------------------------------------------------------------------------------------------
그랬더니... 됩니다! '_state'만 없애버렸더니 나머지 정보가 전부 dict형태로 ajax로 성공적으로 회신이 되었습니다.
구글링하다가 막혔는데 혹시.. 하고 시도해 본게 통해서 기분이 너무 좋았습니다. ^^
이걸 읽으신 분에게 도움이 되시길 바랍니다.