Source code for fiction_outlines_api.serializers

import logging
from rest_framework import serializers
from django.utils.translation import gettext_lazy as _
from taggit_serializer.serializers import TaggitSerializer, TagListSerializerField
from fiction_outlines.models import Series, Character, Location, Outline
from fiction_outlines.models import CharacterInstance, LocationInstance, Arc
from fiction_outlines.models import ArcElementNode, StoryElementNode, MACE_TYPES


logger = logging.getLogger('fiction-outlines-api')

MOVE_POSITION_CHOICES = (
    ('first-child', 'first-child'),
    ('last-child', 'last-child'),
    ('first-sibling', 'first-sibling'),
    ('last-sibling', 'last-sibling'),
    ('left', 'left'),
    ('right', 'right'),
)


[docs]def convert_annotated_list(annotated_list, serializer_class): ''' Takes an annotated list and a serializer class and returns a version that is suitable for serialization. ''' converted_list = [] # pragma: no cover for item, info in annotated_list: converted_list.append((serializer_class(item).data, info)) return converted_list
[docs]class SeriesSerializer(TaggitSerializer, serializers.ModelSerializer): ''' Serializer for Series model. ''' tags = TagListSerializerField()
[docs] class Meta: # pragma: no cover model = Series fields = ('id', 'title', 'description', 'tags') read_only_fields = ('id',)
[docs]class CharacterInstanceSerializer(serializers.ModelSerializer): ''' Serializer for character instance. ''' name = serializers.CharField(read_only=True, source='character.name')
[docs] class Meta: # pragma: no cover model = CharacterInstance fields = ('id', 'outline', 'character', 'name', 'main_character', 'pov_character', 'protagonist', 'antagonist', 'obstacle', 'villain') read_only_fields = ('id', 'outline', 'character', 'name') extra_kwargs = {} for field in read_only_fields: extra_kwargs['field'] = {'required': False}
[docs]class LocationInstanceSerializer(serializers.ModelSerializer): ''' Serializer for location instance. ''' name = serializers.CharField(read_only=True, source='location.name')
[docs] class Meta: # pragma: no cover model = LocationInstance fields = ('id', 'location', 'name', 'outline') read_only_fields = ('id', 'location', 'name', 'outline') extra_kwargs = {} for field in read_only_fields: extra_kwargs['field'] = {'required': False}
[docs]class CharacterSerializer(TaggitSerializer, serializers.ModelSerializer): ''' Serializer for Character model. ''' tags = TagListSerializerField() series = serializers.PrimaryKeyRelatedField(many=True, allow_null=True, queryset=Series.objects.all()) character_instances = CharacterInstanceSerializer(many=True, read_only=True, required=False, source='characterinstance_set')
[docs] class Meta: # pragma: no cover model = Character fields = ('id', 'name', 'description', 'series', 'tags', 'character_instances') read_only_fields = ('id', 'character_instances')
[docs]class LocationSerializer(TaggitSerializer, serializers.ModelSerializer): ''' Serializer for Location model. ''' tags = TagListSerializerField() series = serializers.PrimaryKeyRelatedField(many=True, allow_null=True, queryset=Series.objects.all()) location_instances = LocationInstanceSerializer(many=True, read_only=True, required=False, source='locationinstance_set')
[docs] class Meta: # pragma: no cover model = Location fields = ('id', 'name', 'description', 'series', 'tags', 'location_instances') read_only_fields = ('id', 'location_instances')
[docs]class OutlineSerializer(TaggitSerializer, serializers.ModelSerializer): ''' Serializer for Outline model. Also provides ``outline_structure``, which is a treebeard annotated list of story element nodes. Special read-only fields: :attribute length_estimate: Auto calculated length (in words) based on the number of characters, locations, and arcs. :attribute arc_set: The :class:`fiction_outlines.models.Arc` objects associated with this outline. :attribute characterinstance_set: Character instances associated with this outline. :attribute locationinstance_set: Location instances associated with this outline. :attribute outline_structure: An annotated list of :class:`fiction_outlines.models.StoryElementNode` objects for visualizing the tree structure. ''' length_estimate = serializers.IntegerField(read_only=True, required=False, help_text=_("Autogenerated length estimate for the story in number of words.")) # noqa: E501 tags = TagListSerializerField() series = serializers.PrimaryKeyRelatedField(allow_null=True, queryset=Series.objects.all()) arc_set = serializers.PrimaryKeyRelatedField(many=True, required=False, read_only=True) characterinstance_set = serializers.PrimaryKeyRelatedField(many=True, required=False, read_only=True) locationinstance_set = serializers.PrimaryKeyRelatedField(many=True, required=False, read_only=True) outline_structure = serializers.SerializerMethodField(read_only=True, help_text=_("Annotated list of outline items."))
[docs] def get_outline_structure(self, obj): ''' Retrieves all :class:`fiction_outlines.StoryElementNode` objects associated with this outline, and returns it as an annotated list that can be serialized. :param obj: The outline object this serializer represents. :returns: An annotated list for serialization or an empty list. ''' logger.debug("Checking outline structure.") if obj.story_tree_root: logger.debug('Found a root node') annotated_list = StoryElementNode.get_annotated_list(obj.story_tree_root) logger.debug('Annotated list retrieved.') if len(annotated_list) > 1: # There is more than just a single root node: serialize and return. annotated_list = convert_annotated_list(annotated_list, StoryElementNodeSerializer) logger.debug("Returning results to field.") # pragma: no cover return annotated_list[1:] return []
[docs] class Meta: # pragma: no cover model = Outline fields = ('id', 'title', 'description', 'series', 'tags', 'length_estimate', 'arc_set', 'characterinstance_set', 'locationinstance_set', 'outline_structure') read_only_fields = ('id', 'length_estimate', 'arc_set', 'characterinstance_set', 'locationinstance_set', 'outline_structure')
[docs]class ArcSerializer(serializers.ModelSerializer): ''' Serializer for Arc model. To create an Arc, make sure to instead use the :class:`ArcCreateSerializer` and post it to :class:`fiction_outlines_api.views.ArcCreateView` ''' outline = serializers.PrimaryKeyRelatedField(read_only=True, required=False) current_errors = serializers.ReadOnlyField(read_only=True, required=False, help_text=_('dict current validation errors')) arc_structure = serializers.SerializerMethodField(read_only=True, help_text=_('Annotated list of arc elements.'))
[docs] def get_arc_structure(self, obj): ''' Fetches all the :class:`fiction_outlines.models.ArcElementNode` objects assocaited with this arc as an annotated list. :param obj: The arc this serializer represents. :returns: An annotated list ready to be serialized or an empty list. ''' logger.debug("Attempting to retrieve arc structure for arc %s" % obj.pk) if obj.arc_root_node: annotated_list = ArcElementNode.get_annotated_list(obj.arc_root_node) logger.debug("Retrieved annotated list") if len(annotated_list) > 1: # There is more than just a root node which we don't want to display to users. logger.debug("Arc structure found, builidng serialized structure.") annotated_list = convert_annotated_list(annotated_list, ArcElementNodeSerializer) logger.debug("Success serializing arc!") logger.debug("Arc looks like this:\n\n%s" % annotated_list[1:]) logger.debug("Returning result to field.") return annotated_list[1:] else: logger.debug("Only a root node... returning empty list.") return [] # pragma: no cover This is really unlikely to occur.
[docs] class Meta: # pragma: no cover model = Arc fields = ('id', 'name', 'mace_type', 'outline', 'name', 'current_errors', 'arc_structure') read_only_fields = ('id', 'outline', 'current_errors', 'arc_structure')
[docs]class ArcCreateSerializer(serializers.Serializer): ''' Serializer used for arc creation. You can't create an Arc using it's primary serializer. ''' mace_type = serializers.ChoiceField(choices=MACE_TYPES) name = serializers.CharField(max_length=255)
[docs]class ArcElementNodeSerializer(serializers.ModelSerializer): ''' Serializer for ArcElementNode. Special read-only attributes: :attribute is_milestone: Does this element represent a milestone in the :class:`Arc` :attribute milestone_seq: If a milestone, what is the proscribed sequence where it should appear in the context of the other milestones. :attribute parent_outline: Convenience reference to the parent outline object. :attribute headline: Automatically generated from the first line of the description. ''' arc = serializers.PrimaryKeyRelatedField(read_only=True, required=False) headline = serializers.ReadOnlyField(required=False, help_text=_('Auto generated from description')) story_element_node = serializers.PrimaryKeyRelatedField(required=False, allow_null=True, queryset=StoryElementNode.objects.all()) parent_outline = serializers.PrimaryKeyRelatedField(source='arc.outline', read_only=True, required=False) milestone_seq = serializers.IntegerField(allow_null=True, read_only=True, required=False, help_text=_('If a milestone, what order *should* it appear in?'))
[docs] class Meta: # pragma: no cover model = ArcElementNode fields = ('id', 'arc', 'arc_element_type', 'headline', 'description', 'story_element_node', 'assoc_characters', 'assoc_locations', 'milestone_seq', 'is_milestone', 'parent_outline') read_only_fields = ('id', 'arc', 'headline', 'milestone_seq', 'is_milestone', 'parent_outline')
[docs]class StoryElementNodeSerializer(serializers.ModelSerializer): ''' Serializer for StoryElementNode Two special fields here: :attribute all_characters: All characters associated with this node or its descendants. :attribute all_locations: All locations associated with this node of its descendants. ''' all_characters = CharacterInstanceSerializer(many=True, read_only=True, required=False, help_text=_('All characters associated with this node its descendants.')) # noqa: E501 all_locations = LocationInstanceSerializer(many=True, read_only=True, required=False, help_text=_('All locations associated with this node or its descendants.')) # noqa: E501 outline = serializers.PrimaryKeyRelatedField(read_only=True, required=False)
[docs] class Meta: # pragma: no cover model = StoryElementNode fields = ('id', 'story_element_type', 'name', 'description', 'outline', 'assoc_characters', 'assoc_locations', 'all_characters', 'all_locations', 'impact_rating') read_only_fields = ('all_characters', 'all_locations', 'impact_rating', 'outline', 'id')