DjangoFilterBackend deprecation breaks mro · Issue #5089 · encode/django-rest-framework (original) (raw)

Checklist

Steps to reproduce

I ran into a really nasty bug today because of how we are using DjangoFilterBackend. Here is our scenario... we have a FilterBackend as well as a parent filter backend (that is really a mixin). Our backend extends our mixin as well as the rest_framework.filters.DjangoFilterBackend.... so it looks something like this

class NewDjangoFilterBackend:

def filter_queryset(self):
    print("Inside django-filters")

class DefaultDRFBackwardsCompat:

def __new__(*args, **kwargs):
    return NewDjangoFilterBackend()

class OurCustomerFilterBackendParent:

def filter_queryset(self):
    print("Inside Our Parent Object")

class OurFilterBackend(OurCustomerFilterBackendParent, DefaultDRFBackwardsCompat): pass

OurFilterBackend().filter_queryset()

Expected behavior

(this is in Python 3.4.6 btw)

I expect, because of Python's normal MRO that filter_queryset on OurCustomerFilterBackendParent will be called.

Actual behavior

Due to the __new__ in DefaultDRFBackwardsCompat the filter_queryset inside of django-filters is called instead.

It is not very clear to my why this would happen... but there has to be a way to deprecate a class without breaking Python's MRO.

In our case, the fix to our bug was to just use the DjangoFilterBackend from django-filters instead of the one in rest_framework... but this just seems like a potentially dangerous way to make something be backwards compatible.