From dcc3f0d1095b93f6a005ccd20be8cecac2fa6db3 Mon Sep 17 00:00:00 2001 From: Chatewgne Date: Tue, 23 Jan 2024 11:46:33 +0100 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=20[REF]=20Refactor=20APIv2=20Outdoor?= =?UTF-8?q?=20Serializers=20(refs=20#3569)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- geotrek/api/tests/test_v2.py | 24 +++-- geotrek/api/v2/mixins.py | 36 +++++++ geotrek/api/v2/serializers.py | 182 ++++++---------------------------- 3 files changed, 86 insertions(+), 156 deletions(-) diff --git a/geotrek/api/tests/test_v2.py b/geotrek/api/tests/test_v2.py index 9a5f6712c1..eed2814217 100644 --- a/geotrek/api/tests/test_v2.py +++ b/geotrek/api/tests/test_v2.py @@ -4522,7 +4522,9 @@ def setUpTestData(cls): cls.course.parent_sites.set([cls.site.pk]) cls.course2 = outdoor_factory.CourseFactory() cls.course3 = outdoor_factory.CourseFactory() + cls.course4 = outdoor_factory.CourseFactory() outdoor_models.OrderedCourseChild.objects.create(parent=cls.course, child=cls.course2) + outdoor_models.OrderedCourseChild.objects.create(parent=cls.course, child=cls.course4, order=1) outdoor_models.OrderedCourseChild.objects.create(parent=cls.course3, child=cls.course) cls.information_desk = tourism_factory.InformationDeskFactory() cls.site.information_desks.set([cls.information_desk]) @@ -4548,14 +4550,24 @@ def test_course_serialized_parent_site_and_related_courses(self): children_courses_pk = response.json()['children'] self.assertEqual(parent_sites_pk, [self.site.pk]) self.assertEqual(parent_sites_uuid, [str(self.site.uuid)]) - self.assertEqual(parent_courses_pk, [{'order': 0, 'course': self.course3.pk}]) - self.assertEqual(parent_courses_uuid, [{'order': 0, 'course': str(self.course3.uuid)}]) - self.assertEqual(children_courses_pk, [{'order': 0, 'course': self.course2.pk}]) - self.assertEqual(children_courses_uuid, [{'order': 0, 'course': str(self.course2.uuid)}]) + self.assertEqual(parent_courses_pk, [self.course3.pk]) + self.assertEqual(parent_courses_uuid, [str(self.course3.uuid)]) + self.assertEqual(children_courses_pk, [self.course2.pk, self.course4.pk]) + self.assertEqual(children_courses_uuid, [str(self.course2.uuid), str(self.course4.uuid)]) response = self.get_course_detail(self.course.pk, params={'language': 'en'}) self.assertEqual(response.status_code, 200) - self.assertEqual(parent_courses_uuid, [{'order': 0, 'course': str(self.course3.uuid)}]) - self.assertEqual(children_courses_uuid, [{'order': 0, 'course': str(self.course2.uuid)}]) + parent_sites_pk = response.json()['sites'] + parent_sites_uuid = response.json()['sites_uuids'] + parent_courses_uuid = response.json()['parents_uuids'] + parent_courses_pk = response.json()['parents'] + children_courses_uuid = response.json()['children_uuids'] + children_courses_pk = response.json()['children'] + self.assertEqual(parent_sites_pk, [self.site.pk]) + self.assertEqual(parent_sites_uuid, [str(self.site.uuid)]) + self.assertEqual(parent_courses_pk, [self.course3.pk]) + self.assertEqual(parent_courses_uuid, [str(self.course3.uuid)]) + self.assertEqual(children_courses_pk, [self.course2.pk, self.course4.pk]) + self.assertEqual(children_courses_uuid, [str(self.course2.uuid), str(self.course4.uuid)]) def test_site_serialized_children_course(self): response = self.get_site_detail(self.site.pk) diff --git a/geotrek/api/v2/mixins.py b/geotrek/api/v2/mixins.py index 42867f99a0..6334fb67fb 100644 --- a/geotrek/api/v2/mixins.py +++ b/geotrek/api/v2/mixins.py @@ -1,6 +1,7 @@ from django.conf import settings from django.shortcuts import get_object_or_404 from django.urls import reverse +from modeltranslation.utils import build_localized_fieldname from geotrek.common import models as common_models @@ -32,3 +33,38 @@ def get_pdf_url(self, obj): for language in settings.MODELTRANSLATION_LANGUAGES: data[language] = self._get_pdf_url_lang(obj, language, portal) return data + + +class PublishedRelatedObjectsSerializerMixin: + + def get_values_on_published_related_objects(self, related_queryset, field): + """ + Retrieve values for `field` on objects from `related_queryset` only if they are published according to requested language + """ + request = self.context['request'] + language = request.GET.get('language') + if language: + published_by_lang = build_localized_fieldname('published', language) + return list(related_queryset.filter(**{published_by_lang: True}).values_list(field, flat=True)) + else: + all_values = [] + for item in related_queryset: + if getattr(item, "any_published"): + all_values.append(getattr(item, field)) + return all_values + + def get_value_on_published_related_object(self, related_object, field): + """ + Retrieve value for `field` on instance `related_object` only if it is published according to requested language + """ + value = None + request = self.context['request'] + language = request.GET.get('language') + if related_object: + if language: + if getattr(related_object, build_localized_fieldname('published', language)): + value = getattr(related_object, field) + else: + if related_object.published: + value = getattr(related_object, field) + return value diff --git a/geotrek/api/v2/serializers.py b/geotrek/api/v2/serializers.py index f8bcc392af..694c7c5df3 100644 --- a/geotrek/api/v2/serializers.py +++ b/geotrek/api/v2/serializers.py @@ -20,7 +20,7 @@ from rest_framework_gis import serializers as geo_serializers from geotrek.api.v2.functions import Length3D -from geotrek.api.v2.mixins import PDFSerializerMixin +from geotrek.api.v2.mixins import PDFSerializerMixin, PublishedRelatedObjectsSerializerMixin from geotrek.api.v2.utils import build_url, get_translation_or_dict from geotrek.authent import models as authent_models from geotrek.common import models as common_models @@ -1139,7 +1139,7 @@ class Meta: model = outdoor_models.Practice fields = ('id', 'name') - class SiteSerializer(PDFSerializerMixin, DynamicFieldsMixin, serializers.ModelSerializer): + class SiteSerializer(PDFSerializerMixin, DynamicFieldsMixin, PublishedRelatedObjectsSerializerMixin, serializers.ModelSerializer): url = HyperlinkedIdentityField(view_name='apiv2:site-detail') geometry = geo_serializers.GeometryField(read_only=True, source="geom_transformed", precision=7) attachments = AttachmentSerializer(many=True) @@ -1167,84 +1167,22 @@ def get_labels(self, obj): return [label.pk for label in obj.published_labels] def get_courses(self, obj): - courses = [] - request = self.context['request'] - language = request.GET.get('language') - for course in obj.children_courses.all(): - if language: - if getattr(course, build_localized_fieldname('published', language)): - courses.append(course.pk) - else: - if course.published: - courses.append(course.pk) - return courses + return self.get_values_on_published_related_objects(obj.children_courses.all(), 'pk') def get_courses_uuids(self, obj): - courses = [] - request = self.context['request'] - language = request.GET.get('language') - for course in obj.children_courses.all(): - if language: - if getattr(course, build_localized_fieldname('published', language)): - courses.append(course.uuid) - else: - if course.published: - courses.append(course.uuid) - return courses + return self.get_values_on_published_related_objects(obj.children_courses.all(), 'uuid') def get_parent(self, obj): - parent = None - request = self.context['request'] - language = request.GET.get('language') - if obj.parent: - if language: - if getattr(obj.parent, build_localized_fieldname('published', language)): - parent = obj.parent.pk - else: - if obj.parent.published: - parent = obj.parent.pk - return parent + return self.get_value_on_published_related_object(obj.parent, 'pk') def get_parent_uuid(self, obj): - parent = None - request = self.context['request'] - language = request.GET.get('language') - if obj.parent: - if language: - if getattr(obj.parent, build_localized_fieldname('published', language)): - parent = obj.parent.uuid - else: - if obj.parent.published: - parent = obj.parent.uuid - return parent + return self.get_value_on_published_related_object(obj.parent, 'uuid') def get_children(self, obj): - children = [] - request = self.context['request'] - language = request.GET.get('language') - if language: - for site in obj.get_children(): - if getattr(site, build_localized_fieldname('published', language)): - children.append(site.pk) - else: - for site in obj.get_children(): - if site.published: - children.append(site.pk) - return children + return self.get_values_on_published_related_objects(obj.get_children(), 'pk') def get_children_uuids(self, obj): - children = [] - request = self.context['request'] - language = request.GET.get('language') - if language: - for site in obj.get_children(): - if getattr(site, build_localized_fieldname('published', language)): - children.append(site.uuid) - else: - for site in obj.get_children(): - if site.published: - children.append(site.uuid) - return children + return self.get_values_on_published_related_objects(obj.get_children(), 'uuid') def get_sector(self, obj): if obj.practice and obj.practice.sector: @@ -1261,7 +1199,7 @@ class Meta: 'type', 'url', 'uuid', 'courses', 'courses_uuids', 'web_links', 'wind', ) - class CourseSerializer(PDFSerializerMixin, DynamicFieldsMixin, serializers.ModelSerializer): + class CourseSerializer(PDFSerializerMixin, DynamicFieldsMixin, PublishedRelatedObjectsSerializerMixin, serializers.ModelSerializer): url = HyperlinkedIdentityField(view_name='apiv2:course-detail') geometry = geo_serializers.GeometryField(read_only=True, source="geom_transformed", precision=7) children = serializers.SerializerMethodField() @@ -1298,97 +1236,41 @@ def get_gear(self, obj): def get_ratings_description(self, obj): return get_translation_or_dict('ratings_description', self, obj) - def get_sites(self, obj): - sites = [] + def get_values_on_published_related_ordered_course(self, ordered_course_queryset, related_course, field): + """ + Retrieve dict of values for `field` on objects from `ordered_course_queryset` only if they are published according to requested language + """ request = self.context['request'] language = request.GET.get('language') if language: - for site in obj.parent_sites.all(): - if getattr(site, build_localized_fieldname('published', language)): - sites.append(site.pk) + published_by_lang = f"{related_course}__{build_localized_fieldname('published', language)}" + all_values = ordered_course_queryset.filter(**{published_by_lang: True}).values_list(f"{related_course}__{field}", flat=True) + return list(all_values) else: - for site in obj.parent_sites.all(): - if getattr(site, "published"): - sites.append(site.pk) - return sites + all_values = [] + for item in ordered_course_queryset: + related_object = getattr(item, related_course) + if getattr(related_object, "any_published"): + all_values.append(getattr(related_object, field)) + return all_values + + def get_sites(self, obj): + return self.get_values_on_published_related_objects(obj.parent_sites.all(), 'pk') def get_children(self, obj): - courses = [] - request = self.context['request'] - language = request.GET.get('language') - if language: - for ordered_child in obj.course_children.order_by('order'): - course = ordered_child.child - if getattr(course, build_localized_fieldname('published', language)): - courses.append({'order': ordered_child.order, 'course': course.pk}) - else: - for ordered_child in obj.course_children.order_by('order'): - course = ordered_child.child - if getattr(course, "published"): - courses.append({'order': ordered_child.order, 'course': course.pk}) - return courses + return self.get_values_on_published_related_ordered_course(obj.course_children.order_by('order'), 'child', 'pk') def get_parents(self, obj): - courses = [] - request = self.context['request'] - language = request.GET.get('language') - if language: - for ordered_parent in obj.course_parents.order_by('order'): - course = ordered_parent.parent - if getattr(course, build_localized_fieldname('published', language)): - courses.append({'order': ordered_parent.order, 'course': course.pk}) - else: - for ordered_parent in obj.course_parents.order_by('order'): - course = ordered_parent.parent - if getattr(course, "published"): - courses.append({'order': ordered_parent.order, 'course': course.pk}) - return courses + return self.get_values_on_published_related_ordered_course(obj.course_parents.order_by('order'), 'parent', 'pk') + + def get_sites_uuids(self, obj): + return self.get_values_on_published_related_objects(obj.parent_sites.all(), 'uuid') def get_children_uuids(self, obj): - courses = [] - request = self.context['request'] - language = request.GET.get('language') - if language: - for ordered_child in obj.course_children.order_by('order'): - course = ordered_child.child - if getattr(course, build_localized_fieldname('published', language)): - courses.append({'order': ordered_child.order, 'course': course.uuid}) - else: - for ordered_child in obj.course_children.order_by('order'): - course = ordered_child.child - if getattr(course, "published"): - courses.append({'order': ordered_child.order, 'course': course.uuid}) - return courses + return self.get_values_on_published_related_ordered_course(obj.course_children.order_by('order'), 'child', 'uuid') def get_parents_uuids(self, obj): - courses = [] - request = self.context['request'] - language = request.GET.get('language') - if language: - for ordered_parent in obj.course_parents.order_by('order'): - course = ordered_parent.parent - if getattr(course, build_localized_fieldname('published', language)): - courses.append({'order': ordered_parent.order, 'course': course.uuid}) - else: - for ordered_parent in obj.course_parents.order_by('order'): - course = ordered_parent.parent - if getattr(course, "published"): - courses.append({'order': ordered_parent.order, 'course': course.uuid}) - return courses - - def get_sites_uuids(self, obj): - sites = [] - request = self.context['request'] - language = request.GET.get('language') - if language: - for site in obj.parent_sites.all(): - if getattr(site, build_localized_fieldname('published', language)): - sites.append(site.uuid) - else: - for site in obj.parent_sites.all(): - if getattr(site, "published"): - sites.append(site.uuid) - return sites + return self.get_values_on_published_related_ordered_course(obj.course_parents.order_by('order'), 'parent', 'uuid') def get_points_reference(self, obj): if not obj.points_reference: