Search code examples
pythondjangofilterdjango-rest-frameworkdjango-filter

Django-filter error: 'Meta.fields' must not contain non-model field names


I am working with Django REST framework and django-filters and and I'd like to use the reverse relationship annotation_set as one of filters for a GET API that uses the model Detection. The models are the following:

class Detection(models.Model):
    image = models.ImageField(upload_to="detections/images")

    def local_image_path(self):
        return os.path.join('images' f"{self.id}.jpg")


class Annotation(models.Model):
    detection = models.ForeignKey(Detection, on_delete=models.CASCADE)
    attribute = models.CharField(max_length=255)

The serializer is:

class DetectionSerializer(UniqueFieldsMixin, serializers.ModelSerializer):
    local_image_path = serializers.CharField()

    class Meta:
        model = Detection
        fields = '__all__'

And the viewset is:


class DetectionTrainingViewSet(
        mixins.ListModelMixin,
        mixins.RetrieveModelMixin,
        viewsets.GenericViewSet
    ):
    queryset = Detection.objects.all()
    serializer_class = DetectionSerializer
    filterset_fields = ('annotation_set__id', )

    @action(methods=['GET'], detail=False)
    def list_ids(self, request):
        queryset = self.get_queryset()
        filtered_queryset = self.filter_queryset(queryset)
        return Response(filtered_queryset.values_list('id', flat=True))

When I make a call to the endpoint, I get the error:

'Meta.fields' must not contain non-model field names: annotation_set__id

Shouldn't the field exist? Note: I tried to add other fields to the Annotation model and then use annotation_set__newfield but I still have the error. I can confirm that the newfield exists because it is correctly serialized and return by the API when I comment out the line that set the filterset_fields.


Solution

  • Apparently I had to explicitly state the name of the reverse relationship:

    class Annotation(models.Model):
        detection = models.ForeignKey(Detection, on_delete=models.CASCADE, related_name='annotation_set')
        attribute = models.CharField(max_length=255)
    

    If anybody knows why, I'd love to know it! Thanks!