Skip to content

Instantly share code, notes, and snippets.

@cb109
Last active February 22, 2024 12:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cb109/bc17869ff73c7d2804ae3909264012d7 to your computer and use it in GitHub Desktop.
Save cb109/bc17869ff73c7d2804ae3909264012d7 to your computer and use it in GitHub Desktop.
Django Admin custom clientside Search for Index (tested with Django 3.2)
{% extends "admin/base_site.html" %}
{% block usertools %}
{% url 'admin:index' as admin_index_url %}
{% if request.get_full_path == admin_index_url %}
<input
type="text"
id="admin_base_search"
placeholder="Search..."
autofocus
style="margin-right: auto"
onkeydown="onSearchInputKeyPressed(event)"
>
<script>
/**
* Implement custom clientside search for app and model names.
*/
const APP_CAPTION_SELECTOR = 'div[class^="app-"] caption'
const MODEL_ANCHOR_SELECTOR = 'tr[class^="model-"] th a';
const searchInput = document.getElementById('admin_base_search');
const debounce = (callback, wait) => {
let timeoutId = null;
return (...args) => {
window.clearTimeout(timeoutId);
timeoutId = window.setTimeout(() => {
callback(...args);
}, wait);
};
}
const debouncedToggleModelVisibilityInAdmin = debounce(
toggleModelVisibilityInAdmin, 50
);
function onSearchInputKeyPressed(event) {
if (event.key == 'Escape') {
searchInput.value = '';
}
debouncedToggleModelVisibilityInAdmin();
}
function toggleModelVisibilityInAdmin() {
const searchText = searchInput.value.toLowerCase();
// Models
const modelAnchors = document.querySelectorAll(MODEL_ANCHOR_SELECTOR);
for (const anchor of modelAnchors) {
if (
anchor.innerText.toLowerCase().includes(searchText) ||
anchor.href.toLowerCase().includes(searchText.replace(' ', ''))
) {
anchor.parentElement.parentElement.style.display = '';
}
else {
anchor.parentElement.parentElement.style.display = 'none';
}
}
// Apps: Hide empty apps also.
const appCaptions = document.querySelectorAll(APP_CAPTION_SELECTOR);
for (const appCaption of appCaptions) {
console.log('appCaption', appCaption.innerText);
const visibleModels = [
...appCaption
.parentElement
.parentElement
.querySelectorAll(MODEL_ANCHOR_SELECTOR)
]
.filter(el => el.parentElement.parentElement.style.display !== 'none');
if (visibleModels.length == 0) {
appCaption.parentElement.parentElement.style.display = 'none';
}
else {
appCaption.parentElement.parentElement.style.display = '';
}
}
}
</script>
{% endif %}
{{ block.super }}
{% endblock %}

Copy the above template to yourproject/yourapp/templates/admin/base_site.html and ensure your app is registered after Django's admin app. The index page of your admin will now include a search box in the navbar. Typing will filter app names and model names immediately, pressing escape will clear the filter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment