show search result from meilisearch
This commit is contained in:
parent
0ed828ba1d
commit
06c3ba6f3b
3 changed files with 85 additions and 6 deletions
|
@ -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'])
|
||||
|
|
|
@ -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">«</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">‹</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">›</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">»</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">»</a>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
|
|
@ -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=
|
||||
|
|
Loading…
Add table
Reference in a new issue