1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Django】超最短で複数キーワード検索の制御をする

Last updated at Posted at 2023-05-18

Djangoのフォーム制御は一癖も二癖もあり、細かい制御をしていくとなるとけっこう煩雑になります。そのたびに分岐したりするのはすごく面倒なので、最短で複数のキーワードに対応できる方法がないか調べてみたところそれを実現しているページがあり、実装してみてこれはかなり使えると思い、更に簡略化したものを記事にしてみました。

記事の要件定義はMstBooksという書籍マスターから該当する作品(book_nm)をキーワード検索したい場合です。

py
from django.db.models import Q
from functools import reduce
from operator import and_

  def(request):
    #中略
    if form.is_valid():
      keywords =  [''] if form.cleaned_data['keyword'] is '' else form.cleaned_data['keyword'].split()
      result = MstBooks.objects.filter(
        reduce(and_,[Q(book_nm__icontains=q) for q in keywords]),        
      ).order_by("id")

おわりです

解説

流石にこれでは記事としてあんまりなので、解説を加えます。テンプレートにはname=keywordとなったテキストボックスがあり、ここにフリーワードが入力されます。

そして、Pythonの三項演算子の公式に従って、文字が複数入っている、または単一文字列の場合はsplit()制御によってオブジェクト化されます。splitは引数を何も入れない場合\sが基準となるので、複数ワードが入っている場合はきちんと文字が分けられ、単一ワードの場合は入力文字一つがオブジェクト化されます。対して無記入の場合は空の値を代入しておきます。こうやっておかないと、検索条件のreduceでエラーが発生します。

TypeError: Reduce() of empty sequence with no initial value

クエリセットの式

そして、クエリ検索条件にセットしている式はこのようになっています。

reduce(and_,[Q(book_nm__icontains=q) for q in keywords])

まずQオブジェクトでないと条件式をループできません。そしてPythonのループ式を使って、検索キーワードを一つずつicontainsに与えています。icontainsはlike演算子と同じ働きをするQオブジェクト上のメソッドです。

またreduceはループ処理を再帰的に実行してくれるものなので、どんどんと計算式を追記してくれます。その際、結合条件としているのがand_なので、これによってand文を次々と追記してくれるわけです。検索条件が存在しない場合は空オブジェクトが渡されます。

また、こうやっておけば、フォームを追加して検索条件を足したい場合でもすぐに対応できます。

検証

クエリに対し、queryプロパティを付与するとSQLを出力できます。

print(result.query)

SELECT `app_mstbooks`.`id`, `app_mstbooks`.`book_nm`, 
`app_mstbooks`.`book_yomi`,`app_mstbooks`.`auth_no`, `app_mstbooks`.`published`, 
`app_mstbooks`.`publisher`, `app_mstbooks`.`files`, `app_mstbooks`.`jitai`,
 `app_mstbooks`.`kana` FROM `app_mstbooks`  
WHERE (`app_mstbooks`.`book_nm` LIKE %の% AND `app_mstbooks`.`book_nm` LIKE %に% )) 
ORDER BY `app_mstbooks`.`id` ASC

このようにすればテキストボックスに「の に」と入力すると「~の~」、「~に~」が含まれる書籍タイトルが検索されます。

  • 恩讐彼方

※参考までに、未入力の場合はこのようになります。

app_mstbooks`.`book_nm` LIKE %%

参考にしたサイト

【Django】サイト内検索機能を組み込んで複数のキーワード入力に対応させる

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?