-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(searching): Add Search Functionality and Custom filtering based …
…on parameters - Enable user to filter articles basing on author, title and tag name [Finishes #159952016]
- Loading branch information
1 parent
e6d51e7
commit 01667cc
Showing
7 changed files
with
219 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
""" | ||
Define extra methods to handle extra work for | ||
making search functionality | ||
""" | ||
|
||
|
||
def get_response(attrs): | ||
""" | ||
:param attrs: | ||
:return: | ||
""" | ||
all_fields, author_and_tag, author_and_title, author_only, queryset, tag_only, \ | ||
title_and_tag, title_only, author_query, title_query, tag_query = attrs | ||
|
||
boolean_mapping = { | ||
"all_fields": all_fields, | ||
"author_and_tag": author_and_tag, | ||
"author_and_title": author_and_title, | ||
"title_and_tag": title_and_tag, | ||
"author_only": author_only, | ||
"title_only": title_only, | ||
"tag_only": tag_only, | ||
} | ||
function_mapping = { | ||
"all_fields": lambda: queryset.filter(author_query & title_query & tag_query), | ||
"author_and_tag": lambda: queryset.filter(author_query & tag_query), | ||
"author_and_title": lambda: queryset.filter(author_query & title_query), | ||
"title_and_tag": lambda: queryset.filter(title_query & tag_query), | ||
"author_only": lambda: queryset.filter(author_query), | ||
"title_only": lambda: queryset.filter(title_query), | ||
"tag_only": lambda: queryset.filter(tag_query), | ||
} | ||
for key, val in boolean_mapping.items(): | ||
if val: | ||
return function_mapping.get(key)() | ||
return queryset.all() | ||
|
||
|
||
def extra_vars(all_fields, author, tag, title): | ||
""" | ||
:param all_fields: | ||
:param author: | ||
:param tag: | ||
:param title: | ||
:return: | ||
""" | ||
title_and_tag = (title and tag and not author) | ||
author_only = (author and not all_fields) | ||
title_only = (title and not author and not tag) | ||
tag_only = (tag and not title and not author) | ||
|
||
return author_only, tag_only, title_and_tag, title_only |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
""" | ||
Implements article search and filter | ||
""" | ||
from urllib.parse import unquote | ||
|
||
from django.db import models | ||
from django.db.models import Q | ||
|
||
from authors.apps.articles.filter_search_extras import extra_vars, get_response | ||
|
||
|
||
class ArticleManager(models.Manager): | ||
""" | ||
define custom manager for articles | ||
""" | ||
|
||
def search(self, params): | ||
""" | ||
customised search functionality | ||
""" | ||
author = unquote(params.get("author", "")) | ||
title = unquote(params.get("title", "")) | ||
tag = unquote(params.get("tag", "")) | ||
|
||
author_query = (Q(author__username__icontains=author) | Q(author__email__exact=author)) | ||
tag_query = Q(tags__tag_name__exact=tag) | ||
title_query = Q(title__icontains=title) | ||
|
||
all_fields = (author and title and tag) | ||
author_and_title = (author and title and not tag) | ||
author_and_tag = (author and tag and not title) | ||
author_only, tag_only, title_and_tag, title_only = extra_vars(all_fields, author, tag, title) | ||
|
||
queryset = self.get_queryset() | ||
|
||
attrs = (all_fields, author_and_tag, author_and_title, author_only, queryset, tag_only, | ||
title_and_tag, title_only, author_query, title_query, tag_query) | ||
|
||
return get_response(attrs) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
""" | ||
tests for search filters | ||
""" | ||
import json | ||
from urllib.parse import quote | ||
|
||
from django.test import TestCase | ||
from rest_framework import status | ||
from rest_framework.test import APIClient | ||
|
||
from authors.apps.articles.models import Article | ||
from authors.apps.articles.tests.test_data import TestData | ||
from authors.apps.authentication.models import User | ||
|
||
|
||
class Tests(TestCase, TestData): | ||
|
||
def setUp(self): | ||
""" | ||
setup tests | ||
""" | ||
User.objects.all().delete() | ||
Article.objects.all().delete() | ||
|
||
self.login_data = {"user": {"email": self.user_email, "password": self.password, | ||
} | ||
} | ||
self.user_data = {"user": {"username": self.user_name, "email": self.user_email, | ||
"password": self.password, | ||
} | ||
} | ||
self.client = APIClient() | ||
|
||
self.response = self.client.post( | ||
"/api/users/", | ||
self.user_data, | ||
format="json") | ||
self.user = User.objects.get(email=self.user_email) | ||
self.user.is_active = True | ||
self.user.is_email_verified = True | ||
self.user.save() | ||
self.response = self.client.post( | ||
"/api/users/login/", | ||
self.login_data, | ||
format="json") | ||
self.assertEqual(status.HTTP_200_OK, self.response.status_code) | ||
self.assertIn('token', self.response.data) | ||
token = self.response.data.get("token", None) | ||
self.client.credentials(HTTP_AUTHORIZATION="Token {0}".format(token)) | ||
|
||
def test_searching_with_all_params(self): | ||
val = 0 | ||
while val < 10: | ||
response = self.client.post( | ||
"/api/articles/", data=json.dumps( | ||
self.post_article_tags), content_type='application/json') | ||
self.assertEqual(201, response.status_code) | ||
self.assertIn('article', response.json()) | ||
self.assertIsInstance(response.json().get("article"), dict) | ||
val += 1 | ||
|
||
response = self.client.get( | ||
"/api/articles/?author=iroq", content_type='application/json') | ||
self.assertEqual(response.status_code, 200) | ||
self.assertIn('articles', response.json()) | ||
self.assertIn('results', response.json().get("articles")) | ||
|
||
response = self.client.get( | ||
"/api/articles/?author=iroq&title={0}&tag=python".format(quote('Yet another Sand Blogs')), | ||
content_type='application/json') | ||
self.assertEqual(response.status_code, 200) | ||
self.assertIn('article', response.json()) | ||
|
||
response = self.client.get( | ||
"/api/articles/?author=iroq&title={0}&tag=python".format(quote('Yet another Sand Blogs')), | ||
content_type='application/json') | ||
self.assertEqual(response.status_code, 200) | ||
self.assertIn('article', response.json()) | ||
|
||
response = self.client.get( | ||
"/api/articles/?author=iroq&tag=python", | ||
content_type='application/json') | ||
self.assertEqual(response.status_code, 200) | ||
self.assertIn('articles', response.json()) | ||
|
||
response = self.client.get( | ||
"/api/articles/?title={0}&tag=python".format(quote('Yet another Sand Blogs')), | ||
content_type='application/json') | ||
self.assertEqual(response.status_code, 200) | ||
self.assertIn('article', response.json()) | ||
|
||
response = self.client.get( | ||
"/api/articles/?title={0}&author=iroq".format(quote('Yet another Sand Blogs')), | ||
content_type='application/json') | ||
self.assertEqual(response.status_code, 200) | ||
self.assertIn('article', response.json()) | ||
|
||
response = self.client.get( | ||
"/api/articles/?author=iroq".format(quote('Yet another Sand Blogs')), | ||
content_type='application/json') | ||
self.assertEqual(response.status_code, 200) | ||
self.assertIn('articles', response.json()) | ||
|
||
response = self.client.get( | ||
"/api/articles/?title={0}".format(quote('Yet another Sand Blog')), | ||
content_type='application/json') | ||
self.assertEqual(response.status_code, 200) | ||
self.assertIn('articles', response.json()) | ||
|
||
response = self.client.get( | ||
"/api/articles/?tag=python".format(quote('Yet another Sand Blogs')), | ||
content_type='application/json') | ||
self.assertEqual(response.status_code, 200) | ||
self.assertIn('articles', response.json()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters