Skip to content

Commit

Permalink
Annotation filters
Browse files Browse the repository at this point in the history
  • Loading branch information
stevelacey committed Nov 8, 2021
1 parent a17515b commit fd20417
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 4 deletions.
44 changes: 41 additions & 3 deletions worf/filters.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,53 @@
from urllib.parse import urlencode

from django.db.models.fields.related import ForeignObjectRel, RelatedField
from django.http import QueryDict

from url_filter.filtersets import ModelFilterSet
from url_filter.exceptions import SkipFilter


def generate_filterset(model):
class AnnotatedModelFilterSet(ModelFilterSet):
def get_filters(self):
filters = super().get_filters()

if self.queryset is not None:
state = self._build_state()

for name in self.queryset.query.annotations.keys():
if name in self.Meta.exclude or name in filters:
continue

try:
annotation_filter = self._build_annotation_filter(name, state)
except SkipFilter:
continue

if annotation_filter is not None:
filters[name] = annotation_filter

return filters

def _build_annotation_filter(self, name, state):
field = self.queryset.query.annotations.get(name).output_field

if isinstance(field, RelatedField):
if not self.Meta.allow_related:
raise SkipFilter
return self._build_filterset_from_related_field(name, field)
elif isinstance(field, ForeignObjectRel):
if not self.Meta.allow_related_reverse:
raise SkipFilter
return self._build_filterset_from_reverse_field(name, field)

return self._build_filter_from_field(name, field)


def generate_filterset(model, queryset):
return type(
f"{model.__name__}FilterSet",
(ModelFilterSet,),
dict(Meta=type("Meta", (), dict(model=model))),
(AnnotatedModelFilterSet,),
dict(Meta=type("Meta", (), dict(model=model, queryset=queryset))),
)


Expand Down
2 changes: 1 addition & 1 deletion worf/views/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def __init__(self, *args, **kwargs):

# generate a default filterset if a custom one was not provided
if self.filter_set is None:
self.filter_set = generate_filterset(self.model)
self.filter_set = generate_filterset(self.model, self.queryset)

# support deprecated search_fields and/or dict syntax (note that `and` does nothing)
if isinstance(self.search_fields, dict):
Expand Down

0 comments on commit fd20417

Please sign in to comment.