From 45533e0b2df178ba9af23e5e7e3076992a5d57d4 Mon Sep 17 00:00:00 2001 From: Daniel Egger Date: Fri, 17 Mar 2023 10:59:20 +0100 Subject: [PATCH] Refactor `frontend_url` calculation to avoid DB access and improve performance Das initiale Laden des Lernpfads dauerte so lange, weil das berechnen des Felds `frontend_url` sehr viele DB-Zugriffe auf die jeweiligen "parents" einer Page machten. Die gleiche Berechnung kann man aber auch direkt aus dem `slug` ohne Zugriff auf die Parents machen. Das wurde hier gemacht. Das ganze beruht darauf, dass die page-`slug` in einem bestimmten Format ist. Um das weiter zu bearbeiten, habe ich VBV-296 erstellt. --- server/vbv_lernwelt/competence/models.py | 2 +- server/vbv_lernwelt/course/views.py | 13 ++++-- .../learnpath/create_vv_new_learning_path.py | 6 +-- server/vbv_lernwelt/learnpath/models.py | 45 ++++++++++++++----- server/vbv_lernwelt/media_library/models.py | 7 ++- 5 files changed, 52 insertions(+), 21 deletions(-) diff --git a/server/vbv_lernwelt/competence/models.py b/server/vbv_lernwelt/competence/models.py index b44304da..fc69abd6 100644 --- a/server/vbv_lernwelt/competence/models.py +++ b/server/vbv_lernwelt/competence/models.py @@ -30,7 +30,7 @@ class CompetenceProfilePage(CourseBasePage): super(CompetenceProfilePage, self).full_clean(*args, **kwargs) def get_frontend_url(self): - return f"/course/{self.get_parent().slug}/competence" + return f"/course/{self.slug.replace('-competence', '')}/competence" class CompetencePage(CourseBasePage): diff --git a/server/vbv_lernwelt/course/views.py b/server/vbv_lernwelt/course/views.py index 3716ec4e..478c4e1d 100644 --- a/server/vbv_lernwelt/course/views.py +++ b/server/vbv_lernwelt/course/views.py @@ -39,10 +39,15 @@ def course_page_api_view(request, slug): if not has_course_access_by_page_request(request, page): raise PermissionDenied() - data = api_page_cache_get_or_set( - key=request.get_full_path(), - func=lambda: page.specific.get_serializer_class()(page.specific).data, - ) + with_cache = False + + if with_cache: + data = api_page_cache_get_or_set( + key=request.get_full_path(), + func=lambda: page.specific.get_serializer_class()(page.specific).data, + ) + else: + data = page.specific.get_serializer_class()(page.specific).data return Response(data) except PermissionDenied as e: diff --git a/server/vbv_lernwelt/learnpath/create_vv_new_learning_path.py b/server/vbv_lernwelt/learnpath/create_vv_new_learning_path.py index d5af0f48..4dbe8f2b 100644 --- a/server/vbv_lernwelt/learnpath/create_vv_new_learning_path.py +++ b/server/vbv_lernwelt/learnpath/create_vv_new_learning_path.py @@ -937,12 +937,12 @@ def create_circle_vernetzen(lp, title="Vernetzen"): LearningSequenceFactory(title="Training", parent=circle, icon="it-icon-ls-watch") LearningUnitFactory(title="Onlinetrainings", parent=circle) LearningContentFactory( - title="???", + title="Unknown ???", parent=circle, ) LearningUnitFactory(title="Webinare", parent=circle) LearningContentFactory( - title="???", + title="Unknown ???", parent=circle, ) @@ -968,7 +968,7 @@ def create_circle_pruefungsvorbereitung(lp, title="Prüfungsvorbereitung"): LearningSequenceFactory(title="Aufbau", parent=circle, icon="it-icon-ls-watch") LearningUnitFactory(title="Aufbau und Struktur", parent=circle) LearningContentFactory( - title="???", + title="Unknown ???", parent=circle, ) diff --git a/server/vbv_lernwelt/learnpath/models.py b/server/vbv_lernwelt/learnpath/models.py index 32000f48..616cf022 100644 --- a/server/vbv_lernwelt/learnpath/models.py +++ b/server/vbv_lernwelt/learnpath/models.py @@ -1,3 +1,5 @@ +import re + from django.db import models from django.utils.text import slugify from wagtail.admin.panels import FieldPanel, StreamFieldPanel @@ -42,7 +44,7 @@ class LearningPath(CourseBasePage): return f"{self.title}" def get_frontend_url(self): - return f"/course/{self.get_parent().slug}/learn" + return f"/course/{self.slug.replace('-lp', '')}/learn" class Topic(CourseBasePage): @@ -95,8 +97,11 @@ class Circle(CourseBasePage): ] def get_frontend_url(self): - short_slug = self.slug.replace(f"{self.get_parent().slug}-circle-", "") - return f"{self.get_parent().specific.get_frontend_url()}/{short_slug}" + r = re.compile(r"^(?P.+?)-lp-circle-(?P.+?)$") + m = r.match(self.slug) + if m is None: + return "ERROR: could not parse slug" + return f"/course/{m.group('coursePart')}/learn/{m.group('circlePart')}" def full_clean(self, *args, **kwargs): self.slug = find_slug_with_parent_prefix(self, "circle") @@ -145,8 +150,13 @@ class LearningSequence(CourseBasePage): super(LearningSequence, self).full_clean(*args, **kwargs) def get_frontend_url(self): - short_slug = self.slug.replace(f"{self.get_parent().slug}-", "") - return f"{self.get_parent().specific.get_frontend_url()}#{short_slug}" + r = re.compile( + r"^(?P.+?)-lp-circle-(?P.+?)-ls-(?P.+?)$" + ) + m = r.match(self.slug) + if m is None: + return "ERROR: could not parse slug" + return f"/course/{m.group('coursePart')}/learn/{m.group('circlePart')}#ls-{m.group('lsPart')}" class LearningUnit(CourseBasePage): @@ -186,12 +196,20 @@ class LearningUnit(CourseBasePage): super(LearningUnit, self).full_clean(*args, **kwargs) def get_frontend_url(self): - short_slug = self.slug.replace(f"{self.get_parent().slug}-lu-", "") - return f"{self.get_parent().specific.get_frontend_url()}#lu-{short_slug}" + r = re.compile( + r"^(?P.+?)-lp-circle-(?P.+?)-lu-(?P.+?)$" + ) + m = r.match(self.slug) + if m is None: + return "ERROR: could not parse slug" + return f"/course/{m.group('coursePart')}/learn/{m.group('circlePart')}#lu-{m.group('luPart')}" def get_evaluate_url(self): - short_slug = self.slug.replace(f"{self.get_parent().slug}-lu-", "") - return f"{self.get_parent().specific.get_frontend_url()}/evaluate/{short_slug}" + r = re.compile( + r"^(?P.+?)-lp-circle-(?P.+?)-lu-(?P.+?)$" + ) + m = r.match(self.slug) + return f"/course/{m.group('coursePart')}/learn/{m.group('circlePart')}/evaluate/{m.group('luPart')}" def get_admin_display_title(self): return f"LE: {self.draft_title}" @@ -263,8 +281,13 @@ class LearningContent(CourseBasePage): verbose_name = "Learning Content" def get_frontend_url(self): - short_slug = self.slug.replace(f"{self.get_parent().slug}-lc-", "") - return f"{self.get_parent().specific.get_frontend_url()}/{short_slug}" + r = re.compile( + r"^(?P.+?)-lp-circle-(?P.+?)-lc-(?P.+)$" + ) + m = r.match(self.slug) + if m is None: + return "ERROR: could not parse slug" + return f"/course/{m.group('coursePart')}/learn/{m.group('circlePart')}/{m.group('lcPart')}" def full_clean(self, *args, **kwargs): self.slug = find_slug_with_parent_prefix(self, "lc") diff --git a/server/vbv_lernwelt/media_library/models.py b/server/vbv_lernwelt/media_library/models.py index 534c2a96..cd862a1a 100644 --- a/server/vbv_lernwelt/media_library/models.py +++ b/server/vbv_lernwelt/media_library/models.py @@ -1,3 +1,5 @@ +import re + from django.db import models from django.utils.text import slugify from wagtail import blocks, fields @@ -89,8 +91,9 @@ class MediaCategoryPage(CourseBasePage): super(MediaCategoryPage, self).full_clean(*args, **kwargs) def get_frontend_url(self): - short_slug = self.slug.replace(f"{self.get_parent().slug}-cat-", "") - return f"{self.get_parent().specific.get_frontend_url()}/category/{short_slug}" + r = re.compile(r"^(?P.+?)-media-cat-(?P.+)$") + m = r.match(self.slug) + return f"/media/{m.group('coursePart')}-media/category/{m.group('catPart')}" class LibraryDocument(AbstractDocument):