以前DjangoとReactを連携させたときにページの内容の一部を更新内容として非同期通信で受け取りページの対応部分のみを変更するということをやりました。
その実装はAjaxらしい!というところまでは見たのですがいったいAjaxの実態は何なのでしょう?
ということで今回はAjaxについてなんとなく理解した!まで+DjangoでAjaxを使う方法を見ていきたいと思います。
※Django+AjaxならDjango+Reactで良くないか?という話は知りません。。。
Ajaxについて以下の記事が初心者の私にはよかったです。
Ajaxとは?
Ajaxは「Asynchronous JavaScript + XML」の略です。
つまり、Javascriptを使って非同期にサーバーとXML形式でデータをやり取りするということです。
要素を1つずつ見ていきます。
Asyncronous (非同期の)
非同期通信とは
Googleマップがイメージしやすいと思います。
マウスでのスクロールをトリガーに地図部分の更新情報をサーバーにリクエストします。
サーバーは更新後の地図情報を返し、ページの地図部分のみが更新されます。
※ページ全体の更新は入らない
サーバーからのレスポンスを待っている間もユーザーは待たずに操作をすることができます。
このような通信を非同期通信と言います。
逆にサーバーからページ全体を受け取り、その間ユーザーは操作できずページ全体が更新されるのを同期通信と言います。
JavaScript
AjaxではXMLHttpRequestというAPIでクライアントとサーバーの間の伝送をしているそうです。
このXMLHttpRequestがJavaScriptの組み込みオブジェクトということでJavaScriptが使われているようでした。
XML
XMLはExtensible Markup Languageの略です。
文書、データの構造を記述するためのマークアップ言語のひとつです。
以下サイトにあるものを例として載せておきます。
<?xml version="1.0" encoding="Shift_JIS"?>
<?xml-stylesheet type="text/xsl" href="testxsl.xsl"?>
<おこづかい帳>
<支出>
<内容>
<日付>1月20日</日付>
<交通費>780</交通費>
<食費>980</食費>
<嗜好品>250</嗜好品>
</内容>
<内容>
<日付>1月21日</日付>
<交通費>950</交通費>
<食費>1200</食費>
<嗜好品>300</嗜好品>
</内容>
<内容>
<日付>1月22日</日付>
<交通費>500</交通費>
<食費>1500</食費>
<嗜好品>250</嗜好品>
</内容>
</支出>
</おこづかい帳>
データをタグを使って階層構造で表わしていることがわかります。
JavaScriptではDOM (Document Object Model) というAPIでXMLの定義、アクセス、変更が行えるようになっているようです。
参考:
JSON
先ほどXMLが使われているという話でしたが、現在ではJSON (JavaScript Object Notation) 形式での非同期通信が主流となっているようです。
軽量のデータ交換フォーマットで、人間にとって読み書きが容易で、マシンにとっても簡単にパースや生成を行なえる形式らしいです。
JSON形式の例:
{
"id": 1,
"name": "tanaka",
"attribute": {
"gender": "male",
"phone_number": "xxxxxxxxxxx",
"birth": "1991/01/01"
},
"result": [
87,
83,
71,
59,
91
]
}
参考:
Ajax概要まとめ
- ページ上でイベントが発生
- JavaScript + XMLHttpRequestでサーバーにリクエストを送信する (非同期)
- サーバーが受け取った情報をもとに処理を行う
- サーバーが処理結果をXMLやJSON形式でレスポンスを送信する
- サーバーからのレスポンスを受けてDOMでページを更新する
サーバーへのリクエスト時に欲しいレスポンスの情報を指定してリクエストを行う。
①の発生から⑤の受け取りまでの間、ユーザーはレスポンスを待たずにページを操作し続けることができます。
ページの更新は一部がされるのみでページ全体の更新はされない。(一度白くなったりはしない)
DjangoでAjaxを使う
Projectの作成
プロジェクト名はdjango_ajaxとします。
mkdir django_ajax
cd django_ajax
django-admin startproject config .
アプリの作成
今回はapiというアプリ名にします。
python manage.py startapp api
settigs.pyにapiアプリを追加
config/settings.pyのINSTALLED_APPSにapiアプリを追加します。
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"api", # 追加
]
ルーティング
config/urls.pyのurlpatternsにapiを追加します。
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path("admin/", admin.site.urls),
path("api/", include("api.urls")), # 追加
]
また、api/urls.pyを以下の内容で作成します。
from django.urls import path
from .import views
urlpatterns = [
path('', views.index, name='index'),
path('ajax/', views.ajax_response, name='ajax'),
]
今回はビュー関数として、表示用のindex関数とajax通信用のajax関数を実装します。
ビュー関数
api/views.pyを以下に編集します。
from django.shortcuts import render
from django.http import HttpResponse, JsonResponse
def index(request):
return render(request, 'api/index.html')
def ajax_response(request):
if (request.method == 'POST'):
input_text = request.POST.getlist("name")
return JsonResponse({'name': input_text})
else:
return HttpResponse('NG')
indexではindex.htmlをそのまま返します。
ajax_responseはPOSTリクエストを受け付け、nameというフォームの値を取得しそのままの値でJsonResponseとして返します。
テンプレート (index.html)
Ajaxの実装ですがjQueryを使うものが簡単そうだったので今回はそちらで行います。
XMLHttpRequestどこ行った?という突っ込みはなしで…
api/templetes/apiというフォルダを作成し、その中に以下のindex.htmlを作成します。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Django Ajax</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js" integrity="sha512-v2CJ7UaYy4JwqLDIrZUI/4hqeoQieOmAZNXBeQyjo21dadnwR+8ZaIJVT8EE2iyI61OV8e6M8PP2/4hpQINQ/g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>
<h2>Django Ajax.</h2>
<form name="fm" action="{% url 'ajax' %}" method="POST">
{% csrf_token %}
<label>名前:<input type="text" name="name" size="15"></label>
<input type="submit" class="btn" value="送信">
</form>
<div id="result"></div><!-- このdiv内に整形したデータを非同期で入れる -->
<script>
$('form').submit(function(){
event.preventDefault();
var form = $(this);
$('#result').text('通信中...');
$.ajax({
url: form.prop('action'),
type: form.prop('method'),
dataType: 'json',
data: form.serializeArray(),
timeout: 5000,
})
.done(function(data){
$('#result').text('あなたの名前は ' + data['name'] + ' です。');
})
.fail(function(){
$('#result').text('failed');
});
});
</script>
</body>
</html>
送信用のフォームと結果表示用のdiv、後はajaxを使うjavascript (jQuey使用) を準備しています。
↓送信用フォーム
<form name="fm" action="{% url 'ajax' %}" method="POST">
{% csrf_token %}
<label>名前:<input type="text" name="name" size="15"></label>
<input type="submit" class="btn" value="送信">
</form>
↓結果表示用のdiv
<div id="result"></div><!-- このdiv内に整形したデータを非同期で入れる -->
↓ajax用javascript (jQuey使用)
<script>
$('form').submit(function(){
event.preventDefault();
var form = $(this);
$('#result').text('通信中...');
$.ajax({
url: form.prop('action'),
type: form.prop('method'),
dataType: 'json',
data: form.serializeArray(),
timeout: 5000,
})
.done(function(data){
$('#result').text('あなたの名前は ' + data['name'] + ' です。');
})
.fail(function(){
$('#result').text('failed');
});
});
</script>
jQueryのことはさっぱりわかっていませんが、
- $('form').submitが呼ばれたとき (送信ボタンがクリックされたとき)、
- ajaxの箇所でサーバーに結果をjsonで指定したPOSTリクエストを投げ、
- 成功したら#resultに結果を表示し、
- 失敗したらfailedと結果を表示する
という流れであることが見て取れます。
動作確認
無事に動きました。
まとめ
今回はAjaxとは何者か?、またDjangoでAjaxを (jQueryを使って) 使う方法を見ていきました。
Reactで良い気もしますが、Reactの場合はプロジェクトのビルドが必要で面倒ということはありそうなので小さい範囲でしか非同期通信が必要ないのであれば生のAjaxでも良いのかな?と感じました。
まぁReactもjQueryもさっぱりわからないんですけどね。。。


