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

※本サイトにはプロモーション・広告が含まれています。

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

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

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

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

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

当記事を通じて、

  • 検索機能が実装できる2つの方法
  • Django初心者でも、この3つだけわかれば大丈夫
  • 実例付!一度理解すれば何度でもどんなものにも使える実装方法

を解説していきます

✔YouTube解説動画

当記事の内容は動画を見ながら進めると、約15分程度で完了します。

動画ならではの情報も解説しているので、記事と一緒にご覧ください。

動画の概要欄には、単元ごとのコードを紹介しているgithubページも載せています。

筆者プロフィール

筆者プロフィールアイコン

【現職】プロダクトマネージャー

【副業】ブログ(月間17万PV)/YouTube/Web・アプリ制作

「プログラミング × ライティング × 営業」の経験を活かし、30後半からのIT系職へシフト。当サイトでは、実際に手を動かせるWebアプリの開発を通じて、プログラミングはもちろん、IT職に必要な情報を提供していきます。

【当ブログで紹介しているサイト】

当サイトチュートリアルで作成したデモ版日報アプリ

Django × Reactで開発したツール系Webアプリ

✔人に見せても恥ずかしくないコードを書こう

「リーダブルコード」は、わかりやすく良いコードの定義を教えてくれる本です。

  • 見るからにきれいなコードの書き方
  • コードの分割方法
  • 変数や関数の命名規則

エンジニアのスタンダートとすべき基準を一から解説しています。

何回も読むのに値する本なので、ぜひ手にとって読んでみてください。

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つだけわかれば大丈夫!

①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)

まとめ

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

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

が2通りありました

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

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

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

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

是非お試しください!

✔ウェブアプリを公開したい方へのおすすめ記事

【保存版】Apache WebサーバーでDjangoアプリを公開
Djangoが公開できる月500円~のレンタルサーバー
【初心者向け】ムームードメインで独自ドメインを取得する3ステップ
【実体験】マイIPの使い方を解説|固定IPアドレスを取得・設定する
タイトルとURLをコピーしました