linkding/bookmarks/queries.py

94 lines
2.7 KiB
Python
Raw Normal View History

2019-06-29 10:53:37 +00:00
from django.contrib.auth.models import User
from django.db.models import Q, Count, Aggregate, CharField, Value, BooleanField
2019-06-29 10:53:37 +00:00
2019-06-30 19:15:02 +00:00
from bookmarks.models import Bookmark, Tag
2019-06-29 10:53:37 +00:00
2019-06-30 05:15:46 +00:00
class Concat(Aggregate):
function = 'GROUP_CONCAT'
template = '%(function)s(%(distinct)s%(expressions)s)'
def __init__(self, expression, distinct=False, **extra):
super(Concat, self).__init__(
expression,
distinct='DISTINCT ' if distinct else '',
output_field=CharField(),
**extra)
2019-06-29 10:53:37 +00:00
def query_bookmarks(user: User, query_string: str):
2019-06-30 05:15:46 +00:00
# Add aggregated tag info to bookmark instances
query_set = Bookmark.objects \
2019-06-30 06:24:21 +00:00
.annotate(tag_count=Count('tags'),
tag_string=Concat('tags__name'),
tag_projection=Value(True, BooleanField()))
2019-06-29 10:53:37 +00:00
# Filter for user
query_set = query_set.filter(owner=user)
2019-06-30 17:54:33 +00:00
# Split query into search terms and tags
2019-06-30 19:15:02 +00:00
query = _parse_query_string(query_string)
2019-06-30 17:54:33 +00:00
# Filter for search terms and tags
2019-06-30 19:15:02 +00:00
for term in query['search_terms']:
2019-06-30 17:54:33 +00:00
query_set = query_set.filter(
Q(title__contains=term)
| Q(description__contains=term)
| Q(website_title__contains=term)
| Q(website_description__contains=term)
)
2019-06-30 19:15:02 +00:00
for tag_name in query['tag_names']:
2019-06-29 10:53:37 +00:00
query_set = query_set.filter(
2019-06-30 17:54:33 +00:00
tags__name=tag_name
2019-06-29 10:53:37 +00:00
)
# Sort by modification date
query_set = query_set.order_by('-date_modified')
return query_set
2019-06-30 19:15:02 +00:00
def query_tags(user: User, query_string: str):
query_set = Tag.objects
2019-06-30 19:15:02 +00:00
# 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,
}