Repository: dotkom/onlineweb4

Issue:
Add API-filter to match one of the supplied article tags
<!-- If this is a security issue or information leakage (having access to something you (probably) shouldn't), please send an email rather than opening a public issue. -->

## What kind of an issue is this?

- Feature request


## What is the wanted behaviour?

Add an API-filter, so that you can get a list or articles containing at least ONE of the provided article tags

As wanted from https://github.com/dotkom/onlineweb-frontend/pull/222#discussion_r275752633

## What is the current behaviour?

If you send multiple tags to the api, it filters so the articles have to include **all** the tags supplied

Example of current behaviour: https://online.ntnu.no/api/v1/articles/?tags=%C3%B8konomi&tags=fondstyret




Discussion:

Resolving patch:
diff --git a/apps/article/filters.py b/apps/article/filters.py
new file mode 100644
--- /dev/null
+++ b/apps/article/filters.py
@@ -0,0 +1,19 @@
+import django_filters
+from watson import search as watson_search
+
+
+class CharInFilter(django_filters.BaseInFilter, django_filters.CharFilter):
+    pass
+
+
+class ArticlesFilter(django_filters.FilterSet):
+    year = django_filters.NumberFilter(field_name='published_date', lookup_expr='year')
+    month = django_filters.NumberFilter(field_name='published_date', lookup_expr='month')
+    tags = django_filters.CharFilter(field_name='tags__name')
+    tags_in = CharInFilter(field_name='tags__name', lookup_expr='in')
+    query = django_filters.CharFilter(method='watson_filter')
+
+    def watson_filter(self, queryset, name, value):
+        if value and value != '':
+            queryset = watson_search.filter(queryset, value)
+        return queryset
diff --git a/apps/article/views.py b/apps/article/views.py
--- a/apps/article/views.py
+++ b/apps/article/views.py
@@ -3,14 +3,13 @@
 from collections import Counter
 
 from django.contrib.contenttypes.models import ContentType
-from django.db.models import Q
 from django.shortcuts import get_object_or_404, render
 from django.utils import timezone
 from rest_framework import mixins, viewsets
 from rest_framework.permissions import AllowAny
 from taggit.models import TaggedItem
-from watson import search as watson
 
+from apps.article.filters import ArticlesFilter
 from apps.article.models import Article
 from apps.article.serializers import ArticleSerializer
 from apps.article.utils import create_article_filters
@@ -79,37 +78,10 @@ class ArticleViewSet(viewsets.GenericViewSet, mixins.RetrieveModelMixin, mixins.
     Filtering on tags is only supported if the tags are supplied exactly as the stored tags.
     """
 
-    queryset = Article.objects.filter(published_date__lte=timezone.now()).order_by('-published_date')
+    queryset = Article.objects.filter()
     serializer_class = ArticleSerializer
     permission_classes = (AllowAny,)
+    filterset_class = ArticlesFilter
 
     def get_queryset(self):
-        """Manually filtering the qs. @ToDo: Make this use internal REST framework functions."""
-        queryset = Article.objects.filter(published_date__lte=timezone.now()).order_by('-published_date')
-        month = self.request.query_params.get('month', None)
-        year = self.request.query_params.get('year', None)
-        tags = self.request.query_params.get('tags', None)
-        query = self.request.query_params.get('query', None)
-
-        if tags:
-            queryset = queryset.filter(Q(tags__name__in=[tags]) | Q(tags__slug__in=[tags]))
-
-        if year:
-            if month:
-                # Filtering on year and month
-                queryset = queryset.filter(
-                    published_date__year=year,
-                    published_date__month=month,
-                    published_date__lte=timezone.now()
-                ).order_by('-published_date')
-            else:
-                # Filtering only on year
-                queryset = queryset.filter(
-                    published_date__year=year,
-                    published_date__lte=timezone.now()
-                ).order_by('-published_date')
-
-        if query and query != '':
-            queryset = watson.filter(queryset, query)
-
-        return queryset
+        return super().get_queryset().filter(published_date__lte=timezone.now()).order_by('-published_date')


Test patch: