show search result from meilisearch

This commit is contained in:
Their Name 2021-12-30 15:53:50 -05:00 committed by Your Name
parent 0ed828ba1d
commit 06c3ba6f3b
3 changed files with 85 additions and 6 deletions

View file

@ -7,12 +7,13 @@ from django.db.models.signals import post_save, post_delete
# use post_save, post_delete
# search result translate back to model
INDEX_NAME = 'items'
INDEX_SEARCHABLE_ATTRIBUTES = ['title', 'orig_title', 'other_title', 'subtitle', 'artist', 'author', 'translator', 'developer', 'brief', 'contents', 'track_list', 'pub_house', 'company', 'publisher', 'isbn', 'imdb_code', 'UPC', 'TMDB_ID', 'BANDCAMP_ALBUM_ID']
INDEX_SEARCHABLE_ATTRIBUTES = ['title', 'orig_title', 'other_title', 'subtitle', 'artist', 'author', 'translator', 'developer', 'director', 'actor', 'playwright', 'brief', 'contents', 'track_list', 'pub_house', 'company', 'publisher', 'isbn', 'imdb_code', 'UPC', 'TMDB_ID', 'BANDCAMP_ALBUM_ID']
INDEXABLE_DIRECT_TYPES = ['BigAutoField', 'BooleanField', 'CharField', 'PositiveIntegerField', 'PositiveSmallIntegerField', 'TextField', 'ArrayField']
INDEXABLE_TIME_TYPES = ['DateTimeField']
INDEXABLE_DICT_TYPES = ['JSONField']
INDEXABLE_FLOAT_TYPES = ['DecimalField']
# NONINDEXABLE_TYPES = ['ForeignKey', 'FileField',]
SEARCH_PAGE_SIZE = 20
def item_post_save_handler(sender, instance, **kwargs):
@ -32,6 +33,8 @@ def tag_post_delete_handler(sender, instance, **kwargs):
class Indexer:
class_map = {}
@classmethod
def instance(self):
return meilisearch.Client(settings.MEILISEARCH_SERVER, settings.MEILISEARCH_KEY).index(INDEX_NAME)
@ -54,6 +57,7 @@ class Indexer:
@classmethod
def update_model_indexable(self, model):
self.class_map[model.__name__] = model
model.indexable_fields = ['tags']
model.indexable_fields_time = []
model.indexable_fields_dict = []
@ -108,3 +112,36 @@ class Indexer:
for f in fields:
data[f] = getattr(obj, f)
self.instance().update_documents(documents=[data], primary_key=[pk])
@classmethod
def search(self, q, page=1, category=None, tag=None, sort=None):
if category or tag:
f = []
if category == 'music':
f.append("(_class = 'Album' OR _class = 'Song')")
elif category:
f.append(f"_class = '{category}'")
if tag:
f.append(f"tags = '{tag}'")
filter = ' AND '.join(f)
else:
filter = None
options = {
'offset': (page - 1) * SEARCH_PAGE_SIZE,
'limit': SEARCH_PAGE_SIZE,
'filter': filter,
'facetsDistribution': ['_class'],
'sort': None
}
r = self.instance().search(q, options)
print(r)
import types
results = types.SimpleNamespace()
results.items = list(map(lambda i: self.item_to_obj(i), r['hits']))
results.num_pages = (r['nbHits'] + SEARCH_PAGE_SIZE - 1) // SEARCH_PAGE_SIZE
print(results)
return results
@classmethod
def item_to_obj(self, item):
return self.class_map[item['_class']].objects.get(id=item['id'])

View file

@ -93,14 +93,14 @@
</div>
<div class="pagination" >
{% if items.pagination.has_prev %}
{% if pagination.has_prev %}
<a href="?page=1&{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}" class="pagination__nav-link pagination__nav-link">&laquo;</a>
<a href="?page={{ items.previous_page_number }}&{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}" class="pagination__nav-link pagination__nav-link--right-margin pagination__nav-link">&lsaquo;</a>
{% endif %}
{% for page in items.pagination.page_range %}
{% for page in pagination.page_range %}
{% if page == items.pagination.current_page %}
{% if page == pagination.current_page %}
<a href="?page={{ page }}&{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}" class="pagination__page-link pagination__page-link--current">{{ page }}</a>
{% else %}
<a href="?page={{ page }}&{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}" class="pagination__page-link">{{ page }}</a>
@ -108,9 +108,9 @@
{% endfor %}
{% if items.pagination.has_next %}
{% if pagination.has_next %}
<a href="?page={{ items.next_page_number }}&{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}" class="pagination__nav-link pagination__nav-link--left-margin">&rsaquo;</a>
<a href="?page={{ items.pagination.last_page }}&{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}" class="pagination__nav-link">&raquo;</a>
<a href="?page={{ pagination.last_page }}&{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}" class="pagination__nav-link">&raquo;</a>
{% endif %}
</div>

View file

@ -24,6 +24,8 @@ from common.config import *
from common.searcher import ExternalSources
from management.models import Announcement
from django.conf import settings
from common.index import Indexer
logger = logging.getLogger(__name__)
@ -33,8 +35,48 @@ def home(request):
return user_home(request, request.user.id)
@login_required
def search(request):
category = request.GET.get("c", default='all').strip().lower()
if category == 'all':
category = None
keywords = request.GET.get("q", default='').strip()
tag = request.GET.get("tag", default='').strip()
page_number = request.GET.get('page', default=1)
if not (keywords or tag):
return render(
request,
"common/search_result.html",
{
"items": None,
}
)
url_validator = URLValidator()
try:
url_validator(keywords)
# validation success
return jump_or_scrape(request, keywords)
except ValidationError as e:
pass
#
result = Indexer.search(keywords, page=page_number, category=category, tag=tag)
for item in result.items:
item.tag_list = item.all_tag_list[:TAG_NUMBER_ON_LIST]
return render(
request,
"common/search_result.html",
{
"items": result.items,
"pagination": PageLinksGenerator(PAGE_LINK_NUMBER, page_number, result.num_pages),
"external_items": ExternalSources.search(category, keywords, page_number),
"categories": ['book', 'movie', 'music', 'game'],
}
)
@login_required
def search2(request):
if request.method == 'GET':
# test if input serach string is empty or not excluding param ?c=