Skip to content

Commit

Permalink
♻ [REF] Refactor APIv2 Outdoor Serializers (refs #3569)
Browse files Browse the repository at this point in the history
  • Loading branch information
Chatewgne committed Jan 23, 2024
1 parent 7888b93 commit dcc3f0d
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 156 deletions.
24 changes: 18 additions & 6 deletions geotrek/api/tests/test_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand All @@ -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)
Expand Down
36 changes: 36 additions & 0 deletions geotrek/api/v2/mixins.py
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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
182 changes: 32 additions & 150 deletions geotrek/api/v2/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand All @@ -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()
Expand Down Expand Up @@ -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:
Expand Down

0 comments on commit dcc3f0d

Please sign in to comment.