From 7762a7df42e63a7b93b4ac97801233c19abf9a7e Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Tue, 22 Mar 2016 09:52:40 +0200 Subject: [PATCH] Implement and use an IOError ignoring ManyRelatedField for images --- democracy/views/hearing.py | 6 +++++- democracy/views/section.py | 6 ++++-- democracy/views/utils.py | 24 ++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/democracy/views/hearing.py b/democracy/views/hearing.py index 6d9064e6..759d9d21 100644 --- a/democracy/views/hearing.py +++ b/democracy/views/hearing.py @@ -13,6 +13,7 @@ from democracy.views.hearing_comment import HearingCommentSerializer from democracy.views.label import LabelSerializer from democracy.views.section import SectionFieldSerializer +from democracy.views.utils import IOErrorIgnoringManyRelatedField from .hearing_report import HearingReport @@ -42,7 +43,10 @@ def get_queryset(self): class HearingSerializer(serializers.ModelSerializer): labels = LabelSerializer(many=True, read_only=True) - images = HearingImageSerializer.get_field_serializer(many=True, read_only=True) + images = HearingImageSerializer.get_field_serializer( + many=True, read_only=True, + many_field_class=IOErrorIgnoringManyRelatedField + ) sections = serializers.SerializerMethodField() comments = HearingCommentSerializer.get_field_serializer(many=True, read_only=True) commenting = EnumField(enum_type=Commenting) diff --git a/democracy/views/section.py b/democracy/views/section.py index 8f6b0df0..dabcb840 100644 --- a/democracy/views/section.py +++ b/democracy/views/section.py @@ -4,10 +4,10 @@ from democracy.models import Hearing, Section, SectionImage from democracy.utils.drf_enum_field import EnumField from democracy.views.base import AdminsSeeUnpublishedMixin, BaseImageSerializer +from democracy.views.utils import IOErrorIgnoringManyRelatedField class SectionImageSerializer(BaseImageSerializer): - class Meta: model = SectionImage fields = ['title', 'url', 'width', 'height', 'caption'] @@ -17,7 +17,9 @@ class SectionSerializer(serializers.ModelSerializer): """ Serializer for section instance. """ - images = SectionImageSerializer.get_field_serializer(many=True, read_only=True) + images = SectionImageSerializer.get_field_serializer( + many=True, read_only=True, many_field_class=IOErrorIgnoringManyRelatedField + ) type = serializers.SlugRelatedField(slug_field='identifier', read_only=True) type_name_singular = serializers.SlugRelatedField(source='type', slug_field='name_singular', read_only=True) type_name_plural = serializers.SlugRelatedField(source='type', slug_field='name_plural', read_only=True) diff --git a/democracy/views/utils.py b/democracy/views/utils.py index 7708d4a6..487032e6 100644 --- a/democracy/views/utils.py +++ b/democracy/views/utils.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from functools import lru_cache +from django.db.models.query import QuerySet from rest_framework import serializers from rest_framework.relations import ManyRelatedField, MANY_RELATION_KWARGS @@ -35,3 +36,26 @@ def get_field_serializer_class(cls, many_field_class=ManyRelatedField): def get_field_serializer(cls, **kwargs): many_field_class = kwargs.pop("many_field_class", ManyRelatedField) return cls.get_field_serializer_class(many_field_class=many_field_class)(**kwargs) + + +class IOErrorIgnoringManyRelatedField(ManyRelatedField): + """ + A ManyRelatedField that ignores IOErrors occurring during iterating the children. + + This is mainly useful for images that are referenced in the database but do not exist + on the server (where constructing them requires accessing them to populate the width + and height fields). + """ + def to_representation(self, iterable): + out = [] + if isinstance(iterable, QuerySet): + iterable = iterable.iterator() + while True: + try: + value = next(iterable) + out.append(self.child_relation.to_representation(value)) + except StopIteration: + break + except IOError: + continue + return out