naritoブログ

このブログはDjangoとBootstrap4で作成されました
ソースコード

Djangoで、Ajax

プログラミング関連 Django Python 約288日前
2017年2月26日15:05
DjangoでAjaxを使います。

上のフォームはGETで検索、下のフォームはPOSTで作成、そして一覧表示をしています。


検索を行うと、絞り込まれます。Ajaxなのでページ遷移はなしで、レスポンスとして検索結果を受け取っています。


作成を押すと、このように作成されたデータがレスポンスとしてかえってきて、alertで表示しています。


modelは以下のような感じ。シンプルです。
from django.db import models
from django.utils import timezone


class Post(models.Model):

    title = models.CharField('タイトル', max_length=255)
    created_at = models.DateTimeField('作成日', default=timezone.now)

    def __str__(self):
        return self.title


urls.py
from django.conf.urls import url
from django.contrib import admin
from main.views import PostList, api_v1_posts

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^$', PostList.as_view(), name='post_list'),
    url(r'^api/v1/posts$', api_v1_posts, name='api_v1_posts'),
]


views.py
from django.http import JsonResponse
from django.views import generic
from .models import Post


class PostList(generic.ListView):
    model = Post


def api_v1_posts(request):

    # 絞り込み検索
    if request.method == 'GET':
        query = request.GET.get('query')
        title_list = [post.title for post in Post.objects.filter(title__icontains=query)]
        d = {
            'result_list': title_list
        }
        return JsonResponse(d)

    # 新規作成
    elif request.method == 'POST':
        title = request.POST.get('title')
        post = Post(title=title)
        post.save()
        d = {
            'pk': post.pk,
            'created_at': post.created_at,
            'title': post.title,
        }
        return JsonResponse(d)



is_ajaxで、ajaxかどうかが判別できます。機会があれば使いましょう。
if request.is_ajax():
    ...
    ...


jsonでレスポンスを返すならば、手っ取り早いJsonResponseを使うと楽です。
return JsonResponse(d)


jsonとして扱えるように、リストや辞書にしておくと間違いないです。
以下は、タイトルにqueryが含まれている(大文字小文字の区別なし)Postオブジェクトの、タイトルを取得しています。
title_list = [post.title for post in Post.objects.filter(title__icontains=query)]


テンプレートです。まず、POSTでAjaxを行うならば以下のようにします。CSRFの対策ですね。
<script>
      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);
              }
          }
      });
</script>


今回は、以下のようなhtmlでした。
    <form id="getform" action="{% url 'api_v1_posts' %}" method="GET">
      <input type="text" id="query">
      <input type="submit" value="検索">
    </form>
    <hr>
    <form id="postform" action="{% url 'api_v1_posts' %}" method="POST">
      <input type="text" id="title">
      <input type="submit" value="作成">
    </form>
    <hr>
    <div id="result">
      {% for post in post_list%}
        <p>{{ post.title }}</p>
      {% endfor %}
    </div>


そしてajax部分です。
return false;を忘れないようにしましょう。遷移してしまいます。
<script>
    $('#getform').submit(function() {
        $('#result').html('');
        $.ajax({
            'url':'{% url "api_v1_posts" %}',
            'type':'GET',
            'data':{
                'query':$('#query').val(),
            },
            'dataType':'json',
            'success':function(response){
                $.each(response.result_list, function(index, title) {
                    $('#result').append('<p>'+ title +'</p>')
                });              
            },
        });
        return false;
    });
    $('#postform').submit(function() {
        $.ajax({
            'url':'{% url "api_v1_posts" %}',
            'type':'POST',
            'data':{
                'title':$('#title').val(),
            },
            'dataType':'json',
            'success':function(r){
                message = 'pk→' + r.pk +  '\ntitle→' + r.title + '\n日付→'+ r.created_at;
                alert(message);           
            },
        });
        return false;
    });
    </script>