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

 

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

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

이 글은 2019년 11월 20일 저녁에 오뎅국에 맥주 마시고나서 썼습니다.

 

php를 쓸일이 생겨서 서버흉내를 내보기로 했습니다. 윈도우에서만 django를 쓰다가 실제로 서버컴퓨터에 설치하는데 너무 애를 먹었던 경험이 있어서... 처음부터 해보기로... 역시 실전부터 해야 합니다!

 

앞단계 - 가상머신에 네트워크 설정까지 마치고 리눅스를 설치하고 root계정으로 로그인.. 여기까지는 구글링 해주세요..

 

 

1. IP를 확인합니다. 네트워크 연결이 잘 되었나 확인해야 합니다.

[root@localhost ~]# ifconfig

연두색 상자안이 IP입니다. 제대로 네트워크가 연결되었네요.

 

 

2. 포트(port)도 확인해 봅시다.

[root@localhost ~]# netstat -tnlp

오! 포트 22번이 사용중입니다. 22번은 SSH(Secure Shell)이고 그러면 sftp를 쓸수 있다는 말입니다.

파일질라(FileZilla)로 확인해봅시다.

호스트에 ifconfig로 확인한 IP를 입력하면 됩니다.

연결이 아주 잘됩니다. 참고로 내부 네트워크에서만 됩니다. 같은 공유기를 쓰는게 아니라면 저 IP로 접속할수 없습니다. 방법을 알고 싶다면.. 구글링을..

※ 사용자명을 보면 root인데... 제 컴퓨터에서 막쓰는거니까 root를 씁니다만... 보안에 좋지 않습니다.

 

 

3. yum을 업데이트 합니다.

[root@localhost ~]# yum update

yum은 centOS의 설치마법사입니다. 예수님께서 새 술은 새 부대에 담으라고 하셨었죠. 그렇기 때문에 새 부대에는 새 술을 담아야 합니다. 최신으로 업데이트 해 줍시다.

괜찮냐고 물어네요... y를 입력해줍니다. 갑자기 한글이 나와서 당황했습니다... 그것도 누워서... putty는 누워서 나오나...

업데이트중에 2번정도 괜찮냐고 물어볼건데 괜찮다고! 진행하라고! y를 눌러줍시다. 어차피 망하면 재설치하면 됩니다.

 

 

4. httpd(아파치 하이퍼텍스트 전송 프로토콜)를 설치합니다.

httpd가 우리가 흔히 말하는 아파치가 맞습니다. 혹시 설치되어 있을수도 있으니 확인 해봅시다.

해당 프로그램 명을 쓰고 한칸 띄고 '-v'를 쓰면 버전을 확인할 수 있습니다.

[root@localhost ~]# httpd -v

설치 안되어 있네요. 자신있게 설치 들어갑니다.

[root@localhost ~]# yum install httpd

괜찮냐고 물어볼 겁니다. 괜찮다고 합시다. 다 설치했으면 설치가 확실히 된건지 확인합시다.

어떻게 확인하죠? 좀전에 했던대로 프로그램 명을 쓰고 한칸 띄고 '-v'를 쓰면 됩니다.

[root@localhost ~]# httpd -v

제대로 설치가 되어서 버전이 표기됩니다.

 

 

5. httpd가 부팅하면 자동으로 시작되도록 설정합니다.

아파치가 설치되었으면 실행을 시켜봅시다.

[root@localhost ~]# service httpd start

실행이 된겁니다. 아파치는 포트80번을 쓰는데 사용중인지 확인해봅시다.

[root@localhost ~]# netstat -tnlp

사용중인것을 확인했습니다. 그런데 재부팅을 하면 그때마다 아파치를 켤수는 없잖습니까? 귀찮으니까요... 시작프로그램에 등록합니다.

 

[root@localhost ~]# systemctl enable httpd

이렇게 하면 시작프로그램에 등록이 된겁니다. 재부팅하면 알아서 시작됩니다.

 

 

6. 방화벽이 아파치를 허용하도록 설정합니다.

파일질라로 (/var/www/html)디렉토리에 적당히 index.html을 넣어봅시다. 아파치는 기본적으로 (/var/www/html)안에서 index.html을 읽어서 웹에 띄워줍니다. 파일질라로 넣을때 root계정이 아니면 권한 때문에 업로드가 안될겁니다. root 계정으로 하든지 디렉토리 권한을 바꾸든지 하세요. 보안상 더 좋은 방법도 있겠지만... 저는 아직 부족한 사람인지라...

 

아파치는 포트80번을 쓰죠? 포트80번은 기본포트라서 IP만 입력하면 저절로 연결됩니다. 웹브라우저에 (물론 내부네크워크에 연결된 컴퓨터에서...) IP를 쳐봅시다.

안되네요... 왜냐... centOS의 방화벽이 막고 있어서 그렇습니다. 포트80번을 허용하도록 해줍시다.

[root@localhost ~]# firewall-cmd --permanent --zone=public --add-port=80/tcp

이렇게 하고 방화벽을 재시작합니다. 아래처럼 입력하면 됩니다.

[root@localhost ~]# firewall-cmd --reload

그런데 이렇게 해도 안되면... 재부팅을 해보세요. 전 reload해도 접속안되던데 재부팅 하니까 되더라고요...

 

7. php를 설치합니다.

이제 php를 설치해야 합니다. 제대로 설치된 건지 바로 파악할 수 있도록 "index.php" 만들어서 넣어줍니다.

"phpinfo();"는 php의 정보를 보여주는 함수입니다. php함수니까 php가 제대로 깔려야 작동되겠죠? 확장자도 ".php"로 해줍니다.

이렇게 해 놓으면 php가 제대로 설치되지 않으면 절대로 "index.php"를 아파치가 띄워주지 못합니다. 아래처럼 나와요.

자, 이제 php를 깔아봅시다.

[root@localhost ~]# yum install php

괜찮냐고 물어보겠죠? yes입니다. 설치가 완료되면 이제 아파치를 재시작합시다.

재부팅을 해도 되지만 아래처럼 입력해서 아파치만 재시작할수도 있습니다.

[root@localhost ~]# service httpd restart

이제 "index.php"를 잘 읽는지 확인해 보면...

잘되네요. ^^ 중간중간 안되시면... 문의글 주세요.

+ Recent posts