Djangoで作る初めてのウェブアプリケーション(番外編)検索機能
本記事はDjangoで作成したデータベースのデータの検索機能を追加します。
以前、マガジン(『超入門』Djangoで作る初めてのウェブアプリケーション)で作成した、Djangoアプリを拡張します。
作成順はシンプルに行います。
index.htmlに検索フォームを設置して、views.pyを編集します。
以上です!
検索フォームを作成
今回もBootstrap(Part7 見栄えを Bootstrapで整えよう)を使いフォームを装飾していきます。
index.htmlに検索フォームと、検索結果の数を追加します。
blog/templates/blog_app/index.html
{% extends 'base.html' %}
{% block content %}
<h1 class="mt-5 pt-4 text-center">ブログサイト</h1>
<!-- 検索フォーム -->
<div class="d-flex justify-content-center">
<form class="form-inline my-2" method="GET" action="{% url 'blog_app:index' %}">
<input type="text" class="form-control" name="q" value="{{request.GET.q}}">
<button type="submit" value="search" class="btn btn-primary">検索</button>
</form>
</div>
<!-- 検索フォーム -->
<!-- 検索結果の数 -->
{% if query %}
<p class="text-center font-weight-bold h4">{{posts.count}}件</p>
{% endif%}
<!-- 検索結果の数 -->
#省略
コード説明です。
今回の検索フォームは、特にデータの追加や削除など変更がないためGETメソッドを使用します。そしてフォームの値の送り先は、同じページに検索結果を返したいのでviews.pyのindex関数にフォームの値を渡します。
valueの値の"{{request.GET.q}}"ですが、入力した値が、フォーム内に残るように設定しています。これが無いと、検索結果を表示したときにフォーム内に入力した値は残りません。
ここで重要なのが、name属性の"q"です。これはわかりやすくqueryの頭文字をとっています。
このqueryとは下のようなURLの?q=以降に実際に入力された内容をURLの一部として取得してその値に合致した、結果を返します。
例:http://127.0.0.1:8000/?q=マガジン
検索内容(値)がname属性によりvews.pyのindex関数で受け取ります。
最後にif文を使用して何件データがあるのかcount関数を使用して表示しています。
表示結果
index関数を編集しよう
検索フォームから送られてきた内容をindex関数で処理します。
blog/blog_app/views.py
#省略
from django.db.models import Q #追加
def index(request):
query = request.GET.get('q')
if query:
posts = Post.objects.all().order_by('-created_at')
posts = posts.filter(
Q(title__icontains=query)|
Q(user__username__icontains=query)
).distinct()
else:
posts = Post.objects.all().order_by('-created_at')
return render(request, 'blog_app/index.html', {'posts': posts, 'query': query,})
#省略
コード説明です。
データベース内を検索するときはQ関数をインポートします。
そして、関数内のquery = request.GET.get('q')でフォームのname属性で指定したq(入力内容)を取得し、queryに代入します。
if query: もしquery(入力内容)が存在する場合は、一度Postのデータを全て取得して、posts = Post.objects.all().order_by('-created_at')変数postsに代入します。それに対してfilter関数を使い、Q関数の引数で何を対象に絞り込むか決めます。
今回は、titleとuser__usernameに合致するよう検索します。
icontainsというのは、検索対象の一部でも合致していれば検索に引っかかります。
その他にも、全ての入力内容が合致しないと引っかからないexactなど様々な種類があります。
このQ関数を複数使用することで、さらに検索対象を追加することができます。(Qを増やす場合は|(パイプ)を忘れないでください)
posts = posts.filter(
Q(title__icontains=query)|
Q(user__username__icontains=query)
)
フィルターをかけた結果の配列に重複があると困るのでdistinct()を使い、重複している要素を一意に取り出します。
これで検索結果が複数あるときは〇〇件と表示され、なければ0件と表示されます。
検索を行わずに、index.htmlにアクセスすると従来のように記事が表示されます。
通常通りのアクセス
検索結果の表示
この記事が気に入ったらサポートをしてみませんか?