From 6c9cc93b12e8e1ee44bac87665f53141051fe978 Mon Sep 17 00:00:00 2001 From: Michael Volo Date: Mon, 24 Feb 2025 12:07:37 -0600 Subject: [PATCH] Remove progress indicator and ally app, fix N+1 queries (#1613) * fix some n+1 querys * upgrade python * remove allies app (migrations done) * remove progress tracker (ROY-FE) * more N+1 queries * add basename to role router --- .python-version | 2 +- ...page_ptr_delete_allysubject_delete_ally.py | 23 +++++++++++++++++++ allies/models.py | 10 -------- api/migrations/0013_delete_progresstracker.py | 16 +++++++++++++ api/models.py | 8 ------- api/serializers.py | 18 +-------------- api/urls.py | 3 +-- api/views.py | 16 ++----------- snippets/models.py | 1 + snippets/urls.py | 2 +- snippets/views.py | 15 +++++------- webinars/models.py | 16 ++++++------- 12 files changed, 59 insertions(+), 71 deletions(-) create mode 100644 allies/migrations/0013_remove_ally_page_ptr_delete_allysubject_delete_ally.py create mode 100644 api/migrations/0013_delete_progresstracker.py diff --git a/.python-version b/.python-version index b6d8b7612..24ee5b1be 100644 --- a/.python-version +++ b/.python-version @@ -1 +1 @@ -3.11.8 +3.13 diff --git a/allies/migrations/0013_remove_ally_page_ptr_delete_allysubject_delete_ally.py b/allies/migrations/0013_remove_ally_page_ptr_delete_allysubject_delete_ally.py new file mode 100644 index 000000000..f21822a28 --- /dev/null +++ b/allies/migrations/0013_remove_ally_page_ptr_delete_allysubject_delete_ally.py @@ -0,0 +1,23 @@ +# Generated by Django 5.1.6 on 2025-02-21 21:35 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("allies", "0012_remove_ally_adaptive_courseware_and_more"), + ] + + operations = [ + migrations.RemoveField( + model_name="ally", + name="page_ptr", + ), + migrations.DeleteModel( + name="AllySubject", + ), + migrations.DeleteModel( + name="Ally", + ), + ] diff --git a/allies/models.py b/allies/models.py index b85c2b5f9..139597f9c 100644 --- a/allies/models.py +++ b/allies/models.py @@ -1,12 +1,2 @@ -from django.db import models -from wagtail.models import Page -from snippets.models import Subject -#TODO: remove this app after all migrations have been applied -class AllySubject(models.Model): - pass - - -class Ally(Page): - pass diff --git a/api/migrations/0013_delete_progresstracker.py b/api/migrations/0013_delete_progresstracker.py new file mode 100644 index 000000000..1776049dd --- /dev/null +++ b/api/migrations/0013_delete_progresstracker.py @@ -0,0 +1,16 @@ +# Generated by Django 5.0.12 on 2025-02-22 00:27 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("api", "0012_alter_webviewsettings_options"), + ] + + operations = [ + migrations.DeleteModel( + name="ProgressTracker", + ), + ] diff --git a/api/models.py b/api/models.py index cdff1299c..a1efc7db2 100644 --- a/api/models.py +++ b/api/models.py @@ -2,14 +2,6 @@ from books.models import Book -class ProgressTracker(models.Model): - account_id = models.IntegerField() - progress = models.IntegerField() - - def __str__(self): - return self.account_id - - class CustomizationRequest(models.Model): email = models.CharField(max_length=255) num_students = models.IntegerField() diff --git a/api/serializers.py b/api/serializers.py index f7a25346d..6eccefaee 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -2,7 +2,7 @@ from salesforce.models import Adopter from wagtail.images.models import Image from wagtail.documents.models import Document -from api.models import ProgressTracker, CustomizationRequest +from api.models import CustomizationRequest class AdopterSerializer(serializers.HyperlinkedModelSerializer): @@ -53,22 +53,6 @@ class Meta: ) -class ProgressSerializer(serializers.HyperlinkedModelSerializer): - - def create(self, validated_data): - progress, created = ProgressTracker.objects.update_or_create( - account_id=validated_data.get('account_id', None), - defaults={'progress':validated_data.get('progress', None)}) - - return progress - - class Meta: - model = ProgressTracker - fields = ('account_id', - 'progress', - ) - - class ModuleListingField(serializers.StringRelatedField): def to_internal_value(self, value): return value diff --git a/api/urls.py b/api/urls.py index 594e713b7..28bc4331b 100644 --- a/api/urls.py +++ b/api/urls.py @@ -1,13 +1,12 @@ from django.urls import include, path from rest_framework import routers -from .views import AdopterViewSet, ImageViewSet, DocumentViewSet, ProgressViewSet, customize_request, sticky_note, footer, schools, mapbox, flags, errata_fields, give_today, webview_settings +from .views import AdopterViewSet, ImageViewSet, DocumentViewSet, customize_request, sticky_note, footer, schools, mapbox, flags, errata_fields, give_today, webview_settings router = routers.DefaultRouter() router.register(r'images', ImageViewSet) router.register(r'documents', DocumentViewSet) router.register(r'adopters', AdopterViewSet) -router.register(r'progress', ProgressViewSet) urlpatterns = [ path('', include(router.urls)), diff --git a/api/views.py b/api/views.py index 73c918b86..8875acb00 100644 --- a/api/views.py +++ b/api/views.py @@ -14,8 +14,8 @@ from wagtail.images.models import Image from wagtail.documents.models import Document from wagtail.models import Site -from .models import ProgressTracker, FeatureFlag, WebviewSettings -from .serializers import AdopterSerializer, ImageSerializer, DocumentSerializer, ProgressSerializer, CustomizationRequestSerializer +from .models import FeatureFlag, WebviewSettings +from .serializers import AdopterSerializer, ImageSerializer, DocumentSerializer, CustomizationRequestSerializer class AdopterViewSet(viewsets.ReadOnlyModelViewSet): @@ -39,18 +39,6 @@ def get_queryset(self): return Document.objects.all() -class ProgressViewSet(viewsets.ReadOnlyModelViewSet): - queryset = ProgressTracker.objects.all() - serializer_class = ProgressSerializer - - def get_queryset(self): - queryset = ProgressTracker.objects.all() - account_id = self.request.query_params.get('account_id', None) - if account_id is not None: - queryset = queryset.filter(account_id=account_id) - return queryset - - def sticky_note(request): sticky_note = StickyNote.for_site(Site.find_for_request(request)) diff --git a/snippets/models.py b/snippets/models.py index e0a461d37..0384062ef 100644 --- a/snippets/models.py +++ b/snippets/models.py @@ -486,6 +486,7 @@ def __str__(self): register_snippet(AmazonBookBlurb) + class ContentWarning(TranslatableMixin, models.Model): content_warning = models.TextField() diff --git a/snippets/urls.py b/snippets/urls.py index 5999cdbc4..b6722f9f1 100644 --- a/snippets/urls.py +++ b/snippets/urls.py @@ -2,7 +2,7 @@ from . import views router = routers.SimpleRouter() -router.register('roles', views.RoleViewSet) +router.register('roles', views.RoleViewSet, basename="Roles") router.register('subjects', views.SubjectList, basename="Subjects") router.register('k12subjects', views.K12SubjectList, basename="K12Subjects") router.register('erratacontent', views.ErrataContentViewSet, basename="ErrataContent") diff --git a/snippets/views.py b/snippets/views.py index 537877695..b83bda19e 100644 --- a/snippets/views.py +++ b/snippets/views.py @@ -1,5 +1,3 @@ -from rest_framework import viewsets - from .models import Role, Subject, K12Subject, ErrataContent, SubjectCategory, GiveBanner, BlogContentType, \ BlogCollection, NoWebinarMessage, WebinarCollection, AmazonBookBlurb from .serializers import RoleSerializer, SubjectSerializer, K12SubjectSerializer, ErrataContentSerializer, \ @@ -8,7 +6,7 @@ WebinarCollectionSerializer, AmazonBookBlurbSerializer -from rest_framework import generics, viewsets +from rest_framework import viewsets from django_filters.rest_framework import DjangoFilterBackend SPANISH_LOCALE_ID = 2 @@ -16,11 +14,10 @@ class RoleViewSet(viewsets.ReadOnlyModelViewSet): - queryset = Role.objects.all() serializer_class = RoleSerializer def get_queryset(self): - queryset = Role.objects.all().order_by('display_name') + queryset = Role.objects.order_by('display_name') name = self.request.query_params.get('name', None) locale = self.request.query_params.get('locale', None) if name is not None: @@ -37,7 +34,7 @@ class SubjectList(viewsets.ReadOnlyModelViewSet): filter_backends = (DjangoFilterBackend,) def get_queryset(self): - queryset = Subject.objects.all().order_by('name') + queryset = Subject.objects.order_by('name') name = self.request.query_params.get('name', None) locale = self.request.query_params.get('locale', None) if name is not None: @@ -46,6 +43,7 @@ def get_queryset(self): queryset = queryset.filter(locale=convert_locale(locale)) return queryset + class K12SubjectList(viewsets.ReadOnlyModelViewSet): serializer_class = K12SubjectSerializer filter_backends = (DjangoFilterBackend,) @@ -60,6 +58,7 @@ def get_queryset(self): queryset = queryset.filter(locale=convert_locale(locale)) return queryset + class ErrataContentViewSet(viewsets.ReadOnlyModelViewSet): serializer_class = ErrataContentSerializer filter_backends = (DjangoFilterBackend,) @@ -129,7 +128,5 @@ def convert_locale(locale): def convert_subject_name(subject): - subjects = Subject.objects.all() - result = subjects.filter(name=subject) - return result[0].id + return Subject.objects.filter(name=subject).values_list('id', flat=True).first() diff --git a/webinars/models.py b/webinars/models.py index f35a19b66..0ca009920 100644 --- a/webinars/models.py +++ b/webinars/models.py @@ -1,5 +1,3 @@ -import json - from django.db import models from wagtail import blocks from wagtail.fields import StreamField @@ -59,14 +57,14 @@ class Webinar(models.Model): @property def selected_subjects(self): prep_value = self.webinar_subjects.get_prep_value() - subjects = [] - for s in prep_value: - for x in s['value']: - subject_id = x['value']['subject'] - subject = Subject.objects.filter(id=subject_id) - subjects.append(str(subject[0])) - return subjects + subject_ids = [x['value']['subject'] for s in prep_value for x in s['value']] + subjects_map = { + subj.id: str(subj) for subj in Subject.objects.filter(id__in=subject_ids) + } + + subjects = [subjects_map[x['value']['subject']] for s in prep_value for x in s['value']] + return subjects @property def selected_collections(self):