From 0b509f22008d3982535ba002e8d24858bffdeaaa Mon Sep 17 00:00:00 2001 From: imperosol Date: Fri, 6 Dec 2024 17:40:18 +0100 Subject: [PATCH 1/2] fix N+1 queries on user search --- core/schemas.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/schemas.py b/core/schemas.py index 775cd6b0..f4080c90 100644 --- a/core/schemas.py +++ b/core/schemas.py @@ -4,6 +4,7 @@ from typing import Annotated from annotated_types import MinLen from django.contrib.staticfiles.storage import staticfiles_storage from django.db.models import Q +from django.urls import reverse from django.utils.text import slugify from haystack.query import SearchQuerySet from ninja import FilterSchema, ModelSchema, Schema @@ -37,13 +38,13 @@ class UserProfileSchema(ModelSchema): @staticmethod def resolve_profile_url(obj: User) -> str: - return obj.get_absolute_url() + return reverse("core:user_profile", kwargs={"user_id": obj.pk}) @staticmethod def resolve_profile_pict(obj: User) -> str: if obj.profile_pict_id is None: return staticfiles_storage.url("core/img/unknown.jpg") - return obj.profile_pict.get_download_url() + return reverse("core:download", kwargs={"file_id": obj.profile_pict_id}) class SithFileSchema(ModelSchema): From 84d7e40e668d77d158b0b9044eccd5215c8288e4 Mon Sep 17 00:00:00 2001 From: imperosol Date: Fri, 6 Dec 2024 18:28:12 +0100 Subject: [PATCH 2/2] feat: client-side cache for ajax-select inputs --- .../bundled/core/components/ajax-select-base.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/core/static/bundled/core/components/ajax-select-base.ts b/core/static/bundled/core/components/ajax-select-base.ts index 0befd398..674b7b73 100644 --- a/core/static/bundled/core/components/ajax-select-base.ts +++ b/core/static/bundled/core/components/ajax-select-base.ts @@ -103,6 +103,12 @@ export class AutoCompleteSelectBase extends inheritHtmlElement("select") { export abstract class AjaxSelect extends AutoCompleteSelectBase { protected filter?: (items: TomOption[]) => TomOption[] = null; protected minCharNumberForSearch = 2; + /** + * A cache of researches that have been made using this input. + * For each record, the key is the user's query and the value + * is the list of results sent back by the server. + */ + protected cache = {} as Record; protected abstract valueField: string; protected abstract labelField: string; @@ -135,7 +141,13 @@ export abstract class AjaxSelect extends AutoCompleteSelectBase { this.widget.clearOptions(); } - const resp = await this.search(query); + // Check in the cache if this query has already been typed + // and do an actual HTTP request only if the result isn't cached + let resp = this.cache[query]; + if (!resp) { + resp = await this.search(query); + this.cache[query] = resp; + } if (this.filter) { callback(this.filter(resp), []);