DjangoでAjaxによるデータ更新を行う方法
DjangoでAjaxによるデータ更新を行う方法をご紹介します。
AjaxによるGET/POST処理については、以下の記事もご参照ください。
条件
- Django 2.1.2
- Python 3.7.0
urls.pyの設定
トップ画面に一覧画面を表示し、詳細画面にグラフを表示するという動作とします。
詳細画面で数値の入力を行い、同画面でグラフの再表示を行います。
from django.urls import path
from . import views
app_name = 'monitor'
urlpatterns = [
# トップ画面
path('', views.IndexView.as_view(), name='index'),
# 詳細画面
path('monitor/<int:pk>/', views.DetailView.as_view(), name='detail'),
# グラフ描画
path("monitor/<int:pk>/chart/", views.update_chart, name='chart'),
]
このソースでのポイントは、グラフ描画用のパス「monitor/<int:pk>/chart/」を設定していることです。
詳細画面にてボタンが押された際「monitor/<int:pk>/chart/」にPOSTを行い、views.update_chartで処理を実行します。
views.pyの設定
DetailViewにおいて、get_context_dataを定義し、contextでviewにデータリストを渡すようにします。
詳細画面はここで渡したデータでグラフの初期表示を行います。
from django.shortcuts import render
from django.http import HttpResponse
from django.views import generic
from .models import Location, Greenhouse
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
import datetime
import logging
logger = logging.getLogger('development')
x = ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"]
y = [12, 19, 30, 50, 20, 30]
class IndexView(LoginRequiredMixin, generic.ListView): # generic.ListViewを継承
model = Location
paginate_by = 5
ordering = ['-updated_at']
template_name = 'monitor/index.html'
class DetailView(generic.DetailView):
model = Location
template_name = 'monitor/detail.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# グラフ初期表示用のデータをセットする。
context['x_data'] = x
context['y_data'] = y
return context
def update_chart(request, pk):
input_text_data = request.POST.getlist("input_data") # 入力した値を取得
y[0] = int(input_text_data[0]) # 一つ目のデータを入力値に更新する
y_data = y
x_data = x
return render(request, 'monitor/chart.html', {'y_data': y_data, 'x_data': x_data})
update_chartでは詳細画面でボタンを押した際に実行されたPOSTの値を取得します。
データの一部を入力欄で入力した値で更新し、renderによって以下の処理を行います。
- テンプレート(monitor/chart.html)をロードしてコンテキスト(第三引数)に値(グラフ描画用データ)を入れ、テンプレートをレンダリングした結果を HttpResponse オブジェクトで返す。
detail.htmlの設定
tbodyタグ内で、{% include ‘monitor/chart.html’ %}とすることにより「monitor/chart.html」をロードします。
また、「monitor/chart.html」はボタンを押した後に更新するために<div id=”content”></div>というタグで囲います。
{% extends 'base.html' %}
{% block content %}
<h1>{{ object.name }}</h1>
<section class="post-text">
{{ object.memo|linebreaksbr }}
</section>
<section class="post-date">
<p>Created: {{ object.created_at }}<span>/</span>Updated: {{ object.updated_at }}</p>
</section>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js" integrity="sha384-cs/chFZiN24E4KMATLdqdvsezGxaGsi4hLGOzlXwp5UZB1LY//20VyM2taTB4QvJ" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js" integrity="sha384-uefMccjFJAIv6A+rW+L4AHf99KvxDjWSu1z9VI8SKNVmz4sk7buKt/6v9KI65qnm" crossorigin="anonymous"></script>
<form name="name_form" action="{% url 'monitor:chart' object.pk %}" method="POST">
{% csrf_token %}
<input type="text" id="id_input_data" name="input_data" value="77">
<input class="btn" type="submit">
</form>
<tbody>
<!-- グラフ表示 -->
<div id="content">{% include 'monitor/chart.html' %}</div>
</tbody>
<script>
$("form").submit( function(event) {
event.preventDefault();
var form = $(this);
$.ajax({
url: form.prop("action"),
method: form.prop("method"),
data: form.serialize(),
timeout: 10000,
dataType: "text",
})
.done( function(data) {
$('#content').html(data);
})
});
</script>
<section>
<p><a href="javascript:history.back()">< Back</a></p>
</section>
{% endblock %}
以下、jqueryの解説です。
$.ajax({
url: form.prop("action"),
method: form.prop("method"),
data: form.serialize(),
timeout: 10000,
dataType: "text",
})
以下のオプションは、それぞれformタグから属性を指定して値を取得します。
- url: form.prop(“action”)
- method: form.prop(“method”)
<form name="name_form" action="{% url 'monitor:chart' object.pk %}" method="POST">
すなわち、以下のようにセットしていることになります。
- url: “{% url ‘monitor:chart’ object.pk %}”
- method: “POST”
{% url ‘monitor:chart’ object.pk %}”はDjangoによって「monitor/<int:pk>/chart/」と解釈されます。
.done( function(data) {
$('#content').html(data);
})
POST後にview.update_chartから受け取ったHttpResponseオブジェクトを、id=”content”を指定して置き換えます。
すなわち、<div id=”content”></div>の値が受け取ったHttpResponseオブジェクトに置き換わります。
⇒新たにグラフの描画を行うことになります。
chart.htmlの設定
グラフ描画用のhtmlファイルです。
{{ x_data }}および{{ y_data }}でグラフ描画のデータをセットしています。
当該htmlはdetail.htmlから呼び出されます。
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.bundle.min.js"></script>
<canvas id="myChart" style="width: 100%; height:300px;"></canvas>
<script type="text/javascript">
var chartChart = document.getElementById("myChart");
new Chart(chartChart, {
type: 'bar',
data: {
labels: {% autoescape off %} {{ x_data }} {% endautoescape %} ,
datasets: [{
label: '# of Votes',
data: {{ y_data }},
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});
</script>
動作例
初期表示
詳細画面の初期表示は以下の通りです。
初期データに基づきグラフが描画されます。
更新後
送信ボタンを押した後の表示は以下の通りです。
Redの値が入力値である「77」に更新されています。
また、URLの変更は無いことがわかります。
以下は「1」を入力して送信ボタンを押した結果です。
先ほどと同様に、URL変更なしでRedの値が入力値「1」に更新されていることがわかります。






“DjangoでAjaxによるデータ更新を行う方法” に対して1件のコメントがあります。