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

search-formDjango

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

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

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

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

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

当記事を通じて、

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

を解説していきます

【著者プロフィール】

profile_icon
【Python・Django歴】10年 x 【営業マン歴】11年
HP作成、社内システムの構築、コンサルティング

当ブログを通じて、下記アプリの作り方、コード等を公開、解説しています

☆日報アプリ「D-Repo」(デモ版)→こちら

※Djangoをベースに作成したアプリです

☆便利ツールアプリ「Tool Station」→こちら

※Django REST frameworkとReactで作成しているアプリです

初期費用ゼロ/月9,800円でWebデザインが学べる

デザインを習得するためには、客観的なフィードバックと改善が不可欠です。

以下の記事ではこんなWebデザインスクールをご紹介しています。

  • 初期費用ゼロで、月々9,800円のみ
  • オンラインで、教材が使い放題
  • コンテストや実務案件にチャレンジして報酬もGETできる

デザナルはトップデザイナーからレビューがもらえる、格安の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クラスを上書き作成し、モデルクラスと紐付けることでいつでもどこでも使用可能となります

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

是非お試しください!

当記事をご覧の方の中にも「そろそろウェブでアプリを公開してみたいなぁ」「どうやって公開するの?」という方もいらっしゃるのではないでしょうか?
下記の通り、別記事ではDjangoアプリの公開方法公開までの準備についての解説をしていますのでご覧ください!

「Webアプリを公開したい!」という方へ

【保存版】Apache WebサーバーでDjangoアプリを公開
Djangoが公開できる月500円~のレンタルサーバー
【初心者向け】ムームードメインで独自ドメインを取得する3ステップ
固定IPアドレスのみ単独で契約できる「インターリンク マイIP」Ubuntuコンピューターに固定IPを付与する方法

当ブログでは、日報アプリ開発を通じて、Webアプリを一から開発し公開するまでを初学者の方でもわかるようにと記事を連載しています

「Djangoでのアプリ開発を学びたい!」
「Djangoで開発したアプリをWebで公開するにはどうするの?」

という方は必見です!

【Django】チュートリアル|日報アプリの開発から公開まで
Djangoのチュートリアルをお探しですか?具体的に「手を動かして作ってみたい!」という方へ向けて、誰でもできる簡易的な日報アプリの開発を通じて、Djangoの様々な機能に触れていくシリーズとなっています。PythonでWebアプリを作りたい方、必見の記事となります!
タイトルとURLをコピーしました