mysqlの曖昧検索について
https://www.softel.co.jp/blogs/tech/archives/1877
クエリについてはこちらを参考にさせていただきました
Djangoでどう書くか
特殊なクエリはfilter
では無理なのでextra
を使います
def get_ambiguous_queryset(self, queryset, value, columns):
"""
曖昧検索用のquerysetを返す
:param queryset:
:param value:
:param columns:
:return:
"""
query_text = ''
count = 0
for column in columns:
if query_text != '':
query_text += ' OR '
temp_value = value
if isinstance(value, list):
if len(value) > count:
temp_value = value[count]
else:
temp_value = value[0]
query_text += f"CONVERT({column} USING utf8) COLLATE utf8_unicode_ci LIKE %s"
temp_value = temp_value.replace('%', r'\%%').replace('_', r'\_')
params.append(f'%{temp_value}%')
count += 1
if query_add:
query_text += query_add
return queryset.extra(where=[query_text], params=params)
使い方
# queryset、検索したい値、検索対象のカラムを渡す
self.get_ambiguous_queryset(queryset, value, ['name', 'code', 'description'])
# 検索したい値は配列でも渡せます(検索対象のカラムと連動してます)
self.get_ambiguous_queryset(queryset, [value, self.convert_tel(value)], ['name', 'tel'])
joinが必要な場合には注意
# NGのパターン(shopがjoinされずエラーになります)
self.get_ambiguous_queryset(queryset, value, ['shop.name', 'shop.code'])
# OKのパターン(filterにshopを書いておくとjoinされる)
self.get_ambiguous_queryset(queryset, value, ['shop.name', 'shop.code']).filter(shop__name__isnull=False)
所感
クエリでの書き方がわかっていても、それをDjangoでどう書いたらいいかはいつも悩みます