Asynchronous JavaScript and XML
서버와 데이터를 교환하는 기술 중 하나로, 비동기적인 웹 애플리케이션의 제작을 위한 웹 개발 기법입니다. AJAX는 하나의 기술이 아니라 아래와 같이 함께 사용하는 기술의 묶음을 의미한다.
- 표현정보를 위한 HTML과 CSS
- 동적인 화면 출력을 위한 DOM과 JavaScript
- 웹 서버와 비동기적으로 데이터를 교환하기 위한 XML, XSLT, XMLHttpRequest
사용자에게 홈페이지가 갱신되는 것을 안보이게 하는 목적도 있지만,
페이지 단위 컨셉을 제거시키고, 필요한 일부분만 갱신할 수 있도록 XML HttpRequest 객체를 통해 서버에 요청한다.
비동기(async) 방식이란?
비동기 방식은 웹페이지를 리로드하지 않고 데이터를 불러오는 방식이다. 일반적인 페이지 리로드의 경우 전체 리소스를 다시 불러오므로 불필요한 리소스 낭비가 발생한다. 반면 비동기식 방식을 이용할 경우 필요한 부분만 불러올 수 있으므로 리소스를 절약할 수 있다. 비동기 방식이란 thread를 요청하여 다른 작업을 동시에 할 수 있다.
AJAX를 사용하여 개발하는 입장에서는 server, client 모두 개발해야 한다.
새로운 App 생성
- console
python manage.py startapp ajax #manage.py 로 앱을 생성한다.
html file을 static에 넣는 건 연습용(편해서)이었고
오늘은 template folder에 넣겠다.
templates folder 하위에 폴더를 만들고 그 경로를 사용하는 것도 가능하다.
templates/사용자폴더/파일명
으로 불러오면 된다.
calculate form
Form
<form action="calc" method="get">
<input type="text" name="op1" id="op1"> +<input type="text" name="op2" id="op2">
<button id="btnCalc">=</button> <input type="text" name="result" id="result">
</form>
그냥calc는 현재(http://localhost:8000/ajax/calc), /calc는 절대경로=루트(http://localhost:8000/calc)
form 구성하면 안에 있는 button은 요청값을 무조건 브라우저로 보낸다.
form을 없애면 서버로 submit(서버에 request)이 안 된다. (서버에 요청 = 홈페이지가 갱신)
- input의 name과 id
name
이 있는 것들만 서버로 데이터를 보낸다.
id
는 component를 구분하는 이름. 자바스크립트에서 component를 구분짓는 변수는 name이 아니라 id이다. (name이 없을 수도 있으니까)
getElementById
HTML은 계층구조로 이루어져 있다. (tree 구조)
DOM:document object model.
document.getElementById("아이디")
: 모든 브라우저에서 지원하는 표준 함수
value
: default value 정의 가능. 어느 경우엔 text, innerHTML, HTML... 그러나 기본적으로 사용자 유저 입력은 value.
jQuery에서 event 설정
javascipt로 event 시 구문을 실행하게 하는 것은 브라우저마다 다르다.
jQuery는 event 조정이 비교적 간단하다.
$
=$jQuery
: jQuery 함수. 함수명이 $
이다.
- alert pop-up
다음과 같이 하면 html 로드하는 처음에 알람창이 뜬다.
op1 = document.getElementById("op1")
op1.value = 20; //기본값 설정
alert(op1.value)
위의 코드를 jQuery로 표현하면
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="http://code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
<script>
$("#op1").val(40);
alert( $("#op1").val() );
</script>
- event
$("#btnCalc").click( function() {
// 계산
op1 = parseInt( $("#op1").val() );
op2 = parseInt( $("#op2").val() );
$("#result").val(op1+op2);
} );
AJAX: 필요할 때 일부만 직접 호출해보자.
위를 jQuery로. 차이점은 이름에 "" 마크 쓰지 않아. 이름:value, 이름:value,...
var param = {op1:$("#op1").val(), op2:$("#op2").val()};
...
get 함수
jQuery는 익명 함수를 지원한다. (요즘 언어들은 요즘 많이 사용된다.)
따로 함수를 정의하고 사용하면 관련 코드 간에 분산되는데, 익명 함수는 관련 함수끼리 모여있으므로 가독성을 높여준다.
- javascript
$("#btnCalc").click( function() {
var param = {op1:$("#op1").val(), op2:$("#op2").val()};
// "/calc" 경로는 http://127.0.0.1/ajax/calc 를 호출하는 것임
$.get("/ajax/calc", param, function(data) {
$("#result").val(data.result)
console.log(JSON.stringify(data));
console.log("bbb");
});
console.log("aaa");
});
- console
aaa
{"error":0,"result":8}
bbb
get func는 파라미터 3개.
action에 들어간 프로그램 이름, data는 jason 형식으로, 함수
get: 주소를 가지고 HTML 요청
get함수 출력은 /ajax/calc?op1=6&op2=7
thread로 돌아. get 함수는 실제로 저 함수를 호출하는 게 아니고, 함수를 요청만 해놓고 자기는 빠져나온다. 이후 thread로 돌아서 계산 함수는 서버로 가서 따로 돌아간다.
비동기방식이 아니면 계산하는 동안 다른 코드는 멈춰버리겠지만. 비동기방식이니까
그래서 aaa 메시지가 먼저 나오고 bbb가 호출된다.
디버깅 시 alert 보다 console.log 가 편리하다.
login form
비동기 방식 - error code로 넘기기
- views.py
def login():
...
if id == pwd:
return JsonResponse({'error':0})
return JsonResponse({'error':-1})
error code를 만들어두면 어느 페이지로 갈지 여기서는 신경쓸 필요 없다.
많은 부분들을 서버에서 하지 않고 클라이언트로 넘긴다.
흐름제어장치도 클라이언트로.
데이터는 JsonResponse
함수를 이용하면 dictionary를 Json으로 변환하여 반환해준다.
javascript에서는 JSON 형식으로 읽어들인다.
- javascript
$("#btnLogin").click(function() {
var param = {id:$("#id").val(), pwd:$("#pwd").val()};
$.get("/ajax/login", param, function(data) {
console.log(JSON.stringify(data));
$("#result").val(data.result);
if (data.error==0) location.href="/ajax"
else {
$("#id").focus();
$("#id").val("");
$("#pwd").val("");
alert(data.message);
}
});
});
동적 페이지 반영
- test.html
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<div id="status">dddddddddddd</div>
<script>
$("#status").html("<font color=red>안녕하세요</font>")
</script>
#status
태그의 text 내용이 바뀌어 나온다.
upload
- upload.html
<!-- http://localhost:8000/ajax/upload 호출-->
<form action="upload" enctype="multipart/form-data" method="post">
{% csrf_token %}
<input name="title" value="테스트1" />
<input name="contents" value="테스트 자료입니다." />
<input type="file" name="file1" />
<input type="submit" value="upload" />
</form>
<div class="progress">
<div class="bar"></div>
<div class="percent">0%</div>
</div>
<div id="status"></div>
<script>
$(function() {
var bar = $('.bar');
var percent = $('.percent');
var status = $('#status');
$('form').ajaxForm({
beforeSend: function() {
status.empty();
var percentval = '0%';
bar.width(percentVal);
percent.html(percentVal);
},
uploadProgress: function(event, position, total, percentComplete) {
var percentVal = percentComplete + '%';
bar.width(percentVal);
percent.html(percentVal);
},
complete: function(xhr) {
status.html("xhr.responseText") #서버가 리턴해준 텍스트 문장
},
error : function(e) {
status.html("실패")
}
)
})
</script>
- views.py
#@csrf_exempt 내가 책임질테니 예외처리 해 (체크하지 말아줘)
def upload(request):
file = request.FILES['file1']
filename = file._name
fp = open(settings.BASE_DIR + "/static/" + filename, "wb")
for chunk in file.chunks():
fp.write(chunk)
fp.close()
return HttpResponse("UPLOAD")
POST 방식 사용하기
form에서 POST로 데이터를 전송받아 그냥 실행하면 무조건 Forbidden(403) Error가 나온다. 403 error는 보안 관련 에러이며 예외처리를 해주어야만 전송이 가능하다.
여기서 CSRF가 키워드이다.
디버깅 할 때에는 views.py 에서 def 위에 @csrf_exempt
넣으면 토큰을 체크하지 말라고 예외처리할 수 있다. (비정상적 방식)
실제 서비스 할 때에는 html 에서 POST form 안에 {% csrf_token %}
(시스템 코드) 을 반드시 넣어줘야 동작한다. (일반적 방식) 이로써 위조 여부를 판단할 수 있다.
jupyter notebook 구현
- views.py
glo = {}
loc = {}
def runpython(request):
original_stdout = sys.stdout #sys.stdout은 시스템 변수로 정해진 변수명이다.
sys.stdout = StringIO() #강제로 standard output을 메모리로 바꾼다
code = request.GET['code']
exec(code, glo, loc) #내부적으로 전역변수와 지역변수를 glo, loc에 저장함
contents = sys.stdout.getvalue() #표준출력방향에서 value를 가져온다.
contents = contents.replace("\n","<br>")
sys.stdout = original_stdout
return HttpResponse(contents)
exec
함수 : 파이썬 코드 실행. 돌고 있는 인터프리터 안에서 또 돌리는 것이라서 변수 등은 다 저장이 된다.
그러나 출력 결과는 표준 출력 장치로 가기 때문에, 일반적으로는 중간에 가져올 수 없다.
출력 결과를 메모리오프에 저장하도록 바꾸면 거기서 가져올 수 있다.
html에서는 엔터를 엔터로 출력하지 않고 <br>
태그를 써주어야 엔터로 출력해준다.
- html
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<div>
<textarea rows="10" cols="40" id="code"></textarea>
<button id="btnRun">실행</button>
<div id="result"> result </div>
</div>
<script>
$("#btnRun").click(function() {
var param = {code:$("#code").val()};
$.get("/ajax/runpython", param, function(data) {
$("#result").html(data);
});
});
</script>
$("#result").value(data);
value는 plain text밖에 못들어가서
$("#result").html(data);
html을 사용한다.
단 전역변수와 지역변수를 따로 보관하지 않는다.
주피터 노트북에서는 이 변수들을 glo, loc이라는 딕셔너리에 보관한다.
...
로그인 처리는 동기/비동기 방식 차이 없다.
그러나 포털검색에서 유사 단어를 검색해주는 것은 비동기방식으로 구현, 설계하는 것이 낫다.
'Python > Django' 카테고리의 다른 글
Django에 Database 사용하기 (1) | 2020.02.19 |
---|---|
HTML과 python web server 구축 (0) | 2020.02.18 |
Python Socket programming (0) | 2020.02.18 |
OSI 참조 모델 이론 (0) | 2020.02.18 |
Django 기본 (0) | 2020.02.14 |