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
.
CodePudding user response:
Looking at the django filter docs, you may have missed a reference to DjangoFilterBackend, eg
queryset = Detection.objects.all()
serializer_class = DetectionSerializer
filter_backends = (filters.DjangoFilterBackend,)
filterset_fields = ('annotation_set__id', )
(see: https://django-filter.readthedocs.io/en/stable/guide/rest_framework.html)
CodePudding user response:
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!