Add `timer` field data to OpenAPI schema (#474)

* Add timer as an actual field on the duration serializer

This change enables the timer field to be part of the generated OpenAPI
schema.
This commit is contained in:
Christopher Charbonneau Wells 2022-06-06 06:47:57 -07:00 committed by GitHub
parent 5ab2fce0d0
commit 1a19f05130
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 72 additions and 43 deletions

View File

@ -1,29 +0,0 @@
# -*- coding: utf-8 -*-
from collections import OrderedDict
from rest_framework.response import Response
class TimerFieldSupportMixin:
def options(self, request, *args, **kwargs):
"""
Add information about the optional "timer" field.
"""
meta = self.metadata_class()
data = meta.determine_metadata(request, self)
post = data.get("actions").get("POST") # type: OrderedDict
post["timer"] = OrderedDict(
{
"type": "integer",
"required": False,
"read_only": False,
"label": "Timer",
"details": "ID for an existing Timer, may be used in place of the "
"`start`, `end`, and/or `child` fields. ",
}
)
details = "Required unless a value is provided in the `timer` field."
post["child"]["details"] = details
post["start"]["details"] = details
post["end"]["details"] = details
return Response(data)

View File

@ -39,16 +39,30 @@ class CoreModelWithDurationSerializer(CoreModelSerializer):
child = serializers.PrimaryKeyRelatedField(
allow_null=True,
allow_empty=True,
help_text="Required unless a Timer value is provided.",
queryset=models.Child.objects.all(),
required=False,
)
timer = serializers.PrimaryKeyRelatedField(
allow_null=True,
help_text="May be used in place of the Start, End, and/or Child values.",
queryset=models.Timer.objects.all(),
required=False,
write_only=True,
)
class Meta:
abstract = True
extra_kwargs = {
"start": {"required": False},
"end": {"required": False},
"start": {
"help_text": "Required unless a Timer value is provided.",
"required": False,
},
"end": {
"help_text": "Required unless a Timer value is provided.",
"required": False,
},
}
def validate(self, attrs):
@ -56,11 +70,12 @@ class CoreModelWithDurationSerializer(CoreModelSerializer):
# of "start" and "end" fields as well as "child" if it is set on the
# Timer entry.
timer = None
if "timer" in self.initial_data:
try:
timer = models.Timer.objects.get(pk=self.initial_data["timer"])
except models.Timer.DoesNotExist:
raise ValidationError({"timer": ["Timer does not exist."]})
if "timer" in attrs:
# Remove the "timer" attribute (super validation would fail as it
# is not a true field on the model).
timer = attrs["timer"]
attrs.pop("timer")
if timer.end:
end = timer.end
else:
@ -142,6 +157,7 @@ class FeedingSerializer(CoreModelWithDurationSerializer, TaggableSerializer):
"child",
"start",
"end",
"timer",
"duration",
"type",
"method",
@ -172,7 +188,17 @@ class NoteSerializer(CoreModelSerializer, TaggableSerializer):
class SleepSerializer(CoreModelWithDurationSerializer, TaggableSerializer):
class Meta(CoreModelWithDurationSerializer.Meta):
model = models.Sleep
fields = ("id", "child", "start", "end", "duration", "nap", "notes", "tags")
fields = (
"id",
"child",
"start",
"end",
"timer",
"duration",
"nap",
"notes",
"tags",
)
class TagSerializer(serializers.HyperlinkedModelSerializer):
@ -220,7 +246,16 @@ class TimerSerializer(CoreModelSerializer):
class TummyTimeSerializer(CoreModelWithDurationSerializer, TaggableSerializer):
class Meta(CoreModelWithDurationSerializer.Meta):
model = models.TummyTime
fields = ("id", "child", "start", "end", "duration", "milestone", "tags")
fields = (
"id",
"child",
"start",
"end",
"timer",
"duration",
"milestone",
"tags",
)
class UserSerializer(serializers.ModelSerializer):

View File

@ -6,7 +6,6 @@ from rest_framework.response import Response
from core import models
from . import serializers, filters
from .mixins import TimerFieldSupportMixin
class BMIViewSet(viewsets.ModelViewSet):
@ -37,7 +36,7 @@ class DiaperChangeViewSet(viewsets.ModelViewSet):
filterset_class = filters.DiaperChangeFilter
class FeedingViewSet(TimerFieldSupportMixin, viewsets.ModelViewSet):
class FeedingViewSet(viewsets.ModelViewSet):
queryset = models.Feeding.objects.all()
serializer_class = serializers.FeedingSerializer
filterset_class = filters.FeedingFilter
@ -67,7 +66,7 @@ class PumpingViewSet(viewsets.ModelViewSet):
filterset_class = filters.PumpingFilter
class SleepViewSet(TimerFieldSupportMixin, viewsets.ModelViewSet):
class SleepViewSet(viewsets.ModelViewSet):
queryset = models.Sleep.objects.all()
serializer_class = serializers.SleepSerializer
filterset_class = filters.SleepFilter
@ -104,7 +103,7 @@ class TimerViewSet(viewsets.ModelViewSet):
return Response(self.serializer_class(timer).data)
class TummyTimeViewSet(TimerFieldSupportMixin, viewsets.ModelViewSet):
class TummyTimeViewSet(viewsets.ModelViewSet):
queryset = models.TummyTime.objects.all()
serializer_class = serializers.TummyTimeSerializer
filterset_class = filters.TummyTimeFilter

View File

@ -4684,12 +4684,20 @@ components:
child:
type: integer
nullable: true
description: Required unless a Timer value is provided.
start:
type: string
format: date-time
description: Required unless a Timer value is provided.
end:
type: string
format: date-time
description: Required unless a Timer value is provided.
timer:
type: integer
writeOnly: true
nullable: true
description: May be used in place of the Start, End, and/or Child values.
duration:
type: string
readOnly: true
@ -4809,12 +4817,20 @@ components:
child:
type: integer
nullable: true
description: Required unless a Timer value is provided.
start:
type: string
format: date-time
description: Required unless a Timer value is provided.
end:
type: string
format: date-time
description: Required unless a Timer value is provided.
timer:
type: integer
writeOnly: true
nullable: true
description: May be used in place of the Start, End, and/or Child values.
duration:
type: string
readOnly: true
@ -4905,12 +4921,20 @@ components:
child:
type: integer
nullable: true
description: Required unless a Timer value is provided.
start:
type: string
format: date-time
description: Required unless a Timer value is provided.
end:
type: string
format: date-time
description: Required unless a Timer value is provided.
timer:
type: integer
writeOnly: true
nullable: true
description: May be used in place of the Start, End, and/or Child values.
duration:
type: string
readOnly: true