naritoブログ

【お知らせ】
新ブログができました。今後そちらで更新し、このサイトは更新されません(ウェブサイト自体は残しておきます)
このブログの内容に関してコメントしたい場合は、新ブログのフリースペースに書き込んでください

このブログの内容を新ブログに移行中です。このブログで見つからない記事は、新ブログにありま

Djangoで、Ajax

約625日前 2017年2月26日15:05
プログラミング関連
Django Python
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, safe=False) # 辞書じゃない場合はsafe=Falseが必要。

# 新規作成
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を使うと楽です。
辞書以外のものを渡す場合は、safe=Falseとつけましょう。

return JsonResponse(d)



以下は、タイトルに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">
<button type="submit" >検索</button>
</form>
<hr>
<form id="postform" action="{% url 'api_v1_posts' %}" method="POST">
<input type="text" id="title">
<button type="submit" >検索</button>
</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>
生徒 約223日前 2018年4月5日12:04 返信する
いつも楽しく拝見しています。
今回のコードについて質問いたします。
今回、先生はフォーム部分でinputタグを使用していますが、Umedyの講義において同じようなフォームが出てきたときに、「今はinputタグよりもbuttonタグを使用することが一般的」とおっしゃられていました。
ajaxを使用する際はinputタグを使うべきなのでしょうか。
なりと 約223日前 2018年4月5日12:40
buttonタグで大丈夫です。記事内のコードを修正しました、ありがとうございます。
生徒 約221日前 2018年4月6日20:49 返信する
すいません、わざわざありがとうございます!
勉強させて頂きます。
名無し 約78日前 2018年8月27日19:04 返信する
こんにちは、今日もこのサイトで勉強させていただいています。
ユーザーがチェックボックスや複数選択できるタブなどで選択した要素を全て反映させて絞り込み検索したいのですが、「ユーザーが選択した要素の数によって絞り込み要素が変化する」「とある項目は複数要素を持つ場合がある」という二つの理由からかなり実装が難しく、方法が思いつきません。
二つ目の例を出すと、「ジャンル」という項目は「スポーツ」だけが選択されているが、その次の「国名」は「イギリス」「アメリカ」の二つが選択されている、といった感じです。
お力添えいただけないでしょうか?
なりと 約78日前 2018年8月28日12:53
フォームやモデルによって処理が変わりますが、流れとしては以下のような感じになると思います。
https://paiza.io/projects/5OUVzo2SRTwLyZoD-UQVRw

form.cleaned_data.get('genre') のようにして選択された値を取得し、何か値があれば(選択されていれば)filterで絞り込みます。
複数要素の場合は__in の利用を検討してみてください。