From 91be371ac3334cbc34ea4b53ada00cbf52de55bf Mon Sep 17 00:00:00 2001 From: Maxim Beder Date: Tue, 11 Apr 2023 16:30:52 +0200 Subject: [PATCH] wip: fix using a separate manager --- enterprise/api/v1/serializers.py | 68 +++++++++----------------------- enterprise/api/v1/views.py | 2 +- enterprise/models.py | 54 +++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 50 deletions(-) diff --git a/enterprise/api/v1/serializers.py b/enterprise/api/v1/serializers.py index 8328c9deff..2d63d02f5f 100644 --- a/enterprise/api/v1/serializers.py +++ b/enterprise/api/v1/serializers.py @@ -41,16 +41,6 @@ ) from enterprise.validators import validate_pgp_key -try: - from common.djangoapps.student.models import CourseEnrollment -except ImportError: - CourseEnrollment = None - -try: - from openedx.core.djangoapps.content.course_overviews.models import CourseOverview -except ImportError: - CourseOverview = None - LOGGER = getLogger(__name__) User = auth.get_user_model() @@ -336,8 +326,7 @@ class EnterpriseCourseEnrollmentReadOnlySerializer(serializers.ModelSerializer): class Meta: model = models.EnterpriseCourseEnrollment fields = ( - 'enterprise_customer_user', - 'course_id', + 'enterprise_customer_user', 'course_id', ) @@ -346,44 +335,25 @@ class EnterpriseCourseEnrollmentWithAdditionalFieldsReadOnlySerializer(Enterpris Serializer for EnterpriseCourseEnrollment model with additional fields. """ - def to_representation(self, instance): - representation = super().to_representation(instance) - representation.update(self._get_additional_fields(instance)) - return representation - - def _get_additional_fields(self, instance): - """ - Return annotations with additional data for the queryset. - Additional fields are None in the test environment, where platform models are not available. - """ - - if not CourseEnrollment or not CourseOverview: - return { - 'enrollment_track': None, - 'enrollment_date': None, - 'user_email': None, - 'course_start': None, - 'course_end': None, - } - - user = auth.get_user_model().objects.filter( - id=instance.enterprise_customer_user.user_id, - ).first() - enrollment = CourseEnrollment.objects.filter( - user=user, - course_id=instance.course_id, - ).first() - course_overview = CourseOverview.objects.filter( - id=instance.course_id, - ).first() + class Meta: + model = models.EnterpriseCourseEnrollment + fields = ( + 'enterprise_customer_user', + 'course_id', + 'enterprise_customer_user', + 'course_id', + 'enrollment_date', + 'enrollment_track', + 'user_email', + 'course_start', + 'course_end', + ) - return { - 'enrollment_track': getattr(enrollment, 'mode', None), - 'enrollment_date': getattr(enrollment, 'created', None), - 'user_email': getattr(user, 'email', None), - 'course_start': getattr(course_overview, 'start', None), - 'course_end': getattr(course_overview, 'end', None), - } + enrollment_track = serializers.CharField() + enrollment_date = serializers.DateTimeField() + user_email = serializers.EmailField() + course_start = serializers.DateTimeField() + course_end = serializers.DateTimeField() class EnterpriseCourseEnrollmentWriteSerializer(serializers.ModelSerializer): diff --git a/enterprise/api/v1/views.py b/enterprise/api/v1/views.py index 4d2b046627..bcca5cdc2d 100644 --- a/enterprise/api/v1/views.py +++ b/enterprise/api/v1/views.py @@ -531,7 +531,7 @@ class EnterpriseCourseEnrollmentViewSet(EnterpriseReadWriteModelViewSet): API views for the ``enterprise-course-enrollment`` API endpoint. """ - queryset = models.EnterpriseCourseEnrollment.objects.all() + queryset = models.EnterpriseCourseEnrollment.with_additional_fields.all() filter_backends = (filters.OrderingFilter, DjangoFilterBackend, EnterpriseCourseEnrollmentFilterBackend) USER_ID_FILTER = 'enterprise_customer_user__user_id' diff --git a/enterprise/models.py b/enterprise/models.py index 498d93155f..cce24e4351 100644 --- a/enterprise/models.py +++ b/enterprise/models.py @@ -87,6 +87,11 @@ except ImportError: CourseEntitlement = None +try: + from openedx.core.djangoapps.content.course_overviews.models import CourseOverview +except ImportError: + CourseOverview = None + LOGGER = getLogger(__name__) User = auth.get_user_model() mark_safe_lazy = lazy(mark_safe, str) @@ -1786,6 +1791,54 @@ def get_queryset(self): enterprise_customer_user__linked=True ) +class EnterpriseCourseEnrollmentWithAdditionalFieldsManager(models.Manager): + """ + Model manager for `EnterpriseCourseEnrollment`. + """ + + def get_queryset(self): + """ + Override to return only those enrollment records for which learner is linked to an enterprise. + """ + + return super().get_queryset().select_related('enterprise_customer_user').filter( + enterprise_customer_user__linked=True + ).annotate(**self._get_additional_data_annotations()) + + def _get_additional_data_annotations(self): + """ + Return annotations with additional data for the queryset. + Additional fields are None in the test environment, where platform models are not available. + """ + + if not CourseEnrollment or not CourseOverview: + return { + 'enrollment_track': models.Value(None, output_field=models.CharField()), + 'enrollment_date': models.Value(None, output_field=models.DateTimeField()), + 'user_email': models.Value(None, output_field=models.EmailField()), + 'course_start': models.Value(None, output_field=models.DateTimeField()), + 'course_end': models.Value(None, output_field=models.DateTimeField()), + } + + enrollment_subquery = CourseEnrollment.objects.filter( + user=models.OuterRef('enterprise_customer_user__user_id'), + course_id=models.OuterRef('course_id'), + ) + user_subquery = auth.get_user_model().objects.filter( + id=models.OuterRef('enterprise_customer_user__user_id'), + ).values('email')[:1] + course_subquery = CourseOverview.objects.filter( + id=models.OuterRef('course_id'), + ) + + return { + 'enrollment_track': models.Subquery(enrollment_subquery.values('mode')[:1]), + 'enrollment_date': models.Subquery(enrollment_subquery.values('created')[:1]), + 'user_email': models.Subquery(user_subquery), + 'course_start': models.Subquery(course_subquery.values('start')[:1]), + 'course_end': models.Subquery(course_subquery.values('end')[:1]), + } + class EnterpriseCourseEnrollment(TimeStampedModel): """ @@ -1806,6 +1859,7 @@ class EnterpriseCourseEnrollment(TimeStampedModel): """ objects = EnterpriseCourseEnrollmentManager() + with_additional_fields = EnterpriseCourseEnrollmentWithAdditionalFieldsManager() class Meta: unique_together = (('enterprise_customer_user', 'course_id',),)