Skip to content

Browsable API doesn't show "OPTIONS" and "Filters" button for non-detail custom actions #9739

Open
@bartvanandel

Description

@bartvanandel

We have a couple custom @action-annotated count functions, with detail=False. They do show up in the browsable API, however, no OPTIONS button is rendered for them.

I noticed this while trying to figure out how to get it to show the "Filters" button for those actions, because basically I'm trying to get some aggregated information (count, using some grouping) on a filtered query.

This is what I found out:

Our base code, where filtering works fine via URL, but neither "OPTIONS", nor "Filters" appears as a button:

# Settings:

from configurations import Configuration

class Config(Configuration):
    ...
    REST_FRAMEWORK = {
        ...
        "DEFAULT_FILTER_BACKENDS": [
            "rest_framework.filters.SearchFilter",
            "rest_framework.filters.OrderingFilter",
            "django_filters.rest_framework.DjangoFilterBackend",
        ],
    }
    ...



# View set:

class SomeViewSet(ModelViewSet):
    ...

    @action(
        detail=False,
        methods=[HTTPMethod.GET],
        pagination_class=None,
    )
    def count(self, request):
        raw_data = self.filter_queryset(
            self.get_queryset()
            .values("status")
            .annotate(count=Count("status"))
            .order_by("status")
        )

        data = {
            "grouping": ["status"],
            "items": {item["status"]: item["count"] for item in raw_data},
        }

        return Response(status=status.HTTP_200_OK, data=data)

Changing the annotation as follows will cause an error when querying the API:

# import settings in the file...
from django.conf import settings

...

@action(
    detail=False,
    methods=[HTTPMethod.GET],
    filter_backends=settings.REST_FRAMEWORK.get("DEFAULT_FILTER_BACKENDS")),
    pagination_class=None,
)

The error says:

  File "/.../backend-django/.venv/lib/python3.13/site-packages/rest_framework/generics.py", line 154, in filter_queryset                                                                                                                                                   
    queryset = backend().filter_queryset(self.request, queryset, self)                                                                                                                                                                                                                    
               ~~~~~~~^^                                                                                                                                                                                                                                                                  
TypeError: 'str' object is not callable

Now, changing the DEFAULT_FILTER_BACKENDS config to point to actual classes, like the following, will result in an "OPTIONS" button being shown, and the request now runs without error again. However, this change causes other problems such as pagination on other (e.g. list) endpoints to be entirely skipped:

from configurations import Configuration
from django.utils.module_loading import import_string

class Config(Configuration):
    ...
    REST_FRAMEWORK = {
        ...
        "DEFAULT_FILTER_BACKENDS": [
            import_string(item)
            for item in [
                "rest_framework.filters.SearchFilter",
                "rest_framework.filters.OrderingFilter",
                "django_filters.rest_framework.DjangoFilterBackend",
            ]
        ],
    }
    ...

This is of course undesirable, so let's not do that. Another attempt, with the above change reverted, changing the @action annotation instead. Unfortunately, no "OPTIONS" or "Filters" button show up with this:

@action(
    detail=False,
    methods=[HTTPMethod.GET],
    filter_backends=tuple(import_string(item) for item in settings.REST_FRAMEWORK.get("DEFAULT_FILTER_BACKENDS")),
)

I'm not sure what's going on, but it seems to me that something is wrong with the logic behind whether or not to show the "OPTIONS" and "Filters" buttons.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions