There appears to be quite the mess out there with regard to how DRF
handles filtering.  DRF has its own built-in stuff, but recommends
django_filter for the advanced stuff, which has its own overriding
module that explodes with this message when used as per the
documentation:

  AttributeError: 'NoneType' object has no attribute 'DjangoFilterBackend'

Then there's djangorestframework-filter, another package that claims to
do the same thing, that does everything just differently enough that
nothing worked while I had it enabled.

I ended up using django_filter, but doing so importing each element
explicitly, rather than just using the recommended (and broken, at least
in this project) method of:

    import django_filter.restframework as fitlers

Anyway, this should bring the dependencies up to date, and strips out a
lot of redundant code.
This commit is contained in:
Daniel Quinn
2017-01-01 16:31:46 +00:00
parent 9ea39aeecb
commit 294b8abc3f
4 changed files with 66 additions and 156 deletions

View File

@@ -1,152 +1,58 @@
import django_filters
from django_filters.rest_framework import CharFilter, FilterSet
from rest_framework import filters
from .models import Document, Correspondent, Tag
#
# I hate how copy/pastey this file is. Recommendations are welcome.
#
from .models import Correspondent, Document, Tag
# Filters
class RelatedFilter(django_filters.MethodFilter):
def __init__(self, *args, **kwargs):
self.key = kwargs.pop("key")
self.lookup_type = kwargs.get("lookup_type")
django_filters.MethodFilter.__init__(self, *args, **kwargs)
def filter(self, qs, value):
if not value:
return qs
return qs.filter(**{"tags__{}".format(self.key): value})
# FilterSets
class SluggableFilterSet(filters.FilterSet):
name__startswith = django_filters.CharFilter(
name="name", lookup_type="startswith",
label="Name starts with (case sensitive)"
)
name__istartswith = django_filters.CharFilter(
name="name", lookup_type="istartswith",
label="Name starts with (case insensitive)"
)
name__endswith = django_filters.CharFilter(
name="name", lookup_type="endswith",
label="Name ends with (case sensitive)"
)
name__iendswith = django_filters.CharFilter(
name="name", lookup_type="endswith",
label="Name ends with (case insensitive)"
)
name__contains = django_filters.CharFilter(
name="name", lookup_type="contains",
label="Name contains (case sensitive)"
)
name__icontains = django_filters.CharFilter(
name="name", lookup_type="icontains",
label="Name contains (case insensitive)"
)
slug__istartswith = django_filters.CharFilter(
name="slug", lookup_type="istartswith",
label="Slug starts with (case insensitive)"
)
slug__iendswith = django_filters.CharFilter(
name="slug", lookup_type="endswith",
label="Slug ends with (case insensitive)"
)
slug__icontains = django_filters.CharFilter(
name="slug", lookup_type="icontains",
label="Slug contains (case insensitive)"
)
class CorrespondentFilterSet(SluggableFilterSet):
class CorrespondentFilterSet(FilterSet):
class Meta(object):
model = Correspondent
fields = ["name"]
fields = {
'name': [
"startswith", "endswith", "contains",
"istartswith", "iendswith", "icontains"
],
"slug": ["istartswith", "iendswith", "icontains"]
}
class TagFilterSet(SluggableFilterSet):
class TagFilterSet(FilterSet):
class Meta(object):
model = Tag
fields = ["name", "slug"]
fields = {
'name': [
"startswith", "endswith", "contains",
"istartswith", "iendswith", "icontains"
],
"slug": ["istartswith", "iendswith", "icontains"]
}
class DocumentFilterSet(filters.FilterSet):
class DocumentFilterSet(FilterSet):
title__startswith = django_filters.CharFilter(
name="title", lookup_type="startswith",
label="Title starts with (case sensitive)"
)
title__istartswith = django_filters.CharFilter(
name="title", lookup_type="istartswith",
label="Title starts with (case insensitive)"
)
title__endswith = django_filters.CharFilter(
name="title", lookup_type="endswith",
label="Title ends with (case sensitive)"
)
title__iendswith = django_filters.CharFilter(
name="title", lookup_type="endswith",
label="Title ends with (case insensitive)"
)
title__contains = django_filters.CharFilter(
name="title", lookup_type="contains",
label="Title contains (case sensitive)"
)
title__icontains = django_filters.CharFilter(
name="title", lookup_type="icontains",
label="Title contains (case insensitive)"
)
CHAR_KWARGS = {
"lookup_expr": (
"startswith",
"endswith",
"contains",
"istartswith",
"iendswith",
"icontains"
)
}
content__contains = django_filters.CharFilter(
name="content", lookup_type="contains")
content__icontains = django_filters.CharFilter(
name="content", lookup_type="icontains")
tags__name = RelatedFilter(key="name")
tags__name__startswith = RelatedFilter(key="name__startswith")
tags__name__istartswith = RelatedFilter(key="name__istartswith")
tags__name__endswith = RelatedFilter(key="name__endswith")
tags__name__iendswith = RelatedFilter(key="name__iendswith")
tags__name__contains = RelatedFilter(key="name__contains")
tags__name__icontains = RelatedFilter(key="name__icontains")
tags__slug = RelatedFilter(key="slug")
tags__slug__startswith = RelatedFilter(key="slug__startswith")
tags__slug__istartswith = RelatedFilter(key="slug__istartswith")
tags__slug__endswith = RelatedFilter(key="slug__endswith")
tags__slug__iendswith = RelatedFilter(key="slug__iendswith")
tags__slug__contains = RelatedFilter(key="slug__contains")
tags__slug__icontains = RelatedFilter(key="slug__icontains")
correspondent__name = RelatedFilter(key="name")
correspondent__name__startswith = RelatedFilter(key="name__startswith")
correspondent__name__istartswith = RelatedFilter(key="name__istartswith")
correspondent__name__endswith = RelatedFilter(key="name__endswith")
correspondent__name__iendswith = RelatedFilter(key="name__iendswith")
correspondent__name__contains = RelatedFilter(key="name__contains")
correspondent__name__icontains = RelatedFilter(key="name__icontains")
correspondent__slug = RelatedFilter(key="slug")
correspondent__slug__startswith = RelatedFilter(key="slug__startswith")
correspondent__slug__istartswith = RelatedFilter(key="slug__istartswith")
correspondent__slug__endswith = RelatedFilter(key="slug__endswith")
correspondent__slug__iendswith = RelatedFilter(key="slug__iendswith")
correspondent__slug__contains = RelatedFilter(key="slug__contains")
correspondent__slug__icontains = RelatedFilter(key="slug__icontains")
correspondent__name = CharFilter(name="correspondent__name", **CHAR_KWARGS)
correspondent__slug = CharFilter(name="correspondent__slug", **CHAR_KWARGS)
tags__name = CharFilter(name="tags__name", **CHAR_KWARGS)
tags__slug = CharFilter(name="tags__slug", **CHAR_KWARGS)
class Meta(object):
model = Document
fields = ["title"]
fields = {
"title": [
"startswith", "endswith", "contains",
"istartswith", "iendswith", "icontains"
],
"content": ["contains", "icontains"],
}