(最終更新月:2021年12月)
まだまだDjangoを始めたばかりという方で、下記のようなお考えをお持ちの方へ
「検索機能を実装したいけど、やり方がわからない」
「Djangoにすごい詳しいというわけでもないけど、大丈夫かな??」
「今回だけでなく、今後も使えるものを探してるんだけど、、、」
当記事を通じて、
- 検索機能が実装できる2つの方法
- Django初心者でも、この3つだけわかれば大丈夫
- 実例付!一度理解すれば何度でもどんなものにも使える実装方法
を解説していきます
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ステップを行う必要があります
- models.pyで新たなメソッド「search」を追加する
- 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]
検索機能を実装するには、
- シンプルにフィルタメソッドを使う方法
- メソッドを新規作成し、使用する方法
が2通りありました
オススメは長期的なことも考えて、2のメソッドを新規で作成する方法です
Pythonクラスの継承、フィルタメソッド、Qオブジェクトについての前提知識が必要でした
メソッドを追加するには、QuerySetクラスとMangerクラスを上書き作成し、モデルクラスと紐付けることでいつでもどこでも使用可能となります
検索機能に限らず、「こんなメソッドがあったらいいなぁ」というものがあれば当記事の内容を応用して作ることも可能です
是非お試しください!