##はじめに
クリック数のカウント、具体的には投稿した記事に対するView数を表示する機能を、DjangoとJavascriptのajax通信を使って実装していきます。
こちらのサイトを参考にしています。
##カウントする部分
{% for post in posts %}
<table>
<div class="post">
<div class="date">
<p>{{ post.published_date }}</p>
</div>
<a class="post_{{ post.pk }}" href="{% url 'post_detail' pk=post.pk %}">{{ post.title }}</a>
{{ new.view_number }}views
</div>
</table>
{% endfor %}
Listviewでcontext_object_name ="posts" と宣言して、templateにPostmodelを渡しています。
そして、aタグに class="post_{{ post.pk }}" として、objectごとにpkを振ったクラス名を付けます。DetailViewを用いた各objectのpost_detailに遷移した回数をカウントしていきます。
ここで登場するPostmodelは
class Post(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=50)
text = MDTextField()
view_number = models.IntegerField(blank=False, default=0)
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
の一般的な形です。
##カウント処理
$(function() {
//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]);
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
function csrfSafeMethod(method) {
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
for(let number =1;number<=1000;number ++){
//post_1~post_1000まで、クリックした時の動作
$('.post_'+number).click(function() {
var csrf_token = getCookie("csrftoken");
$.ajax({
type: 'POST',
url: './post_list',
//渡したいdataを辞書形式で挿入
data: {
view_number: 1,
post_number: number,
},
contentType: "application/json",
//csrftokenを付与
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrf_token);}
},
});
});
};
});
Djangoでformを作るときに使う{% csrf_token %}をつけるための処理をする必要があるため、少しコードが長くなっています。上半分のコードの意味はよくわかりませんが、ここでは大丈夫そうです。
view_numberはrequestされるごとに1を足すだけなので、送るデータはpost_numberだけでも十分です。
from django.http import QueryDict
if request.method == 'POST':
# 送ったdataはrequest.bodyに入っている。
dic = QueryDict(request.body, encoding='utf-8')
number = int(dic.get('view_number'))
post_number = int(dic.get('post_number'))
viewed_post = get_object_or_404(Post, pk=post_number)
viewed_post.view_number += number
viewed_news.save()
request.bodyには view_number=1&post_number=(count.jsで送ったnumber) が入っています。QueryDictに関してはDjango公式を見ると理解できそうです。QueryDict(request.body)で辞書形式に変換してgetでkeyに対応する値を取得できます。
後はget_object_or_404(Post, pk=post_number)で遷移先のPostオブジェクトを取得し、view_numberに1を加算して、保存。
##おわりに
csrf_tokenの問題で混乱した箇所だったので残しておこうと思いました。