저는 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)

 

[Django] model object 에서 dict 타입으로 변환하기

django model object to dict! 모델객체에서 dict타입으로의 변환은 여러 방법이 있습니다. 참고로 Django ORM에서 model 객체로 결과가 나오는 것은 get()과 같은 형식이여야 합니다. filter()처럼 QuerySet으로..

brownbears.tistory.com

불곰님 블로그의 두번째 방법을 써봅시다.

-------------------------------------------------------------------------------------------------

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로 성공적으로 회신이 되었습니다.

 

구글링하다가 막혔는데 혹시.. 하고 시도해 본게 통해서 기분이 너무 좋았습니다. ^^

이걸 읽으신 분에게 도움이 되시길 바랍니다.

+ Recent posts