nabilah_argyanti_ardyningrum/backend/easycookapi-main/recipes/serializers.py
2024-12-31 09:49:01 +07:00

215 lines
7.6 KiB
Python

from rest_framework import serializers
from recipes.models import Information, Review, Ingredient, RawIngredient, Unit
from profiles.models import Account, Favorite, Pantry
from django.db.models import Avg, Count
from django.template.defaultfilters import date
from decimal import Decimal
import ast
import math
from profiles.utils import get_owned_raw_ingredients, get_owned_recipe_ingredients
class RawIngredientSerializer(serializers.ModelSerializer):
class Meta:
model = RawIngredient
fields = '__all__'
class RecipeIngredientsSerializer(serializers.ModelSerializer):
unit = serializers.CharField(source='unit.code')
class Meta:
model = Ingredient
fields = ('id', 'name', 'amount', 'state', 'recipe', 'unit')
class ReviewSummarySerializer(serializers.ModelSerializer):
score = serializers.SerializerMethodField()
amount = serializers.SerializerMethodField()
class Meta:
model = Review
fields = ('score', 'amount')
def get_score(self, instance):
ratings = Review.objects.filter(recipe_id=instance.id).aggregate(
avg_rating=Avg('rating'),
review_count=Count('id')
)
avg_rating = ratings['avg_rating'] or 0
review_count = ratings['review_count'] or 0
total_rating = avg_rating * review_count
total_review_count = review_count
return Decimal(total_rating / total_review_count).quantize(Decimal('0.00')) if total_review_count != 0 else 0.0
def get_amount(self, instance):
review_counts = Review.objects.filter(recipe_id=instance.id).aggregate(
user_review_count=Count('id')
)
user_review_count = review_counts['user_review_count'] or 0
total_review_count = user_review_count
return total_review_count
class RecipeInformationSerializer(serializers.ModelSerializer):
completeness_percentage = serializers.SerializerMethodField()
is_favorited = serializers.SerializerMethodField()
similarity = serializers.SerializerMethodField()
rating = ReviewSummarySerializer(source='*')
def get_is_favorited(self, instance):
user = self.context['request'].user
if user.is_authenticated:
return Favorite.objects.filter(recipe_id=instance.pk, user=user).exists()
return False
def get_completeness_percentage(self, instance):
user = self.context['request'].user
if user.is_authenticated:
owned_ingredient_ids = len(get_owned_recipe_ingredients(
user, instance.pk))
total_ingredient_count = instance.ingredients.count()
# print(instance.title + " " + str(owned_ingredient_ids) + " " + str(total_ingredient_count))
if total_ingredient_count > 0:
completeness_percentage = (
owned_ingredient_ids / total_ingredient_count * 100
)
completeness_percentage = round(
completeness_percentage, 2)
return completeness_percentage
return 0
def get_similarity(self, instance): # Add this method
recipe_id = instance.pk
top_recipes = self.context.get('top_recipes')
similarity = 0
if top_recipes:
similarity = next(
(item['similarity']
for item in top_recipes if item['recipe_id'] == recipe_id),
0
)
similarity = round(Decimal(similarity), 2)
return similarity
class Meta:
model = Information
fields = ('id', 'title', 'image_url', 'difficulty', 'source_url',
'calories', 'completeness_percentage', 'is_favorited', 'rating', 'similarity')
class RecipeDetailSerializer(serializers.ModelSerializer):
ingredients = serializers.SerializerMethodField()
owned_ingredients = serializers.SerializerMethodField()
not_owned_ingredients = serializers.SerializerMethodField()
instructions = serializers.CharField()
rating = ReviewSummarySerializer(source='*')
is_favorited = serializers.SerializerMethodField()
def get_ingredients(self, instance):
user = self.context['request'].user
all_ingredients = Ingredient.objects.filter(recipe=instance)
serialized_data = RecipeIngredientsSerializer(
all_ingredients, many=True).data
if user.is_authenticated:
owned_ingredient_ids = get_owned_recipe_ingredients(
user, instance.pk)
owned_ingredients = Ingredient.objects.filter(
pk__in=owned_ingredient_ids).distinct()
owned_ids = [ingredient.id for ingredient in owned_ingredients]
for ingredient in serialized_data:
if ingredient['id'] in owned_ids:
ingredient['is_owned'] = True
else:
ingredient['is_owned'] = False
else:
for ingredient in serialized_data:
ingredient['is_owned'] = False
return serialized_data
def get_owned_ingredients(self, instance):
user = self.context['request'].user
if not user.is_authenticated:
return []
owned_ingredient_ids = get_owned_recipe_ingredients(
user, instance.pk)
owned_ingredients = Ingredient.objects.filter(
id__in=owned_ingredient_ids).distinct()
return RecipeIngredientsSerializer(owned_ingredients, many=True).data
def get_not_owned_ingredients(self, instance):
user = self.context['request'].user
if not user.is_authenticated:
all_ingredients = Ingredient.objects.filter(recipe=instance)
return RecipeIngredientsSerializer(all_ingredients, many=True).data
owned_raw_ingredient_ids = Pantry.objects.filter(
user=user).values_list('raw_ingredient_id', flat=True)
not_owned_ingredients = Ingredient.objects.filter(
recipe=instance).exclude(raw_ingredient__in=owned_raw_ingredient_ids)
return RecipeIngredientsSerializer(not_owned_ingredients, many=True).data
def get_is_favorited(self, instance):
user = self.context['request'].user
if user.is_authenticated:
return Favorite.objects.filter(recipe_id=instance.pk, user=user).exists()
return False
class Meta:
model = Information
fields = ('id', 'title', 'image_url', 'time', 'servings', 'difficulty', 'source_url',
'rating', 'is_favorited', 'ingredients', 'instructions', 'owned_ingredients', 'not_owned_ingredients')
def to_representation(self, instance):
representation = super().to_representation(instance)
string_array = representation['instructions']
array = ast.literal_eval(string_array)
representation['instructions'] = array
return representation
class ReviewSerializer(serializers.ModelSerializer):
user = serializers.SerializerMethodField()
modified_date = serializers.SerializerMethodField()
class Meta:
model = Review
fields = ('id', 'user', 'rating', 'comment', 'modified_date')
def get_user(self, instance):
account = Account.objects.get(user=instance.user)
user_data = {
'id': account.user.id,
'profile_picture': account.profile_picture.url,
'name': f"{account.user.first_name} {account.user.last_name}"
}
return user_data
def get_modified_date(self, instance):
modified_date = date(instance.updated_at, "j F Y")
return modified_date
class UnitSerializer(serializers.ModelSerializer):
class Meta:
model = Unit
fields = '__all__'