DjangoでAxiosを使い非同期通信を行う
約292日前
2021年9月8日0:34
デジタル
Django JavaScript Vue.js
2021/9/8 投稿
非同期通信って何?という方はこちらの記事をご覧下さい。
リンク
非同期通信とは?
Djangoで非同期通信を行いたい場合、Javascript(node.js)系の「Axios」という選択肢があります。
以前紹介した非同期通信方法(上記リンク先)は「Ajax」という、これも同じくJavascript(jQuery)系の方法でした。
何が違うの?どっちを使えばいいの?という疑問があると思います。
結論を言うと「できることは同じ」です。
プログラムの書き方も似ています。
(そもそもやりたいことが同じですので。)
POST処理を行う際のcsrf対策に関する記述はAxiosのほうが短く書けます。
正直「どっちでも良い」」です。
Ajaxで実装しても問題無いですし、AxiosでもOKです。
ただ歴史的に新しいのはAxiosです。
Axiosが出た当初はAjaxとの大きな違いとして「Promiseベース」で書かれていることが挙げられていました。
現在となってはAjaxでもPromiseベースで書けるようなので、ピンと来たほうを選べば良いと思います。
Vue.jsの推奨だったからです。
以前、DjangoでフロントエンドのWEBフレームワークを使うということでVue.jsを導入する記事を書きました。
リンク
Django向けVue.js 「導入」編
Vueでフロントを書く際に
「そういえばVue.jsで非同期通信ってどうやるんだろ?」と思って調べました。
その結果、Vue.js自体が提供する非同期通信手段は無く、代わりに「Axios」を推奨していることが分かりました。
リンク
Vue.js 公式ドキュメント - axios を利用した API の使用
「Axios」は初耳でしたので導入方法を調べてみた次第です。
Axiosの公式ドキュメントによると
AxiosのベースになったのはAngularJSの$httpで、位置づけとしては「Angularを使わなくても使用可能な$http」のようです。
フレームワークの便利な機能をフレームワークの外側で汎用的に使えるようにしました。
ということですね。
Django + Vue.jsの環境で使う前提で解説を進めます。
が、Axios自体はただのJavascriptなので環境が異なる方でも使用可能です。
また、バックエンド(例えばDjango)にリクエストを投げる際の書き方は、別のバックエンド系のフレームワークでも同じですので、流れとしては参考になると思います。
AxiosはCDNでも提供されていますので、下記一文をhtmlファイルに記述するだけで導入可能です。
.html
Vue.js環境でAxiosを使う例を挙げます。
記述方法はVue3ベースです。
.html
それ以外の部分はVue.jsの記述です。
mount()はVue.jsのライフサイクルフックの1つで
「Vue appが特定のエレメントにマウントされたとき」波括弧{}内のスクリプトが実行されます。
今回の場合は実行されるスクリプトが「Axiosの非同期通信」です。
app.mount()によって<div id="test-area">の要素に対し「testVue」appがマウントされ、この要素内では「text」という変数が使えるようになります。
その変数「text」を<body>内で[[text]]として表示します。
補足
「delimiters」について
上記で出てきた [[text]]という表記。
このtextを囲む記号をdelimiter(デリミター)と呼びます。
直訳で「区切り文字」という意味。
変数をhtml上に表示させる際に使われる記法で、Vue.jsではデフォルトでマスタッシュ記法と呼ばれる {{text}} 波括弧2つで囲う方法が採用されています。
しかしDjangoユーザーならお分かりの通り、この記法はDjangoのテンプレート変数の記法 {{ }}と被っています。
対策無しでは互いにバッティングし、変数が上手く表示されません。
そこで下記オプションを付けてVueのデリミターを{{ }}から[[ ]]に変更しています。
Vue.jsの中でAxiosを使う準備ができました!
それでは動作確認を行いながら解説していきましょう。
先程書いたAxiosの部分を抜粋します。
POSTリクエストを行う際は必要です。GETリクエストでは不要です。
method: 'POST'でリクエストメソッドにPOSTを指定します。
「url」にはリクエストを送るURLを記載します。
ここではDjangoの「runserver」コマンドで立ち上がる開発サーバーの「http://127.0.0.1:8000/」を指定しています。
続いてサーバーへデータを送りたいときに使用する2つのオプションです。
「data」はPOSTリクエスト時に使用可能なオプションで、下記のように"KEY", "VALUE"でデータを送ります。
ここに入れられたデータは「Request Payload」としてサーバーへ送られます。
今回は「info」というキーに「request_payload_data」というバリューを入れました。
「params」はGET, POSTどちらでも使用可能なオプションで、クエリストリングを使った方法です。
記述ルールはdataと同じです。
GETリクエストでサーバーへデータを送りたい場合は、このクエリストリングを使用することになります。
ちなみに、上記例のようにPOSTリクエストでは「data」「params」どちらも同時に使うことができます。
今回は「info」というキーに「query_string_data」というバリューを入れました。
「.then」以降はサーバーからレスポンスが来てから実行される部分ですので、今は飛ばします。
さて、AxiosでPOSTリクエストを送ったので、Djangoでリクエストを受け取って処理しましょう。
まずはurls.pyで「http://127.0.0.1:8000/」にリクエストがあった場合にどのビューを実行するか指示します。
urls.py
IndexViewをviews.pyに作ります。
views.py
htmlは下記のように作っておきます。
vue_index.html
では早速「http://127.0.0.1:8000/」にアクセスしてみます。
![]()
リクエストで送ったデータがしっかり画面に表示されていますね!
ビューの中で送られてきたデータを取得します。
基本的には下記の記事で解説した方法で取得可能です。
リンク
リクエストとデータのやりとり
クエリストリングは下記のように取り出しています。
若干ハマりポイントなのがPOSTデータの受け取りです。
上記の記事の方法だと下記のコードで取り出せそうです。
POSTデータが「フォームで入力されてsubmitされた場合」は上記のコードで取得可能です。
しかし、今回のAxiosやAjaxといった「フォームを使わずに送信する方法」の場合はデータが「request.body」に格納されるので、別の方法をとる必要があります。
これはDjangoの公式ドキュメントにも記載されています。
引用文
「request.body」からデータを取り出しますがもう一点注意すべき箇所があります。
「request.body」の中にはデータが「バイト文字列」で入っています。
バイト文字列のままではget()メソッドが使えずデータが取り出せないので、辞書型に変換します。
ここでは「json.loads()」を使用して辞書型に変換してからget()メソッドで"info"の中身を取得しています。
request.bodyの中身がバイト文字列であることはDjangoの公式ドキュメントに記載されています。
(ここに気付かなくて、なぜバイト文字列になってしまうのか長々調べてました。。。涙)
引用文
Django側の作業はあと少しです!
取得したデータをhtmlに返してあげます。
Axiosはデフォルトでjson形式のデータをやり取りするので、Djangoの「JsonResponse」でリターンします。
JsonResponseの引数には先程取得したデータを辞書形式で渡します。
views.py
先程飛ばした下記部分の説明に移ります。
2行目の「.catch()」はリクエスト~レスポンスでエラーが発生した場合の挙動。
今回は成功しているので1行目のみ実行されます。
1行目の説明です。
レスポンスは下記のような構成になっています。
![]()
構成
・config
・data ←今回必要なのはコレ
・headers
・request
・status
・statusText
「data」の中にはJsonResponseの引数に指定したデータが入っています。
![]()
ですので、responseからdataを取り出してhtmlで使えるようにします。
「this.text」というのは、これです。
そして書き換えた「text」をhtmlで表示しています。
これで全体の処理が完了です。
やっていることは
「リクエストをしてレスポンスを受け取る」
ただこれを非同期通信で行っているだけですので、恐れる必要はありません。
Ajaxを使ったことがある方であれば、すんなり理解できたと思います。
お疲れ様でした。
デジタル
Django JavaScript Vue.js
改訂履歴
2021/9/8 投稿
1. Djangoと非同期通信
非同期通信って何?という方はこちらの記事をご覧下さい。
リンク
非同期通信とは?
Djangoで非同期通信を行いたい場合、Javascript(node.js)系の「Axios」という選択肢があります。
以前紹介した非同期通信方法(上記リンク先)は「Ajax」という、これも同じくJavascript(jQuery)系の方法でした。
何が違うの?どっちを使えばいいの?という疑問があると思います。
1.1 - 何が違うの?
結論を言うと「できることは同じ」です。
プログラムの書き方も似ています。
(そもそもやりたいことが同じですので。)
POST処理を行う際のcsrf対策に関する記述はAxiosのほうが短く書けます。
1.2 - どっちを使えばいいの?
正直「どっちでも良い」」です。
Ajaxで実装しても問題無いですし、AxiosでもOKです。
ただ歴史的に新しいのはAxiosです。
Axiosが出た当初はAjaxとの大きな違いとして「Promiseベース」で書かれていることが挙げられていました。
現在となってはAjaxでもPromiseベースで書けるようなので、ピンと来たほうを選べば良いと思います。
1.3 - あえて紹介する理由は?
Vue.jsの推奨だったからです。
以前、DjangoでフロントエンドのWEBフレームワークを使うということでVue.jsを導入する記事を書きました。
リンク
Django向けVue.js 「導入」編
Vueでフロントを書く際に
「そういえばVue.jsで非同期通信ってどうやるんだろ?」と思って調べました。
その結果、Vue.js自体が提供する非同期通信手段は無く、代わりに「Axios」を推奨していることが分かりました。
リンク
Vue.js 公式ドキュメント - axios を利用した API の使用
「Axios」は初耳でしたので導入方法を調べてみた次第です。
Axiosの公式ドキュメントによると
AxiosのベースになったのはAngularJSの$httpで、位置づけとしては「Angularを使わなくても使用可能な$http」のようです。
フレームワークの便利な機能をフレームワークの外側で汎用的に使えるようにしました。
ということですね。
2. Axiosの使い方
Django + Vue.jsの環境で使う前提で解説を進めます。
が、Axios自体はただのJavascriptなので環境が異なる方でも使用可能です。
また、バックエンド(例えばDjango)にリクエストを投げる際の書き方は、別のバックエンド系のフレームワークでも同じですので、流れとしては参考になると思います。
2.1 - CDNでお手軽に導入
AxiosはCDNでも提供されていますので、下記一文をhtmlファイルに記述するだけで導入可能です。
.html
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>これが一番手っ取り早いですね。
2.2 - VueでAxiosを使う
Vue.js環境でAxiosを使う例を挙げます。
記述方法はVue3ベースです。
.html
<body>まずAxiosに関係しているのは
<div id="test-area">
<p>[[text]]</p>
</div>
</body>
<script>
const testVue = {
data() {
return {
text: "App text.",
}
},
delimiters: ['[[', ']]'],
mounted() {
axios.defaults.xsrfCookieName = 'csrftoken'
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN"
axios({
method: 'POST',
url: 'http://127.0.0.1:8000/',
data:{info:'request_payload_data'},
params: {info:"query_string_data"},
responseType: 'json'
}).then(response => this.text = response.data)
.catch(error => console.log(error))
}
}
const app = Vue.createApp(testVue)
app.mount("#test-area")
</script>
mounted(){の部分です。
// Axios関係
}
それ以外の部分はVue.jsの記述です。
mount()はVue.jsのライフサイクルフックの1つで
「Vue appが特定のエレメントにマウントされたとき」波括弧{}内のスクリプトが実行されます。
今回の場合は実行されるスクリプトが「Axiosの非同期通信」です。
app.mount()によって<div id="test-area">の要素に対し「testVue」appがマウントされ、この要素内では「text」という変数が使えるようになります。
その変数「text」を<body>内で[[text]]として表示します。
補足
「delimiters」について
上記で出てきた [[text]]という表記。
このtextを囲む記号をdelimiter(デリミター)と呼びます。
直訳で「区切り文字」という意味。
変数をhtml上に表示させる際に使われる記法で、Vue.jsではデフォルトでマスタッシュ記法と呼ばれる {{text}} 波括弧2つで囲う方法が採用されています。
しかしDjangoユーザーならお分かりの通り、この記法はDjangoのテンプレート変数の記法 {{ }}と被っています。
対策無しでは互いにバッティングし、変数が上手く表示されません。
そこで下記オプションを付けてVueのデリミターを{{ }}から[[ ]]に変更しています。
delimiters: ['[[', ']]']
Vue.jsの中でAxiosを使う準備ができました!
それでは動作確認を行いながら解説していきましょう。
3. Axiosの動作
先程書いたAxiosの部分を抜粋します。
axios.defaults.xsrfCookieName = 'csrftoken'最初の2文はcsrf対策に関する記述です。
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN"
axios({
method: 'POST',
url: 'http://127.0.0.1:8000/',
data:{info:'request_payload_data'},
params: {info:"query_string_data"},
}).then(response => this.text = response.data)
.catch(error => console.log(error))
POSTリクエストを行う際は必要です。GETリクエストでは不要です。
method: 'POST'でリクエストメソッドにPOSTを指定します。
「url」にはリクエストを送るURLを記載します。
ここではDjangoの「runserver」コマンドで立ち上がる開発サーバーの「http://127.0.0.1:8000/」を指定しています。
続いてサーバーへデータを送りたいときに使用する2つのオプションです。
「data」はPOSTリクエスト時に使用可能なオプションで、下記のように"KEY", "VALUE"でデータを送ります。
data:{KEY:'VALUE'}
ここに入れられたデータは「Request Payload」としてサーバーへ送られます。
今回は「info」というキーに「request_payload_data」というバリューを入れました。
「params」はGET, POSTどちらでも使用可能なオプションで、クエリストリングを使った方法です。
記述ルールはdataと同じです。
GETリクエストでサーバーへデータを送りたい場合は、このクエリストリングを使用することになります。
ちなみに、上記例のようにPOSTリクエストでは「data」「params」どちらも同時に使うことができます。
今回は「info」というキーに「query_string_data」というバリューを入れました。
「.then」以降はサーバーからレスポンスが来てから実行される部分ですので、今は飛ばします。
さて、AxiosでPOSTリクエストを送ったので、Djangoでリクエストを受け取って処理しましょう。
まずはurls.pyで「http://127.0.0.1:8000/」にリクエストがあった場合にどのビューを実行するか指示します。
urls.py
urlpatterns = [
path('', views.IndexView, name='index'),
]
IndexViewをviews.pyに作ります。
views.py
def IndexView(request):
template = "vue_test/vue_index.html"
if request.method == "POST":
get_data = request.GET.get("info")
post_data = json.loads(request.body).get("info")
return JsonResponse({'get_data': get_data, 'post_data': post_data})
context = {
'django': "This is Django text.",
}
return render(request, template, context)
htmlは下記のように作っておきます。
vue_index.html
<p>{{django}}</p>
<br>
<div id="test-area">
<p v-for="(data, key) in text">[[key]]:[[data]]</p>
</div>
では早速「http://127.0.0.1:8000/」にアクセスしてみます。
リクエストで送ったデータがしっかり画面に表示されていますね!
3.1 - データの受け取り方
ビューの中で送られてきたデータを取得します。
基本的には下記の記事で解説した方法で取得可能です。
リンク
リクエストとデータのやりとり
クエリストリングは下記のように取り出しています。
get_data = request.GET.get("info")"info"の中身は"query_string_data"ですので、変数「get_data」には「query_string_data」が入ります。
若干ハマりポイントなのがPOSTデータの受け取りです。
上記の記事の方法だと下記のコードで取り出せそうです。
request.POST.get("info")が、この方法では取得できません。
POSTデータが「フォームで入力されてsubmitされた場合」は上記のコードで取得可能です。
しかし、今回のAxiosやAjaxといった「フォームを使わずに送信する方法」の場合はデータが「request.body」に格納されるので、別の方法をとる必要があります。
これはDjangoの公式ドキュメントにも記載されています。
引用文
HttpRequest.POST
A dictionary-like object containing all given HTTP POST parameters, providing that the request contains form data. If you need to access raw or non-form data posted in the request, access this through the HttpRequest.body attribute instead.
「request.body」からデータを取り出しますがもう一点注意すべき箇所があります。
「request.body」の中にはデータが「バイト文字列」で入っています。
バイト文字列のままではget()メソッドが使えずデータが取り出せないので、辞書型に変換します。
ここでは「json.loads()」を使用して辞書型に変換してからget()メソッドで"info"の中身を取得しています。
post_data = json.loads(request.body).get("info")"info"の中身は"request_payload_data"ですので、変数「post_data」には「request_payload_data」が入ります。
request.bodyの中身がバイト文字列であることはDjangoの公式ドキュメントに記載されています。
(ここに気付かなくて、なぜバイト文字列になってしまうのか長々調べてました。。。涙)
引用文
HttpRequest.body
The raw HTTP request body as a bytestring. This is useful for processing data in different ways than conventional HTML forms: binary images, XML payload etc. For processing conventional form data, use HttpRequest.POST.
Django側の作業はあと少しです!
取得したデータをhtmlに返してあげます。
Axiosはデフォルトでjson形式のデータをやり取りするので、Djangoの「JsonResponse」でリターンします。
JsonResponseの引数には先程取得したデータを辞書形式で渡します。
views.py
return JsonResponse({'get_data': get_data, 'post_data': post_data})
3.2 - Axiosでデータを受け取る
先程飛ばした下記部分の説明に移ります。
.then(response => this.text = response.data)1行目の「.then()」はリクエストは成功してレスポンスを受け取ったときの挙動。
.catch(error => console.log(error))
2行目の「.catch()」はリクエスト~レスポンスでエラーが発生した場合の挙動。
今回は成功しているので1行目のみ実行されます。
1行目の説明です。
.then(response => this.text = response.data)「response」にDjangoからのレスポンスが入っています。
レスポンスは下記のような構成になっています。
構成
・config
・data ←今回必要なのはコレ
・headers
・request
・status
・statusText
「data」の中にはJsonResponseの引数に指定したデータが入っています。
ですので、responseからdataを取り出してhtmlで使えるようにします。
this.text = response.data
「this.text」というのは、これです。
data() {Vue appで定義した部分ですね。この値をresponse.dataで上書きしています。
return {
text: "App text.",
}
}
そして書き換えた「text」をhtmlで表示しています。
<p v-for="(data, key) in text">[[key]]:[[data]]</p>
これで全体の処理が完了です。
4. Axiosまとめ
やっていることは
「リクエストをしてレスポンスを受け取る」
ただこれを非同期通信で行っているだけですので、恐れる必要はありません。
Ajaxを使ったことがある方であれば、すんなり理解できたと思います。
お疲れ様でした。