from django.db.models import Q from django_filters.rest_framework import BooleanFilter from django_filters.rest_framework import Filter from django_filters.rest_framework import FilterSet from .models import Correspondent from .models import Document from .models import DocumentType from .models import Log from .models import StoragePath from .models import Tag CHAR_KWARGS = ["istartswith", "iendswith", "icontains", "iexact"] ID_KWARGS = ["in", "exact"] INT_KWARGS = ["exact", "gt", "gte", "lt", "lte", "isnull"] DATE_KWARGS = ["year", "month", "day", "date__gt", "gt", "date__lt", "lt"] class CorrespondentFilterSet(FilterSet): class Meta: model = Correspondent fields = {"name": CHAR_KWARGS} class TagFilterSet(FilterSet): class Meta: model = Tag fields = {"name": CHAR_KWARGS} class DocumentTypeFilterSet(FilterSet): class Meta: model = DocumentType fields = {"name": CHAR_KWARGS} class TagsFilter(Filter): def __init__(self, exclude=False, in_list=False): super().__init__() self.exclude = exclude self.in_list = in_list def filter(self, qs, value): if not value: return qs try: tag_ids = [int(x) for x in value.split(",")] except ValueError: return qs if self.in_list: qs = qs.filter(tags__id__in=tag_ids).distinct() else: for tag_id in tag_ids: if self.exclude: qs = qs.exclude(tags__id=tag_id) else: qs = qs.filter(tags__id=tag_id) return qs class InboxFilter(Filter): def filter(self, qs, value): if value == "true": return qs.filter(tags__is_inbox_tag=True) elif value == "false": return qs.exclude(tags__is_inbox_tag=True) else: return qs class TitleContentFilter(Filter): def filter(self, qs, value): if value: return qs.filter(Q(title__icontains=value) | Q(content__icontains=value)) else: return qs class DocumentFilterSet(FilterSet): is_tagged = BooleanFilter( label="Is tagged", field_name="tags", lookup_expr="isnull", exclude=True, ) tags__id__all = TagsFilter() tags__id__none = TagsFilter(exclude=True) tags__id__in = TagsFilter(in_list=True) is_in_inbox = InboxFilter() title_content = TitleContentFilter() class Meta: model = Document fields = { "title": CHAR_KWARGS, "content": CHAR_KWARGS, "archive_serial_number": INT_KWARGS, "created": DATE_KWARGS, "added": DATE_KWARGS, "modified": DATE_KWARGS, "correspondent": ["isnull"], "correspondent__id": ID_KWARGS, "correspondent__name": CHAR_KWARGS, "tags__id": ID_KWARGS, "tags__name": CHAR_KWARGS, "document_type": ["isnull"], "document_type__id": ID_KWARGS, "document_type__name": CHAR_KWARGS, "storage_path": ["isnull"], "storage_path__id": ID_KWARGS, "storage_path__name": CHAR_KWARGS, } class LogFilterSet(FilterSet): class Meta: model = Log fields = {"level": INT_KWARGS, "created": DATE_KWARGS, "group": ID_KWARGS} class StoragePathFilterSet(FilterSet): class Meta: model = StoragePath fields = { "name": CHAR_KWARGS, "path": CHAR_KWARGS, }