diff --git a/requirements.txt b/requirements.txt index bbfd95fdf..193a6d063 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,10 +1,9 @@ -Django==1.10.3 +Django==1.10.4 Pillow>=3.1.1 django-crispy-forms>=1.6.0 django-extensions>=1.6.1 -django-filter>=0.12.0,<1.0 +django-filter>=1.0 djangorestframework>=3.4.4 -djangorestframework-filters>=0.8.0 filemagic>=1.6 langdetect>=1.0.5 pyocr>=0.3.1 diff --git a/src/documents/filters.py b/src/documents/filters.py index a7c069d33..9519ec37b 100644 --- a/src/documents/filters.py +++ b/src/documents/filters.py @@ -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"], + } diff --git a/src/documents/views.py b/src/documents/views.py index d47ab8654..f271eed9d 100644 --- a/src/documents/views.py +++ b/src/documents/views.py @@ -1,23 +1,33 @@ from django.contrib.auth.mixins import LoginRequiredMixin from django.http import HttpResponse from django.views.decorators.csrf import csrf_exempt -from django.views.generic import FormView, DetailView, TemplateView - -from rest_framework import filters +from django.views.generic import DetailView, FormView, TemplateView +from django_filters.rest_framework import DjangoFilterBackend +from rest_framework.filters import SearchFilter, OrderingFilter +from paperless.db import GnuPG from rest_framework.mixins import ( - RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, ListModelMixin) + DestroyModelMixin, + ListModelMixin, + RetrieveModelMixin, + UpdateModelMixin +) from rest_framework.pagination import PageNumberPagination from rest_framework.permissions import IsAuthenticated from rest_framework.viewsets import ( - ModelViewSet, ReadOnlyModelViewSet, GenericViewSet) + GenericViewSet, + ModelViewSet, + ReadOnlyModelViewSet +) -from paperless.db import GnuPG - -from .filters import DocumentFilterSet, CorrespondentFilterSet, TagFilterSet +from .filters import CorrespondentFilterSet, DocumentFilterSet, TagFilterSet from .forms import UploadForm -from .models import Correspondent, Tag, Document, Log +from .models import Correspondent, Document, Log, Tag from .serialisers import ( - CorrespondentSerializer, TagSerializer, DocumentSerializer, LogSerializer) + CorrespondentSerializer, + DocumentSerializer, + LogSerializer, + TagSerializer +) class IndexView(TemplateView): @@ -94,7 +104,7 @@ class CorrespondentViewSet(ModelViewSet): serializer_class = CorrespondentSerializer pagination_class = StandardPagination permission_classes = (IsAuthenticated,) - filter_backends = (filters.DjangoFilterBackend, filters.OrderingFilter) + filter_backends = (DjangoFilterBackend, OrderingFilter) filter_class = CorrespondentFilterSet ordering_fields = ("name", "slug") @@ -105,7 +115,7 @@ class TagViewSet(ModelViewSet): serializer_class = TagSerializer pagination_class = StandardPagination permission_classes = (IsAuthenticated,) - filter_backends = (filters.DjangoFilterBackend, filters.OrderingFilter) + filter_backends = (DjangoFilterBackend, OrderingFilter) filter_class = TagFilterSet ordering_fields = ("name", "slug") @@ -120,11 +130,7 @@ class DocumentViewSet(RetrieveModelMixin, serializer_class = DocumentSerializer pagination_class = StandardPagination permission_classes = (IsAuthenticated,) - filter_backends = ( - filters.DjangoFilterBackend, - filters.SearchFilter, - filters.OrderingFilter - ) + filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter) filter_class = DocumentFilterSet search_fields = ("title", "correspondent__name", "content") ordering_fields = ( @@ -137,5 +143,5 @@ class LogViewSet(ReadOnlyModelViewSet): serializer_class = LogSerializer pagination_class = StandardPagination permission_classes = (IsAuthenticated,) - filter_backends = (filters.DjangoFilterBackend, filters.OrderingFilter) + filter_backends = (DjangoFilterBackend, OrderingFilter) ordering_fields = ("time",) diff --git a/src/paperless/settings.py b/src/paperless/settings.py index b343b3a17..0a43a6a61 100644 --- a/src/paperless/settings.py +++ b/src/paperless/settings.py @@ -36,7 +36,6 @@ if os.path.exists("/etc/paperless.conf"): load_dotenv("/etc/paperless.conf") - # Application definition INSTALLED_APPS = [