見出し画像

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関数を使用して表示しています。

表示結果

スクリーンショット 2020-05-12 22.24.01

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関数の引数で何を対象に絞り込むか決めます。

今回は、titleuser__usernameに合致するよう検索します。

icontainsというのは、検索対象の一部でも合致していれば検索に引っかかります。

その他にも、全ての入力内容が合致しないと引っかからないexactなど様々な種類があります。

このQ関数を複数使用することで、さらに検索対象を追加することができます。(Qを増やす場合は|(パイプ)を忘れないでください)
posts = posts.filter(
Q(title__icontains=query)|
Q(user__username__icontains=query)
)

フィルターをかけた結果の配列に重複があると困るのでdistinct()を使い、重複している要素を一意に取り出します。

これで検索結果が複数あるときは〇〇件と表示され、なければ0件と表示されます。

検索を行わずに、index.htmlにアクセスすると従来のように記事が表示されます。

通常通りのアクセス

スクリーンショット 2020-05-13 7.37.24

検索結果の表示

スクリーンショット 2020-05-13 7.37.44

この記事が気に入ったらサポートをしてみませんか?