diff --git a/course_discovery/apps/course_metadata/admin.py b/course_discovery/apps/course_metadata/admin.py index 8f5900d0d0..2fa25dbd30 100644 --- a/course_discovery/apps/course_metadata/admin.py +++ b/course_discovery/apps/course_metadata/admin.py @@ -3,6 +3,7 @@ from django.conf import settings from django.contrib import admin, messages from django.contrib.admin.utils import model_ngettext +from django.db.models import Prefetch from django.db.utils import IntegrityError from django.forms import CheckboxSelectMultiple, ModelForm from django.http import HttpResponseRedirect @@ -85,6 +86,9 @@ class SeatInline(admin.TabularInline): readonly_fields = ('_upgrade_deadline', ) raw_id_fields = ('draft_version', 'currency') + def get_queryset(self, request): + return super().get_queryset(request).select_related('draft_version', 'currency') + class PositionInline(admin.TabularInline): model = Position @@ -135,6 +139,10 @@ class CourseAdmin(DjangoObjectActions, SimpleHistoryAdmin): autocomplete_fields = ['canonical_course_run'] change_actions = ('course_skills', 'refresh_course_skills') + def get_queryset(self, request): + queryset = super().get_queryset(request) + return queryset.select_related('canonical_course_run').prefetch_related('location_restriction') + def get_search_results(self, request, queryset, search_term): queryset, may_have_duplicates = super().get_search_results(request, queryset, search_term) if request.GET.get('app_label') == learner_pathway_app_name: @@ -223,6 +231,8 @@ class CourseEditorAdmin(admin.ModelAdmin): @admin.register(CourseEntitlement) class CourseEntitlementAdmin(SimpleHistoryAdmin): list_display = ['course', 'get_course_key', 'mode', 'draft'] + raw_id_fields = ('course', 'draft_version',) + search_fields = ['course__title', 'course__key'] @admin.display( description='Course key' @@ -230,8 +240,9 @@ class CourseEntitlementAdmin(SimpleHistoryAdmin): def get_course_key(self, obj): return obj.course.key - raw_id_fields = ('course', 'draft_version',) - search_fields = ['course__title', 'course__key'] + def get_queryset(self, request): + queryset = super().get_queryset(request) + return queryset.select_related('course', 'mode', 'partner') @admin.register(Mode) @@ -242,6 +253,7 @@ class ModeAdmin(admin.ModelAdmin): @admin.register(Track) class TrackAdmin(admin.ModelAdmin): list_display = ['mode', 'seat_type'] + list_select_related = ['seat_type', 'mode'] @admin.register(CourseRunType) @@ -287,6 +299,12 @@ class CourseRunAdmin(SimpleHistoryAdmin): save_error = False form = CourseRunAdminForm + def get_queryset(self, request): + qs = super().get_queryset(request) + return qs.select_related( + 'course', 'draft_version', 'language', 'type' + ) + def get_readonly_fields(self, request, obj=None): """ Make UUID field editable for draft if flag is enabled. @@ -391,6 +409,30 @@ class ProgramAdmin(DjangoObjectActions, SimpleHistoryAdmin): save_error = False + def get_queryset(self, request): + queryset = super().get_queryset(request) + queryset = queryset.select_related( + 'partner', + 'type' + ).prefetch_related( + 'courses', + 'authoring_organizations', + 'credit_backing_organizations', + ) + return queryset + + def formfield_for_foreignkey(self, db_field, request, **kwargs): + """ + Optimize ForeignKey dropdowns by customizing the queryset. + """ + if db_field.name == 'primary_subject_override': + kwargs['queryset'] = Subject.objects.all() + if db_field.name == 'level_type_override': + kwargs['queryset'] = LevelType.objects.all() + if db_field.name == 'type': + kwargs['queryset'] = ProgramType.objects.all() + return super().formfield_for_foreignkey(db_field, request, **kwargs) + def get_readonly_fields(self, request, obj=None): """ Make product_source field readonly if program obj is already created. In case a product without product_source @@ -492,6 +534,15 @@ class PathwayAdmin(admin.ModelAdmin): def get_programs(self, obj): return [*obj.programs.all()] + def get_queryset(self, request): + queryset = super().get_queryset(request) + queryset = queryset.select_related('partner').prefetch_related( + Prefetch('programs', queryset=Program.objects.prefetch_related( + 'courses__course_runs', + )) + ) + return queryset + @admin.register(ProgramType) class ProgramTypeAdmin(TranslatableAdmin): @@ -538,6 +589,10 @@ class AdditionalPromoAreaAdmin(admin.ModelAdmin): list_display = ('title', 'description', 'courses') search_fields = ('description',) + def get_queryset(self, request): + queryset = super().get_queryset(request) + return queryset.prefetch_related('extra_description') + def courses(self, obj): return ', '.join([ course.key for course in obj.extra_description.all() @@ -549,6 +604,17 @@ class FactAdmin(admin.ModelAdmin): list_display = ('heading', 'blurb', 'courses') search_fields = ('heading', 'blurb',) + def get_queryset(self, request): + queryset = super().get_queryset(request) + queryset = queryset.prefetch_related( + Prefetch( + "related_course_additional_metadata", + queryset=AdditionalMetadata.objects.prefetch_related("related_courses"), + ) + ) + + return queryset + def courses(self, obj): def _get_course_keys(additional_metadata_object): @@ -564,6 +630,9 @@ class CertificateInfoAdmin(admin.ModelAdmin): list_display = ('heading', 'blurb', 'courses') search_fields = ('heading', 'blurb',) + def get_queryset(self, request): + return super().get_queryset(request).prefetch_related('related_course_additional_metadata__related_courses') + def courses(self, obj): def _get_course_keys(additional_metadata_object): @@ -583,6 +652,17 @@ class AdditionalMetadataAdmin(admin.ModelAdmin): search_fields = ('external_identifier', 'external_url') list_filter = ('product_status', ) + def get_queryset(self, request): + queryset = super().get_queryset(request) + return queryset.prefetch_related( + 'related_courses', + 'facts', + ).select_related( + 'taxi_form', + 'product_meta', + 'certificate_info', + ) + def courses(self, obj): return ', '.join([ course.key for course in obj.related_courses.all() @@ -643,6 +723,9 @@ class SubjectAdmin(TranslatableAdmin): readonly_fields = ('uuid',) search_fields = ('uuid', 'name', 'slug',) + def get_queryset(self, request): + return super().get_queryset(request).select_related('partner').prefetch_related('translations') + @admin.register(Topic) class TopicAdmin(TranslatableAdmin): @@ -661,6 +744,12 @@ class PersonAdmin(admin.ModelAdmin): readonly_fields = ('uuid',) search_fields = ('uuid', 'salutation', 'family_name', 'given_name', 'slug',) + def get_queryset(self, request): + return super().get_queryset(request).select_related( + 'partner', + 'bio_language', + ) + @admin.register(Position) class PositionAdmin(admin.ModelAdmin): @@ -697,6 +786,14 @@ class LevelTypeAdmin(SortableAdminMixin, TranslatableAdmin): search_fields = ('name_t',) fields = ('name_t',) + def get_queryset(self, request): + return super().get_queryset(request).prefetch_related( + Prefetch('translations', queryset=LevelTypeTranslation.objects.all(), to_attr='translated_names') + ) + + def name_t(self, obj): + return obj.translated_names[0].name_t if obj.translated_names else obj.name + class CurriculumProgramMembershipInline(admin.TabularInline): model = CurriculumProgramMembership @@ -782,11 +879,17 @@ class IconTextPairingInline(admin.StackedInline): class DegreeDeadlineAdmin(admin.ModelAdmin): list_display = ('degree', 'semester', 'name', 'date', 'time') + def get_queryset(self, request): + return super().get_queryset(request).select_related('degree') + @admin.register(DegreeCost) class DegreeCostAdmin(admin.ModelAdmin): list_display = ('degree', 'description', 'amount') + def get_queryset(self, request): + return super().get_queryset(request).select_related('degree') + class DegreeDeadlineInlineAdmin(admin.StackedInline): model = DegreeDeadline @@ -806,6 +909,9 @@ class DegreeAdditionalMetadataInlineAdmin(admin.StackedInline): class DegreeAdditionalMetadataAdmin(admin.ModelAdmin): list_display = ('degree', 'external_url', 'external_identifier', 'organic_url') + def get_queryset(self, request): + return super().get_queryset(request).select_related('degree') + @admin.register(Specialization) class SpecializationAdmin(admin.ModelAdmin): @@ -843,6 +949,9 @@ class DegreeAdmin(admin.ModelAdmin): ) actions = ['publish_degrees', 'unpublish_degrees', 'display_degrees_on_org_page', 'hide_degrees_on_org_page'] + def get_queryset(self, request): + return super().get_queryset(request).prefetch_related('additional_metadata') + def change_degree_status(self, request, queryset, status): """ Changes the status of a degree. @@ -1052,6 +1161,9 @@ class RestrictedCourseRunAdmin(admin.ModelAdmin): list_display = ['course_run', 'restriction_type'] search_fields = ['course_run__key', 'restriction_type'] + def get_queryset(self, request): + return super().get_queryset(request).select_related('course_run__course') + class CourseReviewAdmin(admin.ModelAdmin): """