基于联接模型的Django过滤器

时间:2019-01-16 22:52:11

标签: django django-filter django-serializer

假设我有以下设计

database table

一个track有一个song,一个song有一个singer。 我希望该曲目也允许基于歌手姓名进行过滤。

因此,我需要track模型提取singer名称。我被过滤器卡住了。

我收到以下错误消息:

File ".../lib/python3.6/site-packages/django_filters/filterset.py", line 352, in get_filters
    "%s" % ', '.join(undefined)
TypeError: 'Meta.fields' contains fields that are not defined on this FilterSet: singer

我从this那里听说过要使用__,但我不知道如何应用。

这是代码

class TrackSerializer(MyModelSerializer):
    singer = serializers.SerializerMethodField()

    def get_singer(self, track): # Is there any shortcut?
        song = Song.objects.get(id=track.song_id)
        if song is not None:
            return Channel.objects.get(id=song.singer_id).name
        else:
            return ''

    class Meta:
        model = Track
        fields = (
            'id',
            'name',
            'song',
            'singer',
        )

class TrackFilterSet(MyFilterSet):
    singer = CharFilter(method='singer_filter')
    song = RefineModelChoiceFilter(
        queryset=Song.objects.all(),
        refine_choices=lambda qs, keywords, request: qs.filter(name__icontains=keywords)
    )

    def singer_filter(self, queryset, name, value):
        # print('queryset:', TrackSerializer(queryset, many=True))
        return queryset.filter(**{
            name: value,  # ???????????
        })

    class Meta:
        model = Track
        fields = (
            'singer',
            'song',
        )


class TrackViewSet(MyViewSet):
    queryset = Track.objects.all()
    serializer_class = TrackSerializer
    filterset_fields = ('singer', 'song')

    def filter_refine_choices_singer(self, qs, keywords, request):
        return qs.filter(name__icontains=keywords)

    def filter_refine_choices_song(self, qs, keywords, request):
        return qs.filter(name__icontains=keywords)

2 个答案:

答案 0 :(得分:1)

尝试将filterset_fields作为数组放在[]而不是()之间。

filterset_fields = ['singer', 'song']

答案 1 :(得分:0)

我认为方法singer_filter应该是这样的:

def singer_filter(self, queryset, name, value):
    return queryset.filter(song_id__singer_id__name_icontains=value)

我没有对此进行测试,但我认为除非禁止第三种关系__,否则类似的事情应该起作用。在这里看看: https://django-filter.readthedocs.io/en/master/ref/filters.html?highlight=method