Files
digest_app/module_activity/api/serializers.py

495 lines
16 KiB
Python

import math
import os
from datetime import datetime
from django.conf import settings
from django.utils import timezone
from rest_framework import serializers
from module_iam.models import IAmPrincipal
from ..models import (
BeverageRecord,
Bowel,
ChronicCondition,
FoodIngredientRecord,
FoodIngredintDataset,
FoodRecord,
Intolerance,
MealRecord,
MealSymptomRecord,
Medication,
Medicine,
PastTreatment,
PrincipalHealthData,
Symptoms,
SymptomTypeAfterMeal,
SymptomTypeBeforeMeal,
)
class FoodDatasetSerializer(serializers.ModelSerializer):
class Meta:
model = FoodIngredintDataset
fields = ["id", "food_name"]
class FoodIngredientDatasetSerializer(serializers.ModelSerializer):
class Meta:
model = FoodIngredintDataset
fields = ['id', 'food_name', 'ingredients']
class IAmPrincipalSerializer(serializers.ModelSerializer):
class Meta:
model = IAmPrincipal
fields = [
"profile_photo",
"first_name",
"date_of_birth",
"gender",
"phone_no",
]
class PrincipalHealthDataSerializer(serializers.ModelSerializer):
weight = serializers.DecimalField(max_digits=5, decimal_places=2, read_only=True)
height = serializers.DecimalField(max_digits=6, decimal_places=2, read_only=True)
class Meta:
model = PrincipalHealthData
fields = [
"ethenicity",
"weight",
"weight_unit",
"height",
"height_unit",
"gastrointestinal_health",
"exercise_frequency",
"sleep_duration",
"eat_frequency",
]
class PrincipalAndHealthSerializer(serializers.ModelSerializer):
ethenicity = serializers.CharField(read_only=True)
weight = serializers.DecimalField(max_digits=5, decimal_places=2, read_only=True)
weight_unit = serializers.CharField(max_length=10, read_only=True)
height = serializers.DecimalField(max_digits=6, decimal_places=2, read_only=True)
height_unit = serializers.CharField(max_length=10, read_only=True)
gastrointestinal_health = serializers.CharField(read_only=True)
exercise_frequency = serializers.CharField(read_only=True)
sleep_duration = serializers.CharField(read_only=True)
eat_frequency = serializers.CharField(read_only=True)
profile_complete = serializers.IntegerField(read_only=True)
class Meta:
model = IAmPrincipal
fields = [
"profile_photo",
"first_name",
"email",
"date_of_birth",
"gender",
"phone_no",
# "phone_verified",
# "email_verified",
"ethenicity",
"weight",
"weight_unit",
"height",
"height_unit",
"gastrointestinal_health",
"exercise_frequency",
"sleep_duration",
"eat_frequency",
"profile_complete",
]
def calculate_profile_completion(self, user):
"""
Calculates the profile completion percentage for a user based on the required fields.
"""
fields = [
"profile_photo",
"first_name",
"email",
"date_of_birth",
"gender",
"phone_no",
"ethenicity",
"weight",
"height",
"gastrointestinal_health",
"exercise_frequency",
"sleep_duration",
"eat_frequency",
]
try:
# Retrieve the user profile from the database
profile = IAmPrincipal.objects.get(id=user)
try:
# Retrieve the user's health data from the database
health_data = PrincipalHealthData.objects.get(principal=profile)
except PrincipalHealthData.DoesNotExist:
# If health data doesn't exist, set health_data to None
health_data = None
# Initialize a counter for completed fields
completed_fields = sum(
1
for field in fields
if (
# If the field is in the user profile and the field value is not None, not an empty string, and not an instance of datetime.date
(
field in vars(profile)
and vars(profile).get(field, "")
and vars(profile).get(field) != datetime.date
)
or
# If health data exists, the field is in the user's health data, and the field value is not None, not an empty string, and not an instance of datetime.date
(
health_data
and field in vars(health_data)
and vars(health_data).get(field, "")
and vars(health_data).get(field) != datetime.date
)
)
)
except IAmPrincipal.DoesNotExist:
# If the user profile doesn't exist, return 0
return 0
# Calculate the total number of fields
total_fields = len(fields)
# Calculate the profile completion percentage
completion_percentage = math.floor((completed_fields / total_fields) * 100)
# Return the profile completion percentage
return completion_percentage
def get_image_url(self, obj, field_name, request):
image_field = getattr(obj, field_name)
if image_field:
return request.build_absolute_uri(image_field.url)
else:
# Return the URL of the default image from the static path
default_image_path = os.path.join(
settings.STATIC_URL, "img/default_profile.jpg"
)
return request.build_absolute_uri(default_image_path)
def to_representation(self, instance):
data = super().to_representation(instance)
request = self.context.get("request")
data["profile_photo"] = self.get_image_url(instance, "profile_photo", request)
data["profile_complete"] = self.calculate_profile_completion(request.user.id)
if (
hasattr(instance, "health_data_principal")
and instance.health_data_principal
):
health_data = instance.health_data_principal
data["ethenicity"] = health_data.ethenicity
data["weight"] = health_data.weight
data["weight_unit"] = health_data.weight_unit
data["height"] = health_data.height
data["height_unit"] = health_data.height_unit
data["gastrointestinal_health"] = health_data.gastrointestinal_health
data["exercise_frequency"] = health_data.exercise_frequency
data["sleep_duration"] = health_data.sleep_duration
data["eat_frequency"] = health_data.eat_frequency
else:
# If health_data_principal doesn't exist or is empty, set empty strings for all attributes
data["ethenicity"] = ""
data["weight"] = 0.00
data["weight_unit"] = "kg"
data["height"] = 0.00
data["height_unit"] = "cm"
data["gastrointestinal_health"] = ""
data["exercise_frequency"] = ""
data["sleep_duration"] = ""
data["eat_frequency"] = ""
return data
class IntoleranceSerializer(serializers.ModelSerializer):
class Meta:
model = Intolerance
fields = ["id", "name", "duration"]
class SymptomsSerializer(serializers.ModelSerializer):
class Meta:
model = Symptoms
fields = ["id", "name", "duration"]
class PastTreatmentSerializer(serializers.ModelSerializer):
class Meta:
model = PastTreatment
fields = ["id", "name", "duration", "is_recurring", "treatment_frequency"]
class ChronicConditionSerializer(serializers.ModelSerializer):
class Meta:
model = ChronicCondition
fields = ["id", "name", "duration"]
class FoodIngredientRecordSerializer(serializers.ModelSerializer):
class Meta:
model = FoodIngredientRecord
fields = ["name", "from_dataset"]
class FoodRecordSerializer(serializers.ModelSerializer):
class Meta:
model = FoodRecord
fields = ["name", "quantity"]
class BeverageRecordSerializer(serializers.ModelSerializer):
class Meta:
model = BeverageRecord
fields = [
"beverage_type",
"quantity",
"quantity_measure",
]
class MealRecordSerializer(serializers.ModelSerializer):
food_records = FoodRecordSerializer(many=True)
beverage_records = BeverageRecordSerializer(many=True)
food_ingredient_records = FoodIngredientRecordSerializer(many=True)
class Meta:
model = MealRecord
fields = [
"id",
"date",
"time",
"meal_type",
"food_records",
"food_ingredient_records",
"beverage_records",
]
def create(self, validated_data):
food_record_data = validated_data.pop("food_records", [])
beverage_record_data = validated_data.pop("beverage_records", [])
food_ingredient_record_data = validated_data.pop("food_ingredient_records", [])
meal_record = self.Meta.model.objects.create(**validated_data)
food_record_list = []
for data in food_record_data:
obj, _ = FoodRecord.objects.get_or_create(**data)
food_record_list.append(obj)
food_ingredient_list = []
for data in food_ingredient_record_data:
obj, _ = FoodIngredientRecord.objects.get_or_create(**data)
food_ingredient_list.append(obj)
beverage_record_list = []
for data in beverage_record_data:
obj, _ = BeverageRecord.objects.get_or_create(**data)
beverage_record_list.append(obj)
meal_record.food_records.set(food_record_list)
meal_record.food_ingredient_records.set(food_ingredient_list)
meal_record.beverage_records.set(beverage_record_list)
return meal_record
def update(self, instance, validated_data):
instance.date = validated_data.get("date", instance.date)
instance.time = validated_data.get("time", instance.time)
instance.meal_type = validated_data.get("meal_type", instance.meal_type)
instance.save()
food_record_data = validated_data.pop("food_records", [])
beverage_record_data = validated_data.pop("beverage_records", [])
food_ingredient_record_data = validated_data.pop("food_ingredient_records", [])
food_record_list = []
for data in food_record_data:
obj, _ = FoodRecord.objects.get_or_create(**data)
food_record_list.append(obj)
food_ingredient_list = []
for data in food_ingredient_record_data:
obj, _ = FoodIngredientRecord.objects.get_or_create(**data)
food_ingredient_list.append(obj)
beverage_record_list = []
for data in beverage_record_data:
obj, _ = BeverageRecord.objects.get_or_create(**data)
beverage_record_list.append(obj)
instance.food_records.set(food_record_list)
instance.food_ingredient_records.set(food_ingredient_list)
instance.beverage_records.set(beverage_record_list)
instance.save()
return instance
class MedicineSerializer(serializers.ModelSerializer):
class Meta:
model = Medicine
fields = ["name", "quantity", "type"]
class MedicationSerializer(serializers.ModelSerializer):
medicines = MedicineSerializer(many=True)
class Meta:
model = Medication
fields = ["id", "date", "time", "medicines"]
def create(self, validated_data):
medicines_data = validated_data.pop("medicines")
medication = self.Meta.model.objects.create(**validated_data)
for medicine_data in medicines_data:
medicine = Medicine.objects.create(**medicine_data)
medication.medicines.add(medicine)
return medication
def update(self, instance, validated_data):
instance.date = validated_data.get("date", instance.date)
instance.time = validated_data.get("time", instance.time)
instance.save()
medicines_data = validated_data.get("medicines", [])
instance.medicines.clear()
for medicine_data in medicines_data:
medicine = Medicine.objects.create(**medicine_data)
instance.medicines.add(medicine)
return instance
class BowelSerializer(serializers.ModelSerializer):
class Meta:
model = Bowel
fields = [
"id",
"date",
"time",
"stool_type",
"stool_name",
"duration",
"completeness_of_evacuation",
"urgency",
"smellness",
"pain_level",
"volume",
"color",
"excessive_flatulence",
]
class MealRecordSymptomsSerializer(serializers.ModelSerializer):
class Meta:
model = MealRecord
fields = [
"id",
"date",
"time",
"meal_type",
]
class SymptomTypeBeforeMealSerializer(serializers.ModelSerializer):
class Meta:
model = SymptomTypeBeforeMeal
fields = ["name"]
class SymptomTypeAfterMealSerializer(serializers.ModelSerializer):
class Meta:
model = SymptomTypeAfterMeal
fields = ["name"]
class MealSymptomRecordSerializer(serializers.ModelSerializer):
symptoms_before_meal = SymptomTypeBeforeMealSerializer(many=True)
symptoms_after_meal = SymptomTypeAfterMealSerializer(many=True)
related_meal_id = serializers.PrimaryKeyRelatedField(
queryset=MealRecord.objects.all(), write_only=True
) # Added field to accept meal ID
related_meal = MealRecordSymptomsSerializer(read_only=True)
class Meta:
model = MealSymptomRecord
fields = [
"id",
"date",
"time",
"symptoms_description",
"interval",
"symptoms_before_meal",
"symptoms_after_meal",
"related_meal_id",
"related_meal"
]
def create(self, validated_data):
before_meal_data = validated_data.pop("symptoms_before_meal")
after_meal_data = validated_data.pop("symptoms_after_meal")
related_meal_id = validated_data.pop("related_meal_id")
meal_symptom_record = MealSymptomRecord.objects.create(
related_meal=related_meal_id, **validated_data
)
before_meal_list = []
for data in before_meal_data:
obj, _ = SymptomTypeBeforeMeal.objects.get_or_create(**data)
before_meal_list.append(obj)
after_meal_list = []
for data in after_meal_data:
obj, _ = SymptomTypeAfterMeal.objects.get_or_create(**data)
after_meal_list.append(obj)
meal_symptom_record.symptoms_before_meal.set(before_meal_list)
meal_symptom_record.symptoms_after_meal.set(after_meal_list)
return meal_symptom_record
def update(self, instance, validated_data):
instance.date = validated_data.get("date", instance.date)
instance.time = validated_data.get("time", instance.time)
instance.symptoms_description = validated_data.get(
"symptoms_description", instance.symptoms_description
)
instance.interval = validated_data.get("interval", instance.interval)
related_meal_id = validated_data.pop("related_meal_id", None) # Extract meal ID
if related_meal_id is not None:
instance.related_meal = related_meal_id
before_meal_data = validated_data.pop("symptoms_before_meal", [])
after_meal_data = validated_data.pop("symptoms_after_meal", [])
before_meal_instances = []
for data in before_meal_data:
obj, _ = SymptomTypeBeforeMeal.objects.get_or_create(**data)
before_meal_instances.append(obj)
after_meal_instances = []
for data in after_meal_data:
obj, _ = SymptomTypeAfterMeal.objects.get_or_create(**data)
after_meal_instances.append(obj)
instance.symptoms_before_meal.set(before_meal_instances)
instance.symptoms_after_meal.set(after_meal_instances)
instance.save()
return instance