Skip to content

Commit

Permalink
Add custom metadata facets to search form and view (#960)
Browse files Browse the repository at this point in the history
  • Loading branch information
blms committed Dec 19, 2023
1 parent 32ca1a8 commit b7a51b4
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 1 deletion.
30 changes: 30 additions & 0 deletions apps/readux/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from dateutil import parser
from django import forms
from django.conf import settings
from django.template.defaultfilters import truncatechars


Expand Down Expand Up @@ -139,12 +140,41 @@ class ManifestSearchForm(forms.Form):
)
)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

# pull additional facets from Elasticsearch
if (
settings
and hasattr(settings, "CUSTOM_METADATA")
and isinstance(settings.CUSTOM_METADATA, dict)
):
# should be a dict like {meta_key: {"multi": bool, "separator": str}}
for key in settings.CUSTOM_METADATA.keys():
self.fields[
# use django-friendly form field names
key.casefold().replace(" ", "_")
] = FacetedMultipleChoiceField(
label=key,
required=False,
widget=forms.SelectMultiple(
attrs={
"aria-label": f"Filter volumes by {key}",
"class": "uk-input",
},
),
)

def set_facets(self, facets):
"""Use facets from Elasticsearch to populate form fields"""
for name, buckets in facets.items():
if name in self.fields:
# Assumes that name passed in the view's facets list matches form field name
self.fields[name].populate_from_buckets(buckets)
elif name.casefold().replace(" ", "_") in self.fields:
self.fields[name.casefold().replace(" ", "_")].populate_from_buckets(
buckets
)

def set_date(self, min_date, max_date):
"""Use min and max aggregations from Elasticsearch to populate date range fields"""
Expand Down
38 changes: 38 additions & 0 deletions apps/readux/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,20 @@ class VolumeSearchView(ListView, FormMixin):
"sort": "label_alphabetical"
}

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# pull additional facets from Elasticsearch
if (
settings
and hasattr(settings, "CUSTOM_METADATA")
and isinstance(settings.CUSTOM_METADATA, dict)
):
for key in settings.CUSTOM_METADATA.keys():
self.facets.append((key, NestedFacet(
"metadata",
TermsFacet(field=f"metadata.{key}", size=2000, min_doc_count=1),
)))

# regex to match terms in doublequotes
re_exact_match = re.compile(r'\B(".+?")\B')

Expand Down Expand Up @@ -368,6 +382,18 @@ def get_form_kwargs(self):

def get_context_data(self, **kwargs):
context_data = super().get_context_data(**kwargs)
# add configured custom metadata keys to context data
context_data["CUSTOM_METADATA_KEYS"] = (
[
# use django-friendly form field names
key.casefold().replace(" ", "_")
for key in settings.CUSTOM_METADATA.keys()
]
if hasattr(settings, "CUSTOM_METADATA")
and isinstance(settings.CUSTOM_METADATA, dict)
else []
)

volumes_response = self.get_queryset().execute()
# populate a dict with "buckets" of extant categories for each facet
facets = {}
Expand Down Expand Up @@ -519,6 +545,18 @@ def get_queryset(self):
if max_date_filter:
volumes = volumes.filter("range", date_latest={"lte": max_date_filter})

# filter on custom metadata fields
if hasattr(settings, "CUSTOM_METADATA") and isinstance(
settings.CUSTOM_METADATA, dict
):
for key in settings.CUSTOM_METADATA.keys():
field_name = key.casefold().replace(" ", "_")
meta_filter = form_data.get(field_name) or ""
if meta_filter:
volumes = volumes.filter("nested", path="metadata", query=Q(
"terms", **{f"metadata.{key}": meta_filter}
))

# create aggregation buckets for facet fields
for (facet_name, facet) in self.facets:
volumes.aggs.bucket(facet_name, facet.get_aggregation())
Expand Down
12 changes: 11 additions & 1 deletion apps/templates/search_results.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{% extends "base.html" %}
{% load wagtailcore_tags static %}
{% load wagtailcore_tags static readux_extras %}

{% block extra_head %}
<meta property="og:title" content="Readux - Search" />
Expand Down Expand Up @@ -112,6 +112,16 @@ <h4 class="uk-flex uk-flex-center">Filters</h4>
{{ form.end_date }}
</noscript>
</fieldset>
{% for key in CUSTOM_METADATA_KEYS %}
<fieldset class="uk-margin">
<div class="uk-width-1-1">
{% with form|dict_item:key as field %}
<div class="uk-form-label">{{ field.label }}</div>
{{ field }}
{% endwith %}
</div>
</fieldset>
{% endfor %}
<fieldset class="uk-margin uk-width-1-1 uk-flex uk-flex-between">
<button id="reset-filters" class="uk-button uk-button-danger" type="button">
Reset filters
Expand Down

0 comments on commit b7a51b4

Please sign in to comment.