215 lines
7.6 KiB
Python
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__'
|