Djangoで定期的なAjax処理(POST)を行う方法をご紹介します。
ここでは、フォームの入力値を指定した間隔で自動POSTを行います。
目次
条件
- Django 3.0.7
- Python 3.7.0
models.py
models.pyに以下のようにPostクラスを追加します。
from django.db import models class Post(models.Model): """投稿モデル""" class Meta: db_table = 'post' title = models.CharField(verbose_name='タイトル', max_length=10) comment = models.CharField(verbose_name='コメント', max_length=100) created_at = models.DateTimeField(verbose_name='登録日時', auto_now_add=True) updated_at = models.DateTimeField(verbose_name='更新日時', auto_now=True) def __str__(self): return self.title + ',' + self.comment
urls.py
トップ画面にフォーム画面を表示します。
また、Ajax処理用のURLを設定します。
from django.urls import path from . import views app_name = 'sampleApp' urlpatterns = [ # トップ画面 path('', views.TestView.as_view(), name='index'), # Ajax処理 path("exec/", views.exec_ajax, name='exec'), ]
forms.py
「forms.Form」のTestFormクラスを定義します。
from django.forms import forms, CharField from sampleApp.models import Post class TestForm(forms.Form): title = CharField( initial='', label='タイトル', max_length=10, required=True, # 必須 ) comment = CharField( initial='', label='コメント', max_length=100, required=True, # 必須 ) def save(self): # save data using the self.cleaned_data dictionary data = self.cleaned_data post = Post(title=data['title'], comment=data['comment']) post.save()
views.py
フォームの処理には「FormView」を用います。
また、Ajax用のメソッドを定義して、POSTで送られてきたパラメータを取得し、何らかの処理を記述します。
from django.contrib import messages from django.http import HttpResponse, QueryDict from django.views.generic.edit import FormView from sampleApp.forms import TestForm class TestView(FormView): template_name = 'sampleApp/index.html' form_class = TestForm success_url = '/' # リダイレクト先URL def form_valid(self, form): form.save() # 保存処理など messages.add_message(self.request, messages.SUCCESS, '登録しました!') # メッセージ出力 return super().form_valid(form) def exec_ajax(request): if request.method == 'POST': # POSTの処理 # JSON文字列の取得 dic = QueryDict(request.body, encoding='utf-8') title = dic.get('title') comment = dic.get('comment') # TODO:何らかの処理を実行する if not title and not comment: # 入力値が空の場合 message = '何もしません。' else: # 何か入力されている場合 # TODO:自動保存処理(DBの値と異なっていた場合、保存する。) message = '自動保存しました。' + 'タイトル:' + title + ', コメント:' + comment return HttpResponse(message)
テンプレート
index.htmlに、「メッセージ」と「フォーム」を表示するようにします。
また、jqueryを用いて定期的にAjaxのPOST処理が行われるようにします。
クロスサイトリクエストフォージェリ (CSRF) 対策のため、CSRFトークンの取得を行っています。
{% extends 'base.html' %} {% block content %} <h2>フォームサンプル</h2> {% if messages %} <ul class="messages"> {% for message in messages %} <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li> {% endfor %} </ul> {% endif %} <form method="post" id="form01" >{% csrf_token %} {{ form.as_p }} <input type="submit" value="送信"> </form> <div id="resultPOST"></div> <script> // csrf_tokenの取得 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; } function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $(function() { var POLLING_INTERVAL_TIME_IN_MILLIS = 10000; // 実行インターバル(ミリ秒) (function polling() { AutoSubmit(); window.setTimeout(polling, POLLING_INTERVAL_TIME_IN_MILLIS); }()); function AutoSubmit() { var val_title = $('#form01 [name=title]').val(); var val_comment = $('#form01 [name=comment]').val(); if(val_title && val_comment){ // フォームに入力されている場合 $.ajax({ type : "POST", url : "{% url 'sampleApp:exec' %}", data: { "title": val_title, "comment": val_comment, }, contentType: "application/json", timeout: 5000, // AJAXリクエストにトークンをセット beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", getCookie("csrftoken")); } }, }).done(function(data) { // alert("success"); $('#resultPOST').text('自動POST処理成功:' + data); }).fail(function(jqXHR, textStatus) { // #alert("error"); $('#resultPOST').text('自動POST処理失敗:'); }); } } }); </script> {% endblock %}
実行結果
フォームが未入力の場合
自動POST処理は行われません。
フォームに入力済の場合
自動POST処理が行われます。(送信ボタンを押さなくてもPOSTが行われます。)
index.htmlの「POLLING_INTERVAL_TIME_IN_MILLIS」で設定した間隔で、定期的に実行されます。
参考
Django:クロスサイトリクエストフォージェリ (CSRF) 対策
https://docs.djangoproject.com/ja/3.0/ref/csrf/