Query parameter doesn't match any record returns "Select a valid choice. That choice is not one of the available choices." instead of empty array

Viewed 41

I'm using DjangoFilterBackend to handle query parameters on a ModelViewSet. My expectation would be that if nothing in the table matches one of the query params, that it would just return an empty array.

Instead it returns:

{
  "document_guid": [
    "Select a valid choice. That choice is not one of the available choices."
  ]
}

Which just seems like an odd response to me so I'm wondering: how can I change this behavior?

EDIT: To clarify changing the behavior, is there a way to change it in DjangoFilterBackend as opposed to overriding the behavior in the views.py?

Would much rather just have the following indicating nothing matched:

[]

I'm aware of this similar question, but I'm already doing what they suggested:

https://stackoverflow.com/a/62219220/3123109

Here's the URI where there are no records that match document_guid (but there are some that match user_guid):

localhost/api/d2u/?user_guid=55d57235-79b0-ec11-9840-000d3a5a343c&document_guid=df4c9c11-49dd-ec11-a7b6-000d3a3667a1

Here's the related code:

# views.py
class Document2UserSyncViewSet(viewsets.ModelViewSet):
    filter_backends = [DjangoFilterBackend]
    filter_fields = [
        'id',
        'document_guid',
        'user_guid'
    ]
    permission_classes = [PowerAutomatePermissions]
    queryset = Document2User.objects.all().order_by('id')
    serializer_class = Document2UserSerializer
# serializer.py
class Document2UserSerializer(serializers.ModelSerializer):
    """Serializer for the d2u model.

    Returns all fields.
    """
    class Meta:
        model = Document2User
        fields = '__all__'
# models.py
class Document2User(models.Model):
    document_guid = models.ForeignKey(
        Documents,
        to_field='guid',
        on_delete=models.CASCADE,
        db_column='document_guid'
    )
    user_guid = models.ForeignKey(
        CRMFields,
        to_field='guid',
        on_delete=models.CASCADE,
        db_column='user_guid'
    )
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = 'document_to_user'
        unique_together = [['user_guid', 'document_guid']]
1 Answers

I talked to the developer who suggested doing the following which has worked for me. This will return an empty array when there are not matches instead of that message.

# utils/filters.py
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import serializers


class StrictDjangoFilterBackend(DjangoFilterBackend):
    """Return no results if the query doesn't validate.
    """
    def filter_queryset(self, request, queryset, view):
        try:
            return super().filter_queryset(request, queryset, view)
        except serializers.ValidationError:
            return queryset.none()
# documents/views.py
from utils.filters import StrictDjangoFilterBackend


class Document2UserSyncViewSet(viewsets.ModelViewSet):
    filter_backends = [StrictDjangoFilterBackend]
    filter_fields = [
        'id',
        'document_guid',
        'user_guid'
    ]
    permission_classes = [PowerAutomatePermissions]
    queryset = Document2User.objects.all().order_by('id')
    serializer_class = Document2UserSerializer
Related