encode / django-rest-framework

Web APIs for Django. 🎸
https://www.django-rest-framework.org
Other
28.11k stars 6.8k forks source link

django rest filter working but browsable api not showing filter forms #4689

Closed atkawa7 closed 7 years ago

atkawa7 commented 7 years ago

django rest filter working but browsable api not showing filter forms. Here is my code


class StatsFilter(rest_framework.FilterSet):
    max_date = django_filters.DateFilter(
        name="date", lookup_expr='lte')
    min_date = django_filters.DateFilter(
        name="date", lookup_expr='gte')

    class Meta:
        model = Stats
        fields = ('__all__')

from django_filters import rest_framework

from .filters import StatsFilter
from .serializers import StatsSerializer
from .pagination import CustomResultsPagination
from .models import Stats

class StatsListView(generics.ListAPIView):
    serializer_class = StatsSerializer
    queryset = Stats.objects.all()
    pagination_class = CustomResultsPagination
    filter_backends = (rest_framework.DjangoFilterBackend,
                       filters.OrderingFilter,)
    filter_class = StatsFilter
    ordering_fields = (
        'title', 'plays', 'unique', 'date', 'total_time',
    )
    ordering = ('-date')

I have django crispy forms installed as well

xordoquy commented 7 years ago

Hi,

The discussion group is the best place to take this discussion and other usage questions. Thanks!

wonderbeyond commented 7 years ago

@xordoquy Isn't this a real issue? I have been facing the same problem, from v3.5.4 to v3.6.2.

One similarity of our use cases is that rest_framework.filters.DjangoFilterBackend and rest_framework.filters.OrderingFilter is used together.

The browsable api interface only shows ordering selections, without filtering forms!

class DrugEventListView(ListAPIView):
    permission_classes = (permissions.IsAuthenticated,)
    queryset = DrugEvent.objects.all()
    serializer_class = DrugEventSerializer
    filter_class = DrugEventFilter
    filter_backends = (OrderingFilter, DjangoFilterBackend)
    ordering_fields = ('date',)
tomchristie commented 7 years ago

@wonderbeyond Not impossible that there's an actual issue here. Something like before and after screenshots might help highlight if there's something we need to look into further or not.

xordoquy commented 7 years ago

I tested it (against latest stable) and it works both with ordering and filtering. You may want to narrow the issue to a simple test case in order to make sure it's not some sort of side effect of another piece of code.

wonderbeyond commented 7 years ago

I tried again, the found a more specific behavior.

This case I only used DjangoFilterBackend, without OrderingFilter, But still set view.filter_backends explicitly, Then the similar issue arose, I just cant see the Filters button.

(I've set DEFAULT_FILTER_BACKENDS to be DjangoFilterBackend in settings. So I normally dont set view.filter_backends)

Code+Screenshot without issue

class ListRetrieveDrugViewSet(viewsets.ReadOnlyModelViewSet):
    permission_classes = (permissions.DjangoModelPermissions,)
    queryset = Drug.objects.all()
    # filter_backends = (DjangoFilterBackend,)
    filter_class = DrugFilter

image

Code+Screenshot with issue

class ListRetrieveDrugViewSet(viewsets.ReadOnlyModelViewSet):
    permission_classes = (permissions.DjangoModelPermissions,)
    queryset = Drug.objects.all()
    filter_backends = (DjangoFilterBackend,)
    filter_class = DrugFilter

image

tomchristie commented 7 years ago

Thanks! Let's reopen this for further investigation.

xordoquy commented 7 years ago

@wonderbeyond are you sure you have django crispy forms installed ?

tomchristie commented 7 years ago

Ah, on second thoughts...

I tested it (against latest stable) and it works both with ordering and filtering

Okay, so would be happy to re-open this, but a test case or simplest possible instructions to replicate would be needed first. Thanks @xordoquy!

xordoquy commented 7 years ago

For the record, here's what has been tested working with Django 1.11, DRF 3.6.2 and django filter 1.0.2:

class CompanyFilter(filters.FilterSet):
    class Meta:
        model = models.Company
        fields = ['name', 'siret']

class Company(viewsets.ModelViewSet):
    queryset = models.Company.objects.all()
    serializer_class = serializers.Company
    filter_backends = [DjangoFilterBackend]
    filter_class = CompanyFilter
wonderbeyond commented 7 years ago

@xordoquy Yes, I have crispy installed, but I have removed it from installed apps during latest test.

I'll try a minimal demo for reproducing tomorrow...

wonderbeyond commented 7 years ago

@xordoquy Hi, I've done my minimal demo project for reproducing this issue, without any magic. https://github.com/wonderbeyond/drf-issue4689

xordoquy commented 7 years ago

views.py:

from rest_framework.filters import DjangoFilterBackend

vs:

'DEFAULT_FILTER_BACKENDS': (
    'django_filters.rest_framework.DjangoFilterBackend',
),

I don't think we'll fix the rest_framework.filters.DjangoFilterBackend though.

xordoquy commented 7 years ago

@wonderbeyond thank you a lot for the work on this. The issue comes from the rest_framework.filters.DjangoFilterBackend that doesn't show the filter box while django_filters.rest_framework.DjangoFilterBackend does (even when defined in the view itself).

wonderbeyond commented 7 years ago

@xordoquy That's really a big confusion. rest_framework.filters.DjangoFilterBackend does its work but not show the filtering ui. I even didn't notice the two different filter classes when involved into this issue.

xordoquy commented 7 years ago

Yup, that wasn't obvious. I'll also make a pass on the documentation to remove some misleading code examples. Most are correct but not all.

carltongibson commented 7 years ago

This comes up because of the original django_filters.FilterSet is not optimised for DRF — it's designed for (vanilla) view usage.

The newer django_filters.rest_framework.FilterSet — which is used by the newer django_filters.rest_framework.DjangoFilterBackend has several optimisations for API usage.

The naming confusion is unfortunate but just a consequence of migrating the filtering code to Django Filter.

It's worth reviewing the Django Filter Docs on Integration with DRF here.

carltongibson commented 7 years ago

Searching the project, the string rest_framework.filters.DjangoFilterBackend occurs just once:

        warnings.warn(
            "The built in 'rest_framework.filters.DjangoFilterBackend' is deprecated. "
            "You should use 'django_filters.rest_framework.DjangoFilterBackend' instead.",
            DeprecationWarning
        )

The docs examples have all been updated.

xordoquy commented 7 years ago

This was ambiguous: 6831472a6237eaf8f513f0af333da86760ef7871

tuanluu-agilityio commented 5 years ago

For the record, here's what has been tested working with Django 1.11, DRF 3.6.2 and django filter 1.0.2:

class CompanyFilter(filters.FilterSet):
    class Meta:
        model = models.Company
        fields = ['name', 'siret']

class Company(viewsets.ModelViewSet):
    queryset = models.Company.objects.all()
    serializer_class = serializers.Company
    filter_backends = [DjangoFilterBackend]
    filter_class = CompanyFilter

I'm missing filter_class so it doesn't show Filter feature. And you also using filterset_fields below:

class ProductList(generics.ListAPIView):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    filter_backends = (DjangoFilterBackend,)
    filterset_fields = ('category', 'in_stock')

Refer docs

Now it's work fine for me on environment:

python_version="3.6"
django="2.1"

Thanks @xordoquy ,

olitomas commented 1 year ago

For anyone still experiencing this.

"filter_fields" has been depricated.

You have to change it to "filterset_fields" like @xordoquy is doing in his example 😊