philipn/django-rest-framework-filters

[resolved] typo in application code

mosesmc52 opened this issue · 19 comments

Th django-rest-framework-filters is not not working with my install of Django v.2.2.4. I have djangorestframework-filters v 1.0.0.dev0 installed, python v. 3.7.4 . I believe I have everything installed as described in the instructions. I'm not sure this makes a difference, within the view I'm using the filter_class within generics.ListAPIView. What steps can I take to troubleshoot this issue?

I'm testing using the Django Rest Framework UI.

Thanks,

Moses

Hi @mosesmc52. There isn't enough information to debug this. What do you mean by "not working"? Do you get an exception, or does nothing seem to happen?

Are you using the correct backend?
'rest_framework_filters.backends.RestFrameworkFilterBackend'

Yes, I'm using the correct backend.

Here is the sample of my filter:

class ApplicationFilter(filters.FilterSet):

    class Meta:
        models = models.Application
        fields = {
            'title': '__all__',
        }

class ApplicationList(generics.ListAPIView):
    queryset = dealer_models.Application.objects.all()
    serializer_class = dealer_serializers.ApplicationSeializer
    filter_class = application_filters.ApplicationFilter

What exactly isn't working? Do you get an exception, or are the query results not filtered? All I can give you is generic debugging advice.

  • What is the querystring that isn't working? It's possible that it's just invalid.
  • Log the database queries. Does the application query have a where clause for the title field?
  • If you're familiar with a debugger, then use that to walk though the code as it's executed.
  • If not, you can use simple print statements to help figure out what's going on. e.g.,
class ApplicationFilter(filters.FilterSet):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        print('*' * 80)
        print('ApplicationFilter init')

    class Meta:
        models = models.Application
        fields = {'title': '__all__'}

If you don't see ApplicationFilter init in your dev server logs, then that would indicate that your application filter isn't being ran.

I copied the init method into my Application filter with the print statments. I used the pdb debugger and saw the input kwargs params being passed within the title field. I don't think the filter is working. I inserted a random string expecting nothing to be returned. However, I saw a few application objects being returned. I'm going to try to figure out to log the database query. Unless you know of any other ways I can troubleshoot.

Thanks for your help

What is the querystring you are using?

Here is my query running on localhost.

http://localhost:8000/api/applications/?title=abc

Okay - so there shouldn't be any issue with the query params, and you saw that they were passed to the filterset, so that's encouraging. Next step would be to see what SQL queries are being executed. Try this:

import sqlparse

def print_sql(qs):
    query = str(qs.query)
    print(sqlparse.format(query, reindent=True, keyword_case='upper')) 

class ApplicationFilter(filters.FilterSet):
    class Meta:
        models = models.Application
        fields = {'title': '__all__'}

    def filter_queryset(self, queryset):
        queryset = super().filter_queryset(queryset)
        print_sql(queryset)
        return queryset

You might also want to take a look at https://stackoverflow.com/q/4375784/1103124

Ok, here is what was returned from the print_sql output in my console after executing the same query. Note, the application model is actually called DealerApplication.

Screen Shot 2019-09-04 at 1 08 58 PM

Can you show the full query? There should be more after from the FROM line.

This is all I see.

Screen Shot 2019-09-04 at 1 17 57 PM

Okay, so your filter is called, it's passed data etc, but no query is produced.. try:

class ApplicationFilter(filters.FilterSet):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        print('*' * 80)
        print('Data:')
        for k, v in self.data.items():
            print(f'{k}: {v}')

        print('Base filters:')
        for name, f in self.base_filters.items():
            print(f'{name}: {type(f)}')

        print('Request filters:')
        for name, f in self.filters.items():
            print(f'{name}: {type(f)}')

Here is the response

Screen Shot 2019-09-04 at 1 35 40 PM

ah - meant to inspect the base_filters on the class, not the instance. Try this instead:

class ApplicationFilter(filters.FilterSet):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        print('*' * 80)
        print('Base filters:')
        for name, f in type(self).base_filters.items():
            print(f'{name}: {type(f)}')

Here is the response

Screen Shot 2019-09-04 at 2 09 44 PM

hm - that doesn't make sense. Your filterset class should have an unmodified set of base_filters. What happens if you just import the class in the shell and print the filters?

import ApplicationFilter
print(ApplicationFilter.base_filters)

Here is what I ran in my Django shell console window

Screen Shot 2019-09-04 at 2 36 17 PM

Oh wow - just figured it out. There's a typo in the filterset.

class ApplicationFilter(filters.FilterSet):

    class Meta:
        # this is incorrect
        models = models.Application
        # should be...
        model = models.Application
        fields = {
            'title': '__all__',
        }

Fix that and Meta.fields should generate your title filters.

It worked!!!

Thank you again.