2017-08-13 13:44:48 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
2020-03-14 03:00:32 +00:00
|
|
|
from copy import deepcopy
|
2017-08-13 13:44:48 +00:00
|
|
|
from rest_framework import serializers
|
2020-03-14 05:17:24 +00:00
|
|
|
from rest_framework.exceptions import ValidationError
|
2017-08-13 13:44:48 +00:00
|
|
|
|
2023-02-06 14:59:57 +00:00
|
|
|
from django.contrib.auth import get_user_model
|
2020-03-14 05:17:24 +00:00
|
|
|
from django.utils import timezone
|
2017-10-21 21:35:34 +00:00
|
|
|
|
2022-06-28 13:52:29 +00:00
|
|
|
from taggit.serializers import TagListSerializerField, TaggitSerializer
|
2022-02-15 09:13:35 +00:00
|
|
|
|
2017-11-10 02:15:09 +00:00
|
|
|
from core import models
|
2022-08-25 08:15:09 +00:00
|
|
|
from babybuddy import models as babybuddy_models
|
2017-08-13 14:48:16 +00:00
|
|
|
|
|
|
|
|
2017-12-05 21:31:37 +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())
|
2017-12-05 21:31:37 +00:00
|
|
|
|
|
|
|
def validate(self, attrs):
|
2020-03-14 03:00:32 +00:00
|
|
|
# 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()
|
2017-12-05 21:31:37 +00:00
|
|
|
return attrs
|
|
|
|
|
|
|
|
|
2020-03-14 05:17:24 +00:00
|
|
|
class CoreModelWithDurationSerializer(CoreModelSerializer):
|
|
|
|
"""
|
|
|
|
Specific serializer base for models with a "start" and "end" field.
|
|
|
|
"""
|
2022-02-10 00:00:30 +00:00
|
|
|
|
2020-03-14 05:17:24 +00:00
|
|
|
child = serializers.PrimaryKeyRelatedField(
|
2022-02-10 00:00:30 +00:00
|
|
|
allow_null=True,
|
2022-06-06 13:47:57 +00:00
|
|
|
help_text="Required unless a Timer value is provided.",
|
2022-02-10 00:00:30 +00:00
|
|
|
queryset=models.Child.objects.all(),
|
|
|
|
required=False,
|
|
|
|
)
|
2020-03-14 05:17:24 +00:00
|
|
|
|
2022-06-06 13:47:57 +00:00
|
|
|
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,
|
|
|
|
)
|
|
|
|
|
2020-03-14 05:17:24 +00:00
|
|
|
class Meta:
|
|
|
|
abstract = True
|
|
|
|
extra_kwargs = {
|
2022-06-06 13:47:57 +00:00
|
|
|
"start": {
|
|
|
|
"help_text": "Required unless a Timer value is provided.",
|
|
|
|
"required": False,
|
|
|
|
},
|
|
|
|
"end": {
|
|
|
|
"help_text": "Required unless a Timer value is provided.",
|
|
|
|
"required": False,
|
|
|
|
},
|
2020-03-14 05:17:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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-06-06 13:47:57 +00:00
|
|
|
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")
|
|
|
|
|
2020-03-14 20:24:00 +00:00
|
|
|
if timer.child:
|
2022-02-10 00:00:30 +00:00
|
|
|
attrs["child"] = timer.child
|
2020-03-14 05:17:24 +00:00
|
|
|
|
|
|
|
# Overwrites values provided directly!
|
2022-02-10 00:00:30 +00:00
|
|
|
attrs["start"] = timer.start
|
2022-08-14 20:55:57 +00:00
|
|
|
attrs["end"] = timezone.now()
|
2020-03-14 05:17:24 +00:00
|
|
|
|
|
|
|
# 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"]:
|
2020-03-14 05:17:24 +00:00
|
|
|
if field not in attrs or not attrs[field]:
|
2022-02-10 00:00:30 +00:00
|
|
|
errors[field] = "This field is required."
|
2020-03-14 05:17:24 +00:00
|
|
|
if len(errors) > 0:
|
|
|
|
raise ValidationError(errors)
|
|
|
|
|
|
|
|
attrs = super().validate(attrs)
|
|
|
|
|
|
|
|
# Only actually stop the timer if all validation passed.
|
|
|
|
if timer:
|
2022-08-14 20:55:57 +00:00
|
|
|
timer.stop()
|
2020-03-14 05:17:24 +00:00
|
|
|
|
|
|
|
return attrs
|
|
|
|
|
|
|
|
|
2022-06-28 13:52:29 +00:00
|
|
|
class TaggableSerializer(TaggitSerializer, serializers.HyperlinkedModelSerializer):
|
2022-04-04 01:41:01 +00:00
|
|
|
tags = TagListSerializerField(required=False)
|
|
|
|
|
|
|
|
|
2022-05-27 22:39:25 +00:00
|
|
|
class BMISerializer(CoreModelSerializer, TaggableSerializer):
|
2017-10-21 21:35:34 +00:00
|
|
|
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"},
|
|
|
|
}
|
2017-10-21 21:35:34 +00:00
|
|
|
|
|
|
|
|
2023-01-29 14:38:54 +00:00
|
|
|
class PumpingSerializer(CoreModelSerializer, TaggableSerializer):
|
2022-03-03 03:00:56 +00:00
|
|
|
class Meta:
|
2022-03-04 15:39:13 +00:00
|
|
|
model = models.Pumping
|
2023-07-02 16:18:34 +00:00
|
|
|
fields = ("id", "child", "amount", "start", "end", "duration", "notes", "tags")
|
2022-03-03 03:00:56 +00:00
|
|
|
|
|
|
|
|
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
|
|
|
|
2017-08-17 16:17:51 +00:00
|
|
|
|
2022-04-04 01:41:01 +00:00
|
|
|
class FeedingSerializer(CoreModelWithDurationSerializer, TaggableSerializer):
|
2020-03-14 05:17:24 +00:00
|
|
|
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",
|
2022-06-06 13:47:57 +00:00
|
|
|
"timer",
|
2022-02-10 00:00:30 +00:00
|
|
|
"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")
|
|
|
|
|
2017-08-17 16:17:51 +00:00
|
|
|
|
2022-04-04 01:41:01 +00:00
|
|
|
class SleepSerializer(CoreModelWithDurationSerializer, TaggableSerializer):
|
2023-06-15 03:01:49 +00:00
|
|
|
nap = serializers.BooleanField(allow_null=True, default=None, required=False)
|
|
|
|
|
2020-03-14 05:17:24 +00:00
|
|
|
class Meta(CoreModelWithDurationSerializer.Meta):
|
2017-11-10 02:15:09 +00:00
|
|
|
model = models.Sleep
|
2022-06-06 13:47:57 +00:00
|
|
|
fields = (
|
|
|
|
"id",
|
|
|
|
"child",
|
|
|
|
"start",
|
|
|
|
"end",
|
|
|
|
"timer",
|
|
|
|
"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
|
|
|
|
|
|
|
|
2017-12-05 21:31:37 +00:00
|
|
|
class TimerSerializer(CoreModelSerializer):
|
2020-01-30 21:55:33 +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,
|
|
|
|
)
|
2020-06-19 21:23:43 +00:00
|
|
|
user = serializers.PrimaryKeyRelatedField(
|
2023-02-08 04:29:15 +00:00
|
|
|
allow_null=True,
|
|
|
|
allow_empty=True,
|
|
|
|
queryset=get_user_model().objects.all(),
|
|
|
|
required=False,
|
2022-02-10 00:00:30 +00:00
|
|
|
)
|
2022-08-14 20:55:57 +00:00
|
|
|
duration = serializers.DurationField(read_only=True, required=False)
|
2017-10-21 21:35:34 +00:00
|
|
|
|
2017-08-16 22:33:02 +00:00
|
|
|
class Meta:
|
2017-11-10 02:15:09 +00:00
|
|
|
model = models.Timer
|
2022-08-14 20:55:57 +00:00
|
|
|
fields = ("id", "child", "name", "start", "duration", "user")
|
2017-08-16 22:33:02 +00:00
|
|
|
|
2020-06-19 21:23:43 +00:00
|
|
|
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
|
2020-06-19 21:23:43 +00:00
|
|
|
|
|
|
|
return attrs
|
|
|
|
|
2017-08-16 22:33:02 +00:00
|
|
|
|
2022-04-04 01:41:01 +00:00
|
|
|
class TummyTimeSerializer(CoreModelWithDurationSerializer, TaggableSerializer):
|
2020-03-14 05:17:24 +00:00
|
|
|
class Meta(CoreModelWithDurationSerializer.Meta):
|
2017-11-10 02:15:09 +00:00
|
|
|
model = models.TummyTime
|
2022-06-06 13:47:57 +00:00
|
|
|
fields = (
|
|
|
|
"id",
|
|
|
|
"child",
|
|
|
|
"start",
|
|
|
|
"end",
|
|
|
|
"timer",
|
|
|
|
"duration",
|
|
|
|
"milestone",
|
|
|
|
"tags",
|
|
|
|
)
|
2017-11-10 02:15:09 +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")
|
2022-08-25 08:15:09 +00:00
|
|
|
|
|
|
|
|
2022-09-05 21:00:03 +00:00
|
|
|
class UserSerializer(serializers.ModelSerializer):
|
|
|
|
class Meta:
|
2023-02-06 14:59:57 +00:00
|
|
|
model = get_user_model()
|
2022-09-05 21:00:03 +00:00
|
|
|
fields = (
|
|
|
|
"id",
|
|
|
|
"username",
|
|
|
|
"first_name",
|
|
|
|
"last_name",
|
|
|
|
"email",
|
|
|
|
"is_staff",
|
|
|
|
)
|
|
|
|
extra_kwargs = {k: {"read_only": True} for k in fields}
|
|
|
|
|
|
|
|
|
2022-08-25 08:15:09 +00:00
|
|
|
class ProfileSerializer(serializers.ModelSerializer):
|
2022-09-05 21:00:03 +00:00
|
|
|
user = UserSerializer(many=False)
|
2022-08-25 09:46:12 +00:00
|
|
|
api_key = serializers.SerializerMethodField("get_api_key")
|
|
|
|
|
|
|
|
def get_api_key(self, value):
|
|
|
|
return self.instance.api_key().key
|
|
|
|
|
2022-08-25 08:15:09 +00:00
|
|
|
class Meta:
|
|
|
|
model = babybuddy_models.Settings
|
2022-08-25 09:46:12 +00:00
|
|
|
fields = (
|
|
|
|
"user",
|
|
|
|
"language",
|
|
|
|
"timezone",
|
|
|
|
"api_key",
|
|
|
|
)
|
|
|
|
extra_kwargs = {k: {"read_only": True} for k in fields}
|