DjangoでAjaxによるデータ更新を2つ以上のformで行う方法

「DjangoでAjaxによるデータ更新を行う方法」の続きです。

今度は1つの画面で入力フォームとボタンを2つ用意し、それぞれのボタンで別々の処理をAjaxで行う方法をご紹介します。

条件

  • 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'),
    path("monitor/<int:pk>/plot/", views.update_plot, name='plot'),
]

今回はボタンを2つ用意しますので、ボタンアクションによるグラフ描画用のpathを2つ定義します。

  • monitor/<int:pk>/chart/
  • monitor/<int:pk>/plot/

views.pyの設定

2つのボタンアクションそれぞれのグラフ描画処理関数を定義します。

  • update_chart
  • update_plot

処理内容は同一ですが、描画対象グラフが「monitor/chart.html」と「monitor/plot.html」とで異なっています。

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})


def update_plot(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/plot.html', {'y_data': y_data, 'x_data': x_data})

detail.htmlの設定

tbodyタグで2つの異なるグラフを表示するようにしています。

  • {% include ‘monitor/chart.html’ %}
  • {% include ‘monitor/plot.html’ %}

formタグに2つの異なるidを振って、それぞれのPOST処理で別の動作をするようにします。

  • id=”graph1″
  • id=”graph2″

また、action属性において、それぞれ異なるグラフ描画処理が呼ばれるようにします。

  • action=”{% url ‘monitor:chart’ object.pk %}”
  • action=”{% url ‘monitor:plot’ object.pk %}”

scriptタグではformのidを指定して、それぞれ別の処理が行われるようにします。

  • #graph1ではid=”content”のグラフを更新
  • #graph2ではid=”content2″のグラフを更新
{% extends 'base.html' %}

{% block content %}

    <h1>{{ object.name }}</h1>
    <section class="post-text">
        {{ object.memo|linebreaksbr }}
    </section>
    <section class="post-date">
        <p>Created:&nbsp;{{ object.created_at }}<span>/</span>Updated:&nbsp;{{ 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 id="graph1" 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 type="submit" id="button1" name="button1" value="グラフ1更新">
    </form>

    <tbody>
        <!-- グラフ表示 -->
        <div id="content">{% include 'monitor/chart.html' %}</div>
    </tbody>

    <hr>

    <form id="graph2" name="name_form2" action="{% url 'monitor:plot' object.pk %}" method="POST">
        {% csrf_token %}
        <input type="text" id="id_input_data" name="input_data" value="55">
        <input type="submit" id="button2" name="button2" value="グラフ2更新">
    </form>

    <tbody>
        <!-- グラフ表示 -->
        <div id="content2">{% include 'monitor/plot.html' %}</div>
    </tbody>

    <script>
        $('#graph1').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);
            })
        });

        $('#graph2').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) {
                 $('#content2').html(data);
            })
        });
    </script>


    <section>
        <p><a href="javascript:history.back()">&lt; Back</a></p>
    </section>

{% endblock %}

テンプレートの設定

2つの異なるグラフ描画用htmlを用意します。

chart.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>

plot.html

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.bundle.min.js"></script>
<canvas id="myPlot" style="width: 100%; height:300px;"></canvas>
<script type="text/javascript">
    var chartChart = document.getElementById("myPlot");
    new Chart(chartChart, {
        type: 'line',
        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>

動作例

初期表示

詳細画面の初期表示は以下の通りです。
初期データに基づき2つのグラフが描画されます。

グラフ1更新

グラフ1更新ボタンを押した後の表示は以下の通りです。
一つ目のグラフのRed値が入力値である「77」に更新されています。
二つ目のグラフに変更はありません。
また、URLの変更は無いことがわかります。

グラフ2更新

グラフ2更新ボタンを押した後の表示は以下の通りです。
二つ目のグラフのRed値が入力値である「55」に更新されています。
一つ目のグラフに変更はありません。
今回もURLの変更はありません。

以上のように同一画面内で複数のフォームを用いてAjax処理を行うことが出来ます。
Django

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です