Mawa Town

Mawaという人が作る小さな町でMawaTownです。技術と音楽が好き。

エラー Related Field got invalid lookup: icontains が DRF SearchFilter で出た場合の対応

Django

Django

症状

#model

class Hoge(models.Model):
    hoge_name = models.CharField(max_length=300, blank=True, null=True)
    first_category = models.ManyToManyField(HogeCategory, blank=True)

というモデルをDRFのListAPIViewでとってきたいとする。フィルターをかけたいものが2つ以上あるので、search_fields(?search=で検索できるようになるもの)と別途q=でフィルターもかけられるようにした。

#api.views

class HogeListAPIView(ListAPIView):
    permission_classes = [AllowAny]
    queryset = Hoge.objects.all()
    serializer_class = HogeListSerializer
    filter_backends= [SearchFilter] #
    search_fields = ['first_category__id'] #['first_category']でも同じエラー出る

    def get_queryset(self, *args, **kwargs):
        queryset_list = Hoge.objects.all()
        query_f = self.request.GET.get("f")
        if query_f:
            queryset_list = queryset_list.filter(
                    Q(hoge_name__icontains=query_f)
                    ).distinct()
        return queryset_list

このようにした場合、エラ−になり、エラーメッセージはRelated Field got invalid lookup: icontains と出た。試行錯誤実験をして挙動を確認したところ、 SearchFilterの場合、ForeignKeyのフィールドはすべてのフィールドで、search_fields = ['first_category__id']のようにSearchFilterの対象にすると、同じRelated Field got invalid lookup: icontainsエラーがでたので、以下のようにすることでエラー回避ができる。

解決策

うまく行ったパターン

class HogeListAPIView(ListAPIView):
    permission_classes = [AllowAny]
    queryset = Hoge.objects.all()
    serializer_class = HogeListSerializer
    filter_backends= [SearchFilter]
    search_fields = ['hoge_name'] #ForeignKey以外のフィールドを対象にする
    pagination_class = LimitOffsetPagination

    def get_queryset(self, *args, **kwargs):
        queryset_list = Hoge.objects.all()
        query_f = self.request.GET.get("f") #ForeignKeyのフィルタリングは、get_querysetのオーバーライドで対応
        if query_f:
            queryset_list = queryset_list.filter(
                    Q(first_category__id__contains=query_f)
                    ).distinct()
        return queryset_list

参考記事(ダイレクトに同じ症状ではないけどもヒントにはなった)

stackoverflow.com