过滤嵌套资源Django REST Framework

时间:2017-05-19 16:47:47

标签: django django-rest-framework django-filter

一开始我想说我找到了我的问题的部分答案(How can I apply a filter to a nested resource in Django REST framework?),但它不能100%覆盖我的问题。

我已经嵌套了3个模型:

- ModelA

- ModelAB

---- ModelB

我需要通过ModelB获得所有ModelA过滤,但我还需要过滤ModelB。

实施例。 / MODELA?modelab__modelb__id = 100

需要返回值:

[{id:1,
    modelab: [{
        id:10
        modelb{
          id: 100
        }]
    }]
}]

但它返回

[{id:1,
    modelab: [{
        id:10
        modelb{
          id: 100
        },
        id:11
        modelb{
          id: 102
        }]
    }]
}]

所以它只对第一级嵌套进行过滤。我想应用过滤器将应用于所有嵌套模型。

我的代码:

// models.py
class ModelA(models.Model):
    name = models.TextField()
class ModelB(models.Model):
    name = models.TextField()
class ModelAB(models.Model):
    modelA = models.ForeignKey(ModelA)
    modelB = models.ForeignKey(ModelB)
    type_id = models.IntegerField(default=0)

// views.py
class ModelAFilter(filters.FilterSet):

    vacancy_id = Filter(name="vacancy__id")
    class Meta:
        model = Candidate
        fields = ('name', 'modelAB__modelB__name')

class ModelAViewSet(viewsets.ModelViewSet):
    queryset = ModelA.objects.all()
    serializer_class = ModelASerializer

    filter_backends = (filters.DjangoFilterBackend, )
    filter_class = ModelFilter

// serializers.py
class ModelBSerializer(serializers.ModelSerializer):

    modelB = ModelB(many=True)

    class Meta:
        model = ModelB
        fields = ('id', 'name')

class ModelABSerializer(serializers.ModelSerializer):

    modelB= ModelBSerializer(many=True)

    class Meta:
        model = ModelB
        fields = ('id', 'name', 'modelB',)

class ModelASerializer(serializers.ModelSerializer):

    modelAB = ModelAB(many=True)

    class Meta:
        model = ModelA
        fields = ('id', 'name', 'modelAB')

1 个答案:

答案 0 :(得分:1)

您必须覆盖视图集上的get_queryset方法并过滤prefetch_related查询:

def get_queryset(self):
    # get the filter value
    modelb_id = self.request.query_params.get('modelab__modelb__id', None)
    queryset_modelab = ModelAB.objects.all()
    # you can use django-filter class here too
    if modelb_id:
        queryset_modelab = queryset_modelab.filter(modelb_id=modelb_id)
    queryset_modelab.select_related('modelb')
    queryset = (ModelA.objects
                .prefetch_related(
                    Prefetch('modelab_set', queryset=queryset_modelab))
                .all())
    # modela filter class will work on this queryset
    return queryset