こんにちは。リューさん(@Ryu_programs)です。今回の記事ではjQueryを使ってDjangoでAjaxを行っていきたいと思います。
この記事ではDjangoについては詳細な説明をしていないので、Djangoの実装方法などについては以下の記事を読んでみてください。
はじめに – Ajaxとは?
Ajax(Asynchronous JavaScript and XML)は、それ自体が技術というわけではなく、一種のアプローチです。このAjaxを利用ことで、表示されているページをすべて更新することなく、一部のみを更新することができ、Webアプリケーションの高速化を行うことができます。
よくGoogle MapsがAjaxを利用している例として挙げられます。Google Mapsはドラッグに合わせて、ページをリロードすることなく表示される範囲が滑らかに移動しますが、それはAjaxを利用しているためです。
また、Asynchronous JavaScript and XMLにはXMLの文字が入っていますが、JSONの方が軽く、JavaScriptで扱いやすいなどの理由から最近はXMLよりもJavaScriptの方がよく使われているそうです。今回もJSONを使って実装していきたいと思います。
実装
テンプレートファイルは以下の通りです。今回はjQueryの$.ajaxメソッドを利用しているので、base.htmlでjQueryを読み込んでいます。
getCookieから$.ajaxSetupまでは、csrftokenをいい感じにするために記述しています。送信フォームを使う場合は{% csrf_token %}をつけておけばDjangoが良い感じにしてくれるのですが、ajaxでPOSTする場合はこのようにcookieから拾ってきたcsrftokenの内容をX-CSRFTokenという名前でヘッダに設定する必要があります。
{% extends 'article/base.html' %}
{% block title %}
My test page
{% endblock %}
{% block content %}
<ul>
{% for article in article_list %}
<li>
{{ article.article_text }}
<span class="add_good" id={{ article.id }}>♥</span>
<span id="good-count-{{article.id}}">{{ article.good_count }}</span>
</li>
{% endfor %}
</ul>
<button onclick="location.href='{% url 'article:article_create' %}'">
追加
</button>
{% endblock %}
{% block extrajs %}
<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);
}
}
});
$('.add_good').on('click', function(e) {
article_id = $(this).attr("id");
$.ajax({
'url': '{% url "article:change_count" %}',
'type': 'POST',
'data': {
'id': article_id,
},
'dataType': 'json'
}).done( response => {
const response_id = response.id;
const good_count = response.good_count;
const element = '#good-count-' + response_id;
$(element).text(good_count);
});
});
</script>
{% endblock %}
モデルはこんな感じです。good_countがいいねの数に対応しています。ajaxでArticleのidをもらい、viewで対応するArticleのgood_countを増やしてからjsonで追加後のいいね数を返しています。
from django.db import models
# Create your models here.
class Article(models.Model):
article_text = models.CharField(max_length=100)
good_count = models.IntegerField(default=0)
def __str__(self):
return self.article_text
viewは以下の通りです。add_good_count_for_articleが主にajaxの処理を行う関数です。return JsonResponseでJsonを返却しています。
from django.shortcuts import render
from .models import Article
from django.views.generic import ListView
from django.views.generic.edit import CreateView
from django.urls import reverse
from django.http import JsonResponse
# Create your views here.
class ArticleListView(ListView):
template_name = 'article_list.html'
model = Article
class ArticleCreateView(CreateView):
model = Article
fields = ('article_text', )
def get_success_url(self):
return reverse('article:article_list')
def add_good_count_for_article(request):
article_id = request.POST.get('id')
article = Article.objects.get(id=article_id)
article.good_count += 1
article.save()
data = {
'id': article_id,
'good_count': article.good_count,
}
return JsonResponse(data)
urlは以下のように設定しています。
from django.urls import path
from . import views
app_name = 'article'
urlpatterns = [
path('', views.ArticleListView.as_view(), name='article_list'),
path('create/', views.ArticleCreateView.as_view(), name='article_create'),
path('change/', views.add_good_count_for_article, name='change_count')
]
トリミングと拡大をしているのでだいぶ荒いですが、このようにいいねを押すとリロードを挟まずにいいね数が増えていきます。変更はデータベースにも反映されているので、リロードを行ってもいいね数は変更された値のままです。(ListViewを使っているので、順序は変わるかもしれませんが)
おわりに
今回はDjangoとajaxを利用していいね!を行うことができる簡単なWebアプリを実装しました。このアプリではいいねを何度も押すことができましたが、ユーザやIPアドレスなどで判別して一度しか押せないようにしたり、いいね!したらcssなどで色を変えたりすればより実用的になると思います。