サイトアイコン ITC Media

【Django】検索機能が実装できる2つの方法|オススメは?

search-form

(最終更新月:2021年12月)

まだまだDjangoを始めたばかりという方で、下記のようなお考えをお持ちの方へ

「検索機能を実装したいけど、やり方がわからない」

「Djangoにすごい詳しいというわけでもないけど、大丈夫かな??」

「今回だけでなく、今後も使えるものを探してるんだけど、、、」

当記事を通じて、

を解説していきます

2つのサーチ機能実装方法

①【views.py】filterメソッドを使う方法

views.py内のビュー関数もしくはクラス内で検索ワードによるフィルターで、新たなQuerySetを返す方法です

通常は、

qs = NippoModel.objects.all()

などとQuerySetを全て取得しているのに対し、

qs = NippoModel.objects.filter(content__icontains="検索ワード")

のようにします

【メリット】

views.py内の一関数を書き換えるだけで済みますので、一番シンプルでカンタンな方法です

【デメリット】

複数のアプリなどに渡り検索機能を実装するときには、それぞれの関数・クラス内で定義しなければならないため、逆にコードが長くなる可能性があります

よって、長期的にこちらはオススメしません

②【models.py】新たなメソッド「search」を作り、実装する方法

objects.all()やobjects.filter()のように、新たなメソッドを追加する方法です

【デメリット】

新たなメソッドを追加するため、複数のクラスを上書き作成する必要があり、導入まで少し手間がかかります

【メリット】

ただし、メソッドを一度作ればいつでもどこでも使用できます

当アプリではこちらを採用し、三章で詳しく解説していきます

ただ、「Djangoを始めたばかりなのに大丈夫だろうか?」という方のために、これだけは知っておきたい前提知識をまとめましたのでご覧ください

Django初心者でもこの3つだけわかれば大丈夫!

[ad]

①Pythonクラスの継承

既存のクラスを使用し、新たな機能を追加する方法です

「検索機能をどうしようか?」と悩んでいるレベルまで来ているあなたは問題ありません

②フィルタメソッド

QuerySetを一定の条件でソートします

使い方は、

<QuerySet>.objects.filter(フィールド名__ルックアップ="値")

「ルックアップってなに?」「よくわからない!」という方は↓の記事に目を通してからお越しください

③Qオブジェクト

「初めて聞いた!」という方もご安心ください

フィルタメソッド内でor検索をする際に使用する「Qオブジェクト」

使い方は、

from django.db.models import Q #インポート
<QuerySet>.objects.filter(Q(フィールド名=”値”) | Q(フィールド名=”値2”))

という形になります

「詳しく知りたい!」という方はこちらもどうぞ↓

この3つがわかっていれば問題ありません

実装に移りましょう!

「search」メソッドを追加して、検索機能を実装する

この方法は下記の2ステップを行う必要があります

  1. models.pyで新たなメソッド「search」を追加する
  2. views.pyでsearchメソッドを使った方法に切り替え

それぞれ見ていきます

サーチメソッドの追加するための3つのステップ

①QuerySetクラスの書き換え

DjangoモデルにはQuerySetクラスが定義されており、get_querysetメソッドを使った場合に呼び出されます

ここで新たに「search」というメソッドを追加します

from django.db.models import Q #インポート

class NippoModelQuerySet(models.QuerySet):
    def search(self, query=None):
        qs = self
    qs = qs.filter(public=True) #公開済みの日報のみでQuerySetを作成しています
        if query is not None:
            or_lookup = (
                Q(title__icontains=query)|
                Q(content__icontains=query)            
            )
            qs = qs.filter(or_lookup).distinct()
        return qs.order_by("-timestamp") #新しい順に並び替えてます

models.QuerySetを継承し、「search」メソッドを追加してます

引数「query」で検索ワードを取得し、Qオブジェクトでor検索を実行しています

②マネジャークラスの書き換え

models.Mangerを継承した新たなクラスを作成します

class NippoModelManager(models.Manager):
    def get_queryset(self):
        return NippoModelQuerySet(self.model, using=self._db)

    def search(self, query=None):
        return self.get_queryset().search(query=query)

get_querysetメソッドが呼び出された時に作成したQuerySetクラスを使うように指示しています

searchメソッドを追加しています

③マネジャークラスとモデルクラスの紐付け

紐付けを行うことにより、

モデルクラス.objects.search(**kwargs)

が使えるようになります

モデルクラス内で

objects = NippoModelManager()

を追記しましょう!

【コード全体】nippo > models.py

from django.db import models
from django.db.models import Q
from django.contrib.auth import get_user_model

User = get_user_model()

class NippoModelQuerySet(models.QuerySet):
    def search(self, query=None):
        qs = self
        qs = qs.filter(public=True)
        if query is not None:
            or_lookup = (
                Q(title__icontains=query)|
                Q(content__icontains=query)            
            )
            qs = qs.filter(or_lookup).distinct()
        return qs.order_by("-timestamp")

class NippoModelManager(models.Manager):
    def get_queryset(self):
        return NippoModelQuerySet(self.model, using=self._db)

    def search(self, query=None):
        return self.get_queryset().search(user=user, query=query)

class NippoModel(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(max_length=100, verbose_name="タイトル")
    content = models.TextField(max_length=1000, verbose_name="内容")
    public = models.BooleanField(default=False, verbose_name="公開する")
    timestamp = models.DateTimeField(auto_now_add=True)

    objects = NippoModelManager()

    def __str__(self):
        return self.title

views.pyで新たなメソッド「search」を使う

クラスベースビュー内の「get_queryset」関数の抜粋です

def get_queryset(self):
    try:
        q = self.request.GET["search"]
    except:
        q = None
    return NippoModel.objects.search(query=q)

まとめ

[ad]

検索機能を実装するには、

  1. シンプルにフィルタメソッドを使う方法
  2. メソッドを新規作成し、使用する方法

が2通りありました

オススメは長期的なことも考えて、2のメソッドを新規で作成する方法です

Pythonクラスの継承フィルタメソッドQオブジェクトについての前提知識が必要でした

メソッドを追加するには、QuerySetクラスとMangerクラスを上書き作成し、モデルクラスと紐付けることでいつでもどこでも使用可能となります

検索機能に限らず、「こんなメソッドがあったらいいなぁ」というものがあれば当記事の内容を応用して作ることも可能です

是非お試しください!

モバイルバージョンを終了