django-filter利用時にOR検索したかった件


初めてdjango-rest-frameworkを利用したシステムを作ることになった。
django-filterと言われるものが有るらしいので入れた際に時間がかかった点について書いていこうと思う。
https://django-filter.readthedocs.io/en/stable/guide/install.html

やりたかったこと

Customerモデルを検索するときにcustomerNameに値を渡したら、customerNameに該当するものとfuriganaに該当するデータを出力したかった。

結果

filters.FilterSetにカスタムのやつ作る

コマンドプロンプト
$ pip install django-filter

djangoのsettings.pyのINSTALLED_APPS追記する。

settings.py
INSTALLED_APPS = [
    ...
    'django_filters',
]

Djangoにアプリを追加したり色々、ここらへんは省略。
以下はmodelsやview、serializerの設定を記載します。

models.py
class Customer(models.Model):
    customerCode = models.IntegerField("得意先コード")
    customerName = models.CharField("得意先名", max_length=100)
    furigana = models.CharField("ふりがな", max_length=100, blank=True, null=True)

    def __str__(self):
        return self.name
serializers.py
from rest_framework import serializers
from .models import Customer

class CustomerSerializer(serializers.ModelSerializer):
    class Meta:
        model = Customer
        fields = '__all__'
views.py
from rest_framework import  viewsets
from django_filters import rest_framework as filters
from django.db.models import Q
from .serializers import CustomerSerializer
from .models import Customer

class CustomerFilter(filters.FilterSet):
    # フィルタの定義
    customerCode = filters.NumberFilter(lookup_expr='exact')
    customerName = filters.CharFilter(method='myCustomNameFilter')
    furigana = filters.CharFilter(lookup_expr='contains')

    class Meta:
        model = Customer
        # フィルタを列挙する。
        # デフォルトの検索方法でいいなら、モデルフィールド名のフィルタを直接定義できる。
        fields = ['customerCode','customerName ', 'furigana']

    def myCustomNameFilter(self,queryset,name,value):
        #ここでOR検索を入れる。fieldsのcustomerNameに入ってきた値を利用
        return Customer.objects.filter(Q(customerName__startswith=value)|Q(furigana__startswith=value))


class CustomerViewSet(viewsets.ModelViewSet):
    queryset = Customer.objects.all()
    serializer_class = CustomerSerializer
    filter_class = CustomerFilter
urls.py
from rest_framework import routers
from .views import  CustomerViewSet

router = routers.DefaultRouter()
router.register("customers",CustomerViewSet)