티스토리 뷰

Web/Django

[django] 비동기요청(AJAX)

HAN_PY 2020. 7. 26. 23:23
반응형

AJAX(Asynchronous Javascripy And Xml) [에이젝스] [아약스]

JS로 비동기 요청을 보내기

 

비동기 요청은 새로 고침없이 화면을 바꿔준다.

 

 

 

javascript의 최종관문을 이해하기 위해 잠시 브라우저에 관련된 이야기를 해 볼까 한다.(DOM)

예시를 보자.

개발자도구 열고 Console클릭 후에 아래의 톱니바퀴를 누른 후에 Log XMLHttpRequesys 를 클릭해서 체크하자.

그러면 비동기 요청이 모두 찍힌다. 그러면 이제 검색창에 글을 적어보면 글자 하나하나당 비동기 요청이 실행되는 것을 알 수 있다. 즉, 새로고침 없이 글자가 하나하나 찍힐 때 마다 DB를 확인하여 자동완성을 완성한다.

 

 

데이터 받아보기

https://koreanjson.com/

 

Korean JSON

{ Korean JSON } Super simple JSON API in Korean. Request GET, POST, PUT, DELETE actions and get JSON data in Korean back to get the most out of the look and feel of Korean language when prototyping your project. 한국어 데이터를 제공하는 초간��

koreanjson.com

위의 사이트에서 더미 데이터를 받아보자.

 

 

 

코드

import requests

res = requests.get('https://koreanjson.com/posts/')

data = res.json()

post_content = data[0].get('content')

print(post_content)


코드해석

import requests

pip install requests로 설치 후 작성

 

res = requests.get('https://koreanjson.com/posts/')

위의 주소로 요청을 보내낸 후 응답을 받아서 그 데이터를 res에 넣는다.

 

data = res.json()

json으로 온 문자열을 해석가능하게 object로 변경해서 data에 저장한다.

 

post_content = data[0].get('content')

딕셔너리인 data들 중 첫번째 데이터(인덱스 0)를 뽑아서 key값이 content인 값을 post_content에 저장. 

 

print(post_content)

 


출력을 해보면 더미 데이터 값이 온다.

 

문제점

python은 한줄을 처리하고 다음 줄로 넘어간다.

따라서 requests로 요청을 보냈을 때, 응답이 올 때까지 기다린다.

이러한 것들을 'bloking하다' 라고 한다.

 

도큐먼트나 돔, 브라우저에서 제공하는 몇몇 method들 중에 Non-blocking한 것들이 있다. 실행한 코드가 끝나지도 않았는데 기다리지 않고 막 넘어간다.

 

아래의 코드도 같은 맥락으로 이해하면 된다. 

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <script>
    // 제대로 동작하지 않는다.
    const xhr = new XMLHttpRequest()
    xhr.open('GET', 'https://koreanjson.com/posts/1')
    // non-blocking 하다.(함수가 모두 종료될 때 까지 기다리지 않는다.)
    xhr.send() 
    // 요청을 보낸 이후 응답이 제대로 도착하지 않았지만, 바로 res 에 값을 할당한다. => ""
    const res = xhr.response
    console.log('RES: ', res)
  </script>
</body>
</html>

응답이 안왔는데 res에 ""로 빈문자열로 할당을 해버린다.

XHR은 대표적으로 non-bloking이다.

 

따라서 예전 javascript는 무한으로 기다리지 않기 위해서, 콜백함수를 계속 적어서 뒤로 미뤄서 사용했어야 했다.(ES5) 이게 너무 싫어서 promise 라는 것을 가지고 왔다. 쉽게 말해서 하던가 안하던가 둘중 하나만 하게 만들어 놨다. 즉, 외부요청을 보내는 일과 기다려야하는 일은 지금 당장 하지않고(Non-bloking) 진행되고 있는 코드가 다 한뒤로 미룬다고 이해하면 된다. 우리의 포인트는 promise 함수를 어떻게 쓰는지에 대해 알아보자.

 

promise는 성공 아니면 실패다.

성공할 때, 하는 일은 .then() 에 넣고

실패할 때, 하는 일은 .catch() 에 넣는다.

 

이때, 각각의 ( ) 안에 어떤 일을 하는지를 넣어줘야 한다. 저기에 들어 가는 것은 해야하는 것이기 때문에 반드시 함수를 넣어줘야 한다.

 

 

axios

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  <script>
    // promise => 성공/실패
    // 성공했을 때, 어떤 일을 한다 .then()
    // 실패했을 때, 어떤 일을 한다 .catch()
    console.log(1)
    axios.get('https://koreanjson.com/posts/1')
      .then(function (res) { return res.data })
      .then(function (data) { return data.content } )
      .then(function (content) { console.log(content) })
    console.log(2)
    // callback 함수들 시작

  </script>
</body> 
</html>

출력은 1 -> content -> 2 가 나오는 게 아니라 1 -> 2 -> content가 나온다.

 

기본적으로

  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

로 불러온 밑에 axios를 적어야 한다.

 

코드 해석

    axios.get('https://koreanjson.com/posts/1')

시간순으로 시나리오를 쓴다고 생각하자. 요청을 해서 온 응답은 아래의 res로 들어간다.

 

      .then(function (res) { return res.data })

함수를 실행해서 return된 res.data는 아래의 data로 들어간다.

 

      .then(function (data) { return data.content } )

위의 then이 성공하면, 함수를 실행하고 return된 data.content가 아래의 content로 들어간다.

 

      .then(function (content) { console.log(content) })

위의 then이 성공하면, 함수를 실행하고 content를 출력한다.


+ promise를 쓴다는 것은 axios.get()의 리턴값이라고 할 수 있다.

지금부터 우리는 요청을 보낼 때 위의 방식으로 코드를 짠다.

이제, axios를 통해서 비동기 요청을 보내고 받아서 무엇을 할 수 있는지를 알아보자.

 

 

ping/pong

 

 

 

import art 

from django.shortcuts import render
from django.http import JsonResponse

def ping(request):
    return render(request, 'artii/ping.html')

def pong(request):

    #print(request.GET.get('inpuText'))

    user_input = request.GET.get('inputText')
    art_text = art.text2art(user_input)
    data = {
        'success': True,
        'content': art_text,
    }
    return JsonResponse(data)

 

axios로 요청을 보내면 퐁이 받아서 응답을 보낸다. JsonResponse는 string화 되어 나간다고 생각하면된다.

 

import art

pip install art

user_input을 가공해서 내보내고 싶다.

art_text = art.text2art(user_input)

를 적어준다. 그리고 html에 div가 아니라 pre로 바꿔준다.(폰트셋팅. div에서는 꺠진다.)

 

 

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>아-트</title>
</head>
<body>

  <label for="userInput">input</label>: 
  <input id="userInput" type="text">
  <pre id="resultArea">

  </pre>

  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  <script>
    /* 1. input#userInput 의 'input' 이벤트 때, */
    const userInput = document.querySelector('#userInput')
    userInput.addEventListener('input', function(event) {
      
      // input type="text" 는, 포커스 아웃/엔터가 change다
      const inputText = userInput.value

      // console.log(event.target, inputText)

      /* 2. value 값을 AJAX 요청으로 '/art/pong' 으로 보낸다. */
      axios.get('/artii/pong/', {
        params: {
          inputText: inputText,
        },
      })
        /* 3. pong 이 받아서 다시 JSON 으로 응답을 보낸다. */
        .then(function (res) { 
          /* 4. 응답 JSON 의 내용을 div#resultArea 에 표시한다. */
          const resultArea = document.querySelector('#resultArea')
          resultArea.innerText = res.data.content 
        })
    })


  </script>
</body>
</html>

 

이벤트를 change가 아니라 input으로 바꾸면 키보드를 칠 때마다 적용된다.

input의 value값을 /art/pong/으로 보낸다.

클릭이 일어나거나 엔터를 쳤을때 ajax요청을 보내는거기 때문에 Form이 굳이 필요없다. input은 form안에 있으면 강력하지만 밖에 있으면 그냥 입력창이다.

label을 for는 input의 id와 엮인다. input에 id값이 있으면 label 적어주면된다. 서버에서 input을 알아차리기 위해서는 name값이 필수불가결하다고 했지만, 여기서는 우리가 id값 잡아서 value꺼내면 되므로 안썼다.

엔터를 치거나 포커스가 나가면 작동을한다.

 

get요청에서 데이터를 보내는 방법은 쿼리스트링(url뒤쪽에 ?뒤에 key=value&~~ 있다.)이다.

따라서

axios.get('/art/pong/?inputText=$(inputText)')

로 하드코딩으로 보내기가 가능하다.

이때 view.py의 pong에서 보낸 보낸 값을 받아서, input값의 value값을 print 하려면

print(request.GET.get('inpuText'))

하면된다.  GET요청 꺼내려면 request.GET로 시작한다.

 

    

axios.get('/art/pong/?inputText=$(inputText)')이거 보니 생각보다 너무 길다. 바꾸자.!

그래서 axios는 get의 두번째 인자를 옵셔널하게 넣을 수 있다. 우리는 두번쨰 인자에 object를 넣자. 그 object 안에 params:를 넣고 또 object를 할당한다. 위의 코드 처럼 inputText: inputText, 치면 알아서 위의 하드코딩처럼 만들어준다.

 

 

      console.log(event.targetinputText)

중간 확인상 넣은 코드다.

 

 


js DOM 조작

요소선택

document.querySelector()

document.querySelectorAll()

 

요소생성

document.createElement

 

값추가

newLise.innerText = ' '

 

값올리기

append

 

ex

const newUI = queryselector('ul')

const newList = document.createElement('li')

newList.innerText = 'hanpy'

newUI.append(newLIst)

반응형

'Web > Django' 카테고리의 다른 글

[django] 프로젝트 만드는 순서 정리  (0) 2020.08.02
[Django] render와 redirect 의 차이점  (0) 2020.08.01
[Django] 분기  (31) 2020.07.24
[Django] admin.py  (0) 2020.07.22
[Django] get_object_or_404  (0) 2020.07.22
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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
글 보관함