Filter tag cloud based on search query
This commit is contained in:
parent
ff68d2591f
commit
e157bcd34f
|
@ -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,
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 %}
|
||||||
|
|
|
@ -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:]
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue