Filter tag cloud based on search query

This commit is contained in:
Sascha Ißbrücker 2019-06-30 21:15:02 +02:00
parent ff68d2591f
commit e157bcd34f
5 changed files with 74 additions and 19 deletions

View File

@ -1,7 +1,7 @@
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.db.models import Q, Count, Aggregate, CharField from django.db.models import Q, Count, Aggregate, CharField
from bookmarks.models import Bookmark from bookmarks.models import Bookmark, Tag
class Concat(Aggregate): class Concat(Aggregate):
@ -22,22 +22,14 @@ def query_bookmarks(user: User, query_string: str):
.annotate(tag_count=Count('tags'), .annotate(tag_count=Count('tags'),
tag_string=Concat('tags__name')) tag_string=Concat('tags__name'))
# Sanitize query params
if not query_string:
query_string = ''
# Filter for user # Filter for user
query_set = query_set.filter(owner=user) query_set = query_set.filter(owner=user)
# Split query into search terms and tags # Split query into search terms and tags
keywords = query_string.strip().split(' ') query = _parse_query_string(query_string)
keywords = [word for word in keywords if word]
search_terms = [word for word in keywords if word[0] != '#']
tag_names = [word[1:] for word in keywords if word[0] == '#']
# Filter for search terms and tags # Filter for search terms and tags
for term in search_terms: for term in query['search_terms']:
query_set = query_set.filter( query_set = query_set.filter(
Q(title__contains=term) Q(title__contains=term)
| Q(description__contains=term) | Q(description__contains=term)
@ -45,7 +37,7 @@ def query_bookmarks(user: User, query_string: str):
| Q(website_description__contains=term) | Q(website_description__contains=term)
) )
for tag_name in tag_names: for tag_name in query['tag_names']:
query_set = query_set.filter( query_set = query_set.filter(
tags__name=tag_name tags__name=tag_name
) )
@ -54,3 +46,47 @@ def query_bookmarks(user: User, query_string: str):
query_set = query_set.order_by('-date_modified') query_set = query_set.order_by('-date_modified')
return query_set return query_set
def query_tags(user: User, query_string: str):
query_set = Tag.objects;
# Filter for user
query_set = query_set.filter(owner=user)
# Split query into search terms and tags
query = _parse_query_string(query_string)
# Filter for search terms and tags
for term in query['search_terms']:
query_set = query_set.filter(
Q(bookmark__title__contains=term)
| Q(bookmark__description__contains=term)
| Q(bookmark__website_title__contains=term)
| Q(bookmark__website_description__contains=term)
)
for tag_name in query['tag_names']:
query_set = query_set.filter(
bookmark__tags__name=tag_name
)
return query_set.distinct()
def _parse_query_string(query_string):
# Sanitize query params
if not query_string:
query_string = ''
# Split query into search terms and tags
keywords = query_string.strip().split(' ')
keywords = [word for word in keywords if word]
search_terms = [word for word in keywords if word[0] != '#']
tag_names = [word[1:] for word in keywords if word[0] == '#']
return {
'search_terms': search_terms,
'tag_names': tag_names,
}

View File

@ -43,7 +43,7 @@ ul.bookmark-list {
margin-bottom: 0.4rem; margin-bottom: 0.4rem;
} }
.group-label { .highlight-char {
font-weight: bold; font-weight: bold;
text-transform: uppercase; text-transform: uppercase;
color: $alternative-color-dark; color: $alternative-color-dark;

View File

@ -3,11 +3,20 @@
<div class="tag-cloud"> <div class="tag-cloud">
{% for group in groups %} {% for group in groups %}
<p class="group"> <p class="group">
<span class="group-label mr-2">{{ group.char }}</span>
{% for tag in group.tags %} {% for tag in group.tags %}
<a href="?{% append_query_param q=tag.name|hash_tag %}"> {# Highlight first char of first tag in group #}
<span class="mr-2">{{ tag.name }}</span> {% if forloop.counter == 1 %}
</a> <a href="?{% append_query_param q=tag.name|hash_tag %}"
class="mr-2">
<span class="highlight-char">{{ tag.name|first_char }}</span><span>{{ tag.name|remaining_chars:1 }}</span>
</a>
{% else %}
{# Render remaining tags normally #}
<a href="?{% append_query_param q=tag.name|hash_tag %}"
class="mr-2">
<span>{{ tag.name }}</span>
</a>
{% endif %}
{% endfor %} {% endfor %}
</p> </p>
{% endfor %} {% endfor %}

View File

@ -33,3 +33,13 @@ def append_query_param(context, **kwargs):
@register.filter(name='hash_tag') @register.filter(name='hash_tag')
def hash_tag(tag_name): def hash_tag(tag_name):
return '#' + tag_name return '#' + tag_name
@register.filter(name='first_char')
def first_char(text):
return text[0]
@register.filter(name='remaining_chars')
def remaining_chars(text, index):
return text[index:]

View File

@ -4,7 +4,7 @@ from django.shortcuts import render
from django.urls import reverse from django.urls import reverse
from bookmarks import queries from bookmarks import queries
from bookmarks.models import Bookmark, BookmarkForm, Tag from bookmarks.models import Bookmark, BookmarkForm
from bookmarks.services.bookmarks import create_bookmark, update_bookmark from bookmarks.services.bookmarks import create_bookmark, update_bookmark
_default_page_size = 30 _default_page_size = 30
@ -16,7 +16,7 @@ def index(request):
query_set = queries.query_bookmarks(request.user, query_string) query_set = queries.query_bookmarks(request.user, query_string)
paginator = Paginator(query_set, _default_page_size) paginator = Paginator(query_set, _default_page_size)
bookmarks = paginator.get_page(page) bookmarks = paginator.get_page(page)
tags = Tag.objects.all() tags = queries.query_tags(request.user, query_string)
if request.GET.get('tag'): if request.GET.get('tag'):
mod = request.GET.copy() mod = request.GET.copy()