mybuddy/api/serializers.py

236 lines
7.0 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
from copy import deepcopy
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from django.contrib.auth.models import User
from django.utils import timezone
2022-04-04 01:41:01 +00:00
from taggit.serializers import TagListSerializerField
2022-02-15 09:13:35 +00:00
2017-11-10 02:15:09 +00:00
from core import models
2017-08-13 14:48:16 +00:00
class CoreModelSerializer(serializers.HyperlinkedModelSerializer):
"""
Provide the child link (used by most core models) and run model clean()
methods during POST operations.
"""
2022-02-10 00:00:30 +00:00
child = serializers.PrimaryKeyRelatedField(queryset=models.Child.objects.all())
def validate(self, attrs):
# Ensure that all instance data is available for partial updates to
# support clean methods that compare multiple fields.
if self.partial:
new_instance = deepcopy(self.instance)
for attr, value in attrs.items():
setattr(new_instance, attr, value)
else:
new_instance = self.Meta.model(**attrs)
new_instance.clean()
return attrs
class CoreModelWithDurationSerializer(CoreModelSerializer):
"""
Specific serializer base for models with a "start" and "end" field.
"""
2022-02-10 00:00:30 +00:00
child = serializers.PrimaryKeyRelatedField(
2022-02-10 00:00:30 +00:00
allow_null=True,
allow_empty=True,
queryset=models.Child.objects.all(),
required=False,
)
class Meta:
abstract = True
extra_kwargs = {
2022-02-10 00:00:30 +00:00
"start": {"required": False},
"end": {"required": False},
}
def validate(self, attrs):
# Check for a special "timer" data argument that can be used in place
# of "start" and "end" fields as well as "child" if it is set on the
# Timer entry.
timer = None
2022-02-10 00:00:30 +00:00
if "timer" in self.initial_data:
try:
2022-02-10 00:00:30 +00:00
timer = models.Timer.objects.get(pk=self.initial_data["timer"])
except models.Timer.DoesNotExist:
2022-02-10 00:00:30 +00:00
raise ValidationError({"timer": ["Timer does not exist."]})
if timer.end:
end = timer.end
else:
end = timezone.now()
if timer.child:
2022-02-10 00:00:30 +00:00
attrs["child"] = timer.child
# Overwrites values provided directly!
2022-02-10 00:00:30 +00:00
attrs["start"] = timer.start
attrs["end"] = end
# The "child", "start", and "end" field should all be set at this
# point. If one is not, model validation will fail because they are
# required fields at the model level.
if not self.partial:
errors = {}
2022-02-10 00:00:30 +00:00
for field in ["child", "start", "end"]:
if field not in attrs or not attrs[field]:
2022-02-10 00:00:30 +00:00
errors[field] = "This field is required."
if len(errors) > 0:
raise ValidationError(errors)
attrs = super().validate(attrs)
# Only actually stop the timer if all validation passed.
if timer:
2022-02-10 00:00:30 +00:00
timer.stop(attrs["end"])
return attrs
2022-04-04 01:41:01 +00:00
class TaggableSerializer(serializers.HyperlinkedModelSerializer):
tags = TagListSerializerField(required=False)
2022-05-27 22:39:25 +00:00
class BMISerializer(CoreModelSerializer, TaggableSerializer):
class Meta:
2022-05-27 22:39:25 +00:00
model = models.BMI
fields = ("id", "child", "bmi", "date", "notes", "tags")
extra_kwargs = {
"core.BMI.bmi": {"label": "BMI"},
}
2022-03-04 15:39:13 +00:00
class PumpingSerializer(CoreModelSerializer):
class Meta:
2022-03-04 15:39:13 +00:00
model = models.Pumping
fields = ("id", "child", "amount", "time", "notes")
2017-08-16 12:49:58 +00:00
class ChildSerializer(serializers.HyperlinkedModelSerializer):
2017-08-13 14:48:16 +00:00
class Meta:
2017-11-10 02:15:09 +00:00
model = models.Child
2022-02-10 00:00:30 +00:00
fields = ("id", "first_name", "last_name", "birth_date", "slug", "picture")
lookup_field = "slug"
2017-08-13 14:48:16 +00:00
2022-04-04 01:41:01 +00:00
class DiaperChangeSerializer(CoreModelSerializer, TaggableSerializer):
2017-08-13 19:51:25 +00:00
class Meta:
2017-11-10 02:15:09 +00:00
model = models.DiaperChange
2022-04-04 01:41:01 +00:00
fields = (
"id",
"child",
"time",
"wet",
"solid",
"color",
"amount",
"notes",
"tags",
)
2017-08-13 19:51:25 +00:00
2022-04-04 01:41:01 +00:00
class FeedingSerializer(CoreModelWithDurationSerializer, TaggableSerializer):
class Meta(CoreModelWithDurationSerializer.Meta):
2017-11-10 02:15:09 +00:00
model = models.Feeding
2022-02-10 00:00:30 +00:00
fields = (
"id",
"child",
"start",
"end",
"duration",
"type",
"method",
"amount",
"notes",
2022-04-04 01:41:01 +00:00
"tags",
2022-02-10 00:00:30 +00:00
)
2017-08-13 15:59:14 +00:00
2022-05-27 22:39:25 +00:00
class HeadCircumferenceSerializer(CoreModelSerializer, TaggableSerializer):
class Meta:
model = models.HeadCircumference
fields = ("id", "child", "head_circumference", "date", "notes", "tags")
class HeightSerializer(CoreModelSerializer, TaggableSerializer):
class Meta:
model = models.Height
fields = ("id", "child", "height", "date", "notes", "tags")
2022-04-04 01:41:01 +00:00
class NoteSerializer(CoreModelSerializer, TaggableSerializer):
2017-08-13 20:48:16 +00:00
class Meta:
2017-11-10 02:15:09 +00:00
model = models.Note
2022-02-15 09:13:35 +00:00
fields = ("id", "child", "note", "time", "tags")
2022-04-04 01:41:01 +00:00
class SleepSerializer(CoreModelWithDurationSerializer, TaggableSerializer):
class Meta(CoreModelWithDurationSerializer.Meta):
2017-11-10 02:15:09 +00:00
model = models.Sleep
2022-04-04 01:41:01 +00:00
fields = ("id", "child", "start", "end", "duration", "nap", "notes", "tags")
2017-08-13 15:59:14 +00:00
2022-05-27 22:39:25 +00:00
class TagSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = models.Tag
fields = ("slug", "name", "color", "last_used")
extra_kwargs = {
"slug": {"required": False, "read_only": True},
"color": {"required": False},
"last_used": {"required": False, "read_only": True},
}
2022-04-04 01:41:01 +00:00
class TemperatureSerializer(CoreModelSerializer, TaggableSerializer):
2019-05-17 05:13:14 +00:00
class Meta:
model = models.Temperature
2022-04-04 01:41:01 +00:00
fields = ("id", "child", "temperature", "time", "notes", "tags")
2019-05-17 05:13:14 +00:00
class TimerSerializer(CoreModelSerializer):
child = serializers.PrimaryKeyRelatedField(
2022-02-10 00:00:30 +00:00
allow_null=True,
allow_empty=True,
queryset=models.Child.objects.all(),
required=False,
)
user = serializers.PrimaryKeyRelatedField(
2022-02-10 00:00:30 +00:00
allow_null=True, allow_empty=True, queryset=User.objects.all(), required=False
)
class Meta:
2017-11-10 02:15:09 +00:00
model = models.Timer
2022-02-10 00:00:30 +00:00
fields = ("id", "child", "name", "start", "end", "duration", "active", "user")
def validate(self, attrs):
attrs = super(TimerSerializer, self).validate(attrs)
# Set user to current user if no value is provided.
2022-02-10 00:00:30 +00:00
if "user" not in attrs or attrs["user"] is None:
attrs["user"] = self.context["request"].user
return attrs
2022-04-04 01:41:01 +00:00
class TummyTimeSerializer(CoreModelWithDurationSerializer, TaggableSerializer):
class Meta(CoreModelWithDurationSerializer.Meta):
2017-11-10 02:15:09 +00:00
model = models.TummyTime
2022-04-04 01:41:01 +00:00
fields = ("id", "child", "start", "end", "duration", "milestone", "tags")
2017-11-10 02:15:09 +00:00
2022-05-27 22:39:25 +00:00
class UserSerializer(serializers.ModelSerializer):
class Meta:
2022-05-27 22:39:25 +00:00
model = User
fields = ("id", "username")
2022-02-15 21:24:13 +00:00
2022-02-27 19:36:31 +00:00
2022-05-27 22:39:25 +00:00
class WeightSerializer(CoreModelSerializer, TaggableSerializer):
2022-02-15 21:24:13 +00:00
class Meta:
2022-05-27 22:39:25 +00:00
model = models.Weight
fields = ("id", "child", "weight", "date", "notes", "tags")