admin: add SearchListMixin mixin and partial template
This commit is contained in:
parent
b35d27c83e
commit
0150a5c58c
|
@ -1,13 +1,15 @@
|
||||||
"""passbook admin util views"""
|
"""passbook admin util views"""
|
||||||
from typing import Any, Dict, Optional
|
from typing import Any, Dict, List, Optional
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.messages.views import SuccessMessageMixin
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
|
from django.contrib.postgres.search import SearchQuery, SearchVector
|
||||||
from django.db.models import QuerySet
|
from django.db.models import QuerySet
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.http.request import HttpRequest
|
from django.http.request import HttpRequest
|
||||||
from django.views.generic import DeleteView, ListView, UpdateView
|
from django.views.generic import DeleteView, ListView, UpdateView
|
||||||
|
from django.views.generic.list import MultipleObjectMixin
|
||||||
|
|
||||||
from passbook.lib.utils.reflection import all_subclasses
|
from passbook.lib.utils.reflection import all_subclasses
|
||||||
from passbook.lib.views import CreateAssignPermView
|
from passbook.lib.views import CreateAssignPermView
|
||||||
|
@ -32,6 +34,26 @@ class InheritanceListView(ListView):
|
||||||
return super().get_queryset().select_subclasses()
|
return super().get_queryset().select_subclasses()
|
||||||
|
|
||||||
|
|
||||||
|
class SearchListMixin(MultipleObjectMixin):
|
||||||
|
"""Accept search query using `search` querystring parameter. Requires self.search_fields,
|
||||||
|
a list of all fields to search. Can contain special lookups like __icontains"""
|
||||||
|
|
||||||
|
search_fields: List[str]
|
||||||
|
|
||||||
|
def get_queryset(self) -> QuerySet:
|
||||||
|
queryset = super().get_queryset()
|
||||||
|
if "search" in self.request.GET:
|
||||||
|
raw_query = self.request.GET["search"]
|
||||||
|
if raw_query == "":
|
||||||
|
# Empty query, don't search at all
|
||||||
|
return queryset
|
||||||
|
search = SearchQuery(raw_query, search_type="websearch")
|
||||||
|
return queryset.annotate(search=SearchVector(*self.search_fields)).filter(
|
||||||
|
search=search
|
||||||
|
)
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
class InheritanceCreateView(CreateAssignPermView):
|
class InheritanceCreateView(CreateAssignPermView):
|
||||||
"""CreateView for objects using InheritanceManager"""
|
"""CreateView for objects using InheritanceManager"""
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
<div class="pf-c-toolbar__group pf-m-filter-group">
|
||||||
|
<div class="pf-c-toolbar__item pf-m-search-filter">
|
||||||
|
<form class="pf-c-input-group" method="GET">
|
||||||
|
{# include page data for pagination #}
|
||||||
|
<input type="hidden" name="page" value="{{ page_obj.number }}">
|
||||||
|
<input class="pf-c-form-control" name="search" type="search" placeholder="Search..." value="{{ request.GET.search }}">
|
||||||
|
<button class="pf-c-button pf-m-control" type="submit">
|
||||||
|
<i class="fas fa-search" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -7,6 +7,14 @@ document.querySelectorAll("button.pf-c-dropdown__toggle").forEach((b) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll("input[type=search]").forEach((si) => {
|
||||||
|
si.addEventListener("search", (e) => {
|
||||||
|
if (si.value === "") {
|
||||||
|
si.parentElement.submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// Modal
|
// Modal
|
||||||
document.querySelectorAll("[data-target='modal']").forEach((m) => {
|
document.querySelectorAll("[data-target='modal']").forEach((m) => {
|
||||||
m.addEventListener("click", (e) => {
|
m.addEventListener("click", (e) => {
|
||||||
|
|
Reference in New Issue