【Django】検索をマスターする

検索とフィルター

フィルターはたくさんあるデータの中から必要なものを絞り込むためのものです。
フィルターは以下のようなメソッドとして用意されています。

変数=<Model>.objects.filter(フィルターの内容)

urlpatternsの修正
今回はfindという検索用ページを新たに用意して下記のように定義します。

urlpatterns =[
..
path('find', views.find, name='find'),
]

forms.pyにFindFormを作成します。
hello/forms.py

from django import forms
from.models import Contact

class ContactForm(forms.ModelForm):
  class Meta:
    model = Contact
    fields = ['name','mail','gender','age','birthday']

class FindForm(forms.Form): #追加
  find = forms.CharField(label='Find', required=False, \
    widget=forms.TextInput(attrs={'class':'form-control'}))
  

find.htmlを作成します。
hello/templates/hello/find.html

{% load static %}
<!doctype html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>{{title}}</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.css" 
  rel="stylesheet" crossorigin="anonymous">
</head>
<body class="container">
  <h1 class="display-4 text-primary">
    {{title}}</h1>
  <p>{{message|safe}}</p>
  <form action="{% url 'find' %}" method="post">
  {% csrf_token %}
  {{ form.as_p }}
    <input type="submit" value="click"
      class="btn btn-primary">
  </form>
  <hr>
  <table class="table">
    <tr>
      <th>id</th>
      <th>name</th>
      <th>mail</th>
    </tr>
  {% for item in data %}
    <tr>
      <th>{{item.id}}</th>
      <td>{{item.name}}({{item.age}})</td>
      <td>{{item.mail}}</td>
    <tr>
  {% endfor %}
  </table>
</body>
</html>

views.pyにfind関数を作成します。
hello/views.py

from .forms import FindForm  #この文を追記

def find(request):
  if (request.method == 'POST'):
    form = FindForm(request.POST)
    find = request.POST['find']
    data = Contact.objects.filter(name=find)
    msg = 'Result: ' + str(data.count())
  else:
    msg = 'search words...'
    form = FindForm()
    data =Contact.objects.all()
  params = {
    'title': 'Hello',
    'message': msg,
    'form':form,
    'data':data,
  }
  return render(request, 'hello/find.html', params)

webブラウザにてアクセスします。

nameで検索を行うことができる

LIKE検索

値を含む検索

項目名__contains=値

値で始まるものを検索

項目名__startswith=値

値で終わるものを検索

項目名__endswith=値

それでは、contains検索を実装してみましょう。
hello/views.py

def find(request):
  if (request.method == 'POST'):
    form = FindForm(request.POST)
    find = request.POST['find']
    data = Contact.objects.filter(name__contains=find)  #追加
    msg = 'Result: ' + str(data.count())
  else:
    msg = 'search words...'
    form = FindForm()
    data =Contact.objects.all()
  params = {
    'title': 'Hello',
    'message': msg,
    'form':form,
    'data':data,
  }
  return render(request, 'hello/find.html', params)

webブラウザにてアクセスします。nameの一部分で検索をします。

大文字小文字を区別しない

大文字小文字を区別しない検索

項目名__iexact = 値

大文字小文字を区別しないLIKE検索

項目名__icontains=値
項目名__istartswith=値
項目名__iendswith=値

view.pyのfind関数を下記のように修正します。
hello/views.py

def find(request):
  if (request.method == 'POST'):
    form = FindForm(request.POST)
    find = request.POST['find']
    data = Contact.objects.filter(name__iexact=find)  #修正
    msg = 'Result: ' + str(data.count())
  else:
    msg = 'search words...'
    form = FindForm()
    data =Contact.objects.all()
  params = {
    'title': 'Hello',
    'message': msg,
    'form':form,
    'data':data,
  }
  return render(request, 'hello/find.html', params)

webブラウザにてアクセスします。

数値の比較

値と等しい

項目名=値

値よりも大きい(>)

項目名__gt=値

値以上(=>)

項目名__gte=値

値よりも小さい

項目名__lt=値

値以下(<=)

項目名__lte=値

今回はageが〇〇歳以下で検索できるようにします。
view.pyのfind関数を下記のように修正します。
hello/views.py

def find(request):
  if (request.method == 'POST'):
    form = FindForm(request.POST)
    find = request.POST['find']
    data = Contact.objects.filter(age__lte=int(find))  #修正
    msg = 'Result: ' + str(data.count())
  else:
    msg = 'search words...'
    form = FindForm()
    data =Contact.objects.all()
  params = {
    'title': 'Hello',
    'message': msg,
    'form':form,
    'data':data,
  }
  return render(request, 'hello/find.html', params)

webブラウザにてアクセスします。
21歳以下で検索してみます。

〇歳以上、〇歳以下で検索する

両方の条件に合うものを探す場合、filter引数に2つの条件を書きます。

変数 = <モデル>.objects.filter(1つ目の条件, 2つ目の条件)

view.pyのfind関数を下記のように修正します。
hello/views.py

def find(request):
  if (request.method == 'POST'):
    form = FindForm(request.POST)
    find = request.POST['find']
    val = find.split()
    data = Contact.objects.filter(age__gte=val[0], age__lte=val[1])  #☆
    msg = 'search result: ' + str(data.count())
  else:
    msg = 'search words...'
    form = FindForm()
    data =Contact.objects.all()
  params = {
    'title': 'Hello',
    'message': msg,
    'form':form,
    'data':data,
  }
  return render(request, 'hello/find.html', params)

webブラウザにてアクセスします。21歳以上40歳以下で検索してみます。
「21 40」のように間を半角スペースで区切ります。

OR検索

複数の項目でOR検索する場合は下記の形で指定します。

変数=<モデル>.objects.filter(@1つ目の条件 | @2つ目の条件)

view.pyのfind関数を下記のように修正します。nameとmailの2つを検索条件とします。
hello/views.py

from django.db.models import Q #この文を冒頭に追記

def find(request):
  if (request.method == 'POST'):
    msg = 'search result:'
    form = FindForm(request.POST)
    find = request.POST['find']
    data = Contact.objects.filter\
      (Q(name__contains=find)|Q(mail__contains=find))  #☆
  else:
    msg = 'search words...'
    form = FindForm()
    data =Contact.objects.all()
  params = {
    'title': 'Hello',
    'message': msg,
    'form':form,
    'data':data,
  }
  return render(request, 'hello/find.html', params)

webブラウザにてアクセスします。
nameで検索できます。

mailでも検索できます。

リストを使って検索

データを全部探したい場合、リストを使った検索はを行う機能があります。

変数=<モデル>.objects.filter(項目名__in=リスト)

view.pyのfind関数を下記のように修正します。
hello/views.py

def find(request):
  if (request.method == 'POST'):
    msg = 'search result:'
    form = FindForm(request.POST)
    find = request.POST['find']
    list = find.split()
    data = Contact.objects.filter(name__in=list)  #☆
  else:
    msg = 'search words...'
    form = FindForm()
    data =Contact.objects.all()
  params = {
    'title': 'Hello',
    'message': msg,
    'form':form,
    'data':data,
  }
  return render(request, 'hello/find.html', params)

ではコードを見てみましょう。
下記では入力された値をリストに変換します。

    find = request.POST['find']
    list = find.split()

splitで半角スペースでテキストを分割しリストを作ります。

data = Contact.objects.filter(name__in=list)

webブラウザにてアクセスします。
ichiroとtaroを検索してみます。「ichiro taro」をスペースで区切って検索します。

この記事は役に立ちましたか?

もし参考になりましたら、下記のボタンで教えてください。

関連記事

コメント

この記事へのコメントはありません。