【Django】Ajaxでファイルをサーバーへ送信・受信(views.pyで処理)する方法

2021.10.01 /

【Django】Ajaxでファイルをサーバーへ送信・受信(views.pyで処理)する方法

本記事ではDjangoAjaxを利用した、ファイル送信(アップロード)・受信(views.pyで処理)する方法について解説していきます。

会社で使用しているWebアプリケーションを改修しているときに、Ajaxでページ遷移を行うことなくユーザーのアップロードしたファイルをサーバーに送信し、サーバー側で処理した結果をサイト上に表示したいことがありました。

本記事ではその際に利用した以下の方法を解説していきます。

  1. Ajaxでファイルをサーバーに送信する方法
  2. Ajaxで送信されたファイルをviews.pyで処理する方法

DjangoにおけるAjax

Ajaxとは

Ajax(Asynchronous JavaScript + XML)とは、Webサーバーと非同期通信を行うための技術のことです。

Ajaxによりページ遷移(ページの読み込み)をすることなく、Webサイト上からサーバーにデータを送信することができます。またページの再読み込みなしで、ページの一部を更新することができます。

やり取りする上で使用するデータ形式はJSONです。
JSONについて知らない方は以下記事をご参照ください。

DjangoでAjaxを実装する方法

PythonのWebフレームワークであるDjangoでも、もちろんAjaxを実装することができます。

DjangoにAjaxを実装する詳しい方法については以下記事をご参照ください。

Ajax:ファイルデータをサーバーに送信する

フォームにアップロードされたファイルをAjaxでサーバーに送信する方法を解説していきます。

フォーム(HTML)

ここでは次のフォームを利用します。

Django:Ajaxのフォーム
<form id="ajax-file-send" action="" method="post" enctype="multipart/form-data">
    {% csrf_token %}
    <p>ファイル:<input type="file" id="uploadfile" name="uploadfile" value=""></p>
    <p><input type="submit" name="submit"></p>
</form>

このファイルを送信するフォームで重要なのは次の点です。

  1. メソッドはPOSTとする
  2. Content-Typeはmultipart/form-dataとする
  3. CSRF対策として、{% csrf_token %}は必ず入れる

urls.py

ここではアプリケーションフォルダ内のurls.pyに次のようルーティングを記述しました。

path('ajax-file-send/', views.ajax_file_send, name='ajax_file_send')

views.py

ここではアプリケーションフォルダ内のviews.pyに次のように処理を記述しています。

def ajax_file_send(request):
    print("OK")
    d = {}
    return JsonResponse(d)

この段階では、まだ送信されたファイルを受け取る記述はしていません。

Ajaxのソースコード

jQeryを利用できるように次のコードでjQeryを読み込みます。

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

次にDjangoでAjaxを利用するためのおまじないを記述します。

function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

var csrftoken = getCookie('csrftoken');

function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

$.ajaxSetup({
    beforeSend: function (xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});

次にファイルを送信するAjaxの本体を次のように記述します。

$('#ajax-file-send').on('submit', function(e) {
    e.preventDefault();
    var fd = new FormData($("#ajax-file-send").get(0));
    $.ajax({
        'url': '{% url "ajax_file_send" %}',
        'type': 'POST',
        'data': fd,
        'processData': false,
        'contentType': false,
        'dataType': 'json'
    })
    .done(function(response){
        //Ajax通信が成功した場合に実行する処理
    });
});

Ajaxの解説

上記のAjaxについて解説していきます。

まずは送信ボタン(formのidがajax-file-send)がクリックされた時に検知し、処理を実行するjQueryを記述します。

$('#ajax-file-send').on('submit', function(e) {処理を記述}

次にフォーム送信の通信を止めるためにpreventDefault()を使用します。

e.preventDefault();

Ajaxでファイルを送信するためにFormDataオブジェクトを作成します。

IT用語の確認

FormDataを使うことでフォームに入力されたデータを一括でサーバーに送信できます。値はキーと値のペアです。

new FormData()の引数にはform要素のDOMを指定し、生成されたFormDataオブジェクトをfdに格納します。

var fd = new FormData($("#ajax-file-send").get(0));

生成したFormDataオブジェクトをAjaxを通して次のようにサーバーに送信します。

$.ajax({
    'url': '{% url "ajax_file_send" %}',
    'type': 'POST',
    'data': fd,
    'processData': false,
    'contentType': false,
    'dataType': 'json'
})

dataにはFormDataオブジェクトを指定します。

重要な点として、processDataとcontentTypeをfalseにしている点です。

processDataはdataを文字列への変換の有無(クエリ文字への変換有無)を指定します。初期値はtrueです。
この値をfalseにすることで変換されずにファイルとして送信されます。

Ajax:送信されたファイルデータをviews.pyで処理する

Ajaxで送られたJSONデータをviews.pyで受け取る方法を解説していきます。

Ajaxを通して送られてきたリクエストデータ(送信データ)はHttpRequestオブジェクト(request)に格納されています。

このrequestからファイルデータを抽出するには次のように属性FILESを使用します。
FILESは辞書型オブジェクトのようなもので、キーはinputタグのnameに対応しています。

def ajax_file_send(request):
    print("OK")
    file = request.FILES['uploadfile']
    # ここにファイルの処理を記述
    d = {
        # レスポンスに渡したいデータを記述
    }
    return JsonResponse(d)

ブラウザからのリクエストを受けたときに生成されるHttpRequestオブジェクトの利用方法については以下記事をご参照ください。

まとめ

本記事「【Django】Ajaxでファイルをサーバーへ送信・受信(views.pyで処理)する方法」はいかがでしたか。

Webアプリケーションにおいてフォームを利用することは多々あります。

そのときにファイルデータをAjaxを通してサーバーに送信し、views.pyでファイルを処理できることは非常に有用です。

ぜひ本記事を通して、ファイルのAjaxによる送信方法をマスターしてください。