user nutrition types + ingredient nutrtion calculation

This commit is contained in:
vabene1111 2023-02-24 22:12:52 +01:00
parent 5651beffb2
commit a2b987352f
5 changed files with 105 additions and 14 deletions

View File

@ -15,7 +15,7 @@ from .models import (BookmarkletImport, Comment, CookLog, Food, FoodInheritField
Recipe, RecipeBook, RecipeBookEntry, RecipeImport, SearchPreference, ShareLink,
ShoppingList, ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage,
Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync, SyncLog,
TelegramBot, Unit, UserFile, UserPreference, ViewLog, Automation, UserSpace, UnitConversion)
TelegramBot, Unit, UserFile, UserPreference, ViewLog, Automation, UserSpace, UnitConversion, NutritionType, FoodNutrition)
class CustomUserAdmin(UserAdmin):
@ -327,6 +327,20 @@ class ShareLinkAdmin(admin.ModelAdmin):
admin.site.register(ShareLink, ShareLinkAdmin)
class NutritionTypeAdmin(admin.ModelAdmin):
list_display = ('id', 'name')
admin.site.register(NutritionType, NutritionTypeAdmin)
class FoodNutritionAdmin(admin.ModelAdmin):
list_display = ('id', 'food_amount', 'food_unit', 'food', 'nutrition_amount', 'nutrition_type')
admin.site.register(FoodNutrition, FoodNutritionAdmin)
class NutritionInformationAdmin(admin.ModelAdmin):
list_display = ('id',)

View File

@ -1,4 +1,4 @@
# Generated by Django 4.1.4 on 2023-01-09 16:41
# Generated by Django 4.1.7 on 2023-02-24 19:47
import cookbook.models
from django.conf import settings
@ -11,7 +11,7 @@ class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('cookbook', '0186_automation_order_alter_automation_type'),
('cookbook', '0188_space_no_sharing_limit'),
]
operations = [

View File

@ -0,0 +1,40 @@
# Generated by Django 4.1.7 on 2023-02-24 20:15
import cookbook.models
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('cookbook', '0189_unitconversion'),
]
operations = [
migrations.CreateModel(
name='NutritionType',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=128)),
('unit', models.CharField(blank=True, max_length=64, null=True)),
('icon', models.CharField(blank=True, max_length=16, null=True)),
('description', models.CharField(blank=True, max_length=512, null=True)),
('space', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space')),
],
bases=(models.Model, cookbook.models.PermissionModelMixin),
),
migrations.CreateModel(
name='FoodNutrition',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('food_amount', models.DecimalField(decimal_places=2, default=0, max_digits=32)),
('nutrition_amount', models.DecimalField(decimal_places=4, default=0, max_digits=32)),
('food', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.food')),
('food_unit', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.unit')),
('nutrition_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='cookbook.nutritiontype')),
('space', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space')),
],
bases=(models.Model, cookbook.models.PermissionModelMixin),
),
]

View File

@ -739,6 +739,33 @@ class Step(ExportModelOperationsMixin('step'), models.Model, PermissionModelMixi
indexes = (GinIndex(fields=["search_vector"]),)
class NutritionType(models.Model, PermissionModelMixin):
name = models.CharField(max_length=128)
unit = models.CharField(max_length=64, blank=True, null=True)
icon = models.CharField(max_length=16, blank=True, null=True)
description = models.CharField(max_length=512, blank=True, null=True)
space = models.ForeignKey(Space, on_delete=models.CASCADE)
objects = ScopedManager(space='space')
def __str__(self):
return f'{self.name}'
class FoodNutrition(models.Model, PermissionModelMixin):
food_amount = models.DecimalField(default=0, decimal_places=2, max_digits=32)
food_unit = models.ForeignKey(Unit, on_delete=models.CASCADE)
food = models.ForeignKey(Food, on_delete=models.CASCADE)
nutrition_amount = models.DecimalField(default=0, decimal_places=4, max_digits=32)
nutrition_type = models.ForeignKey(NutritionType, on_delete=models.PROTECT)
space = models.ForeignKey(Space, on_delete=models.CASCADE)
objects = ScopedManager(space='space')
def __str__(self):
return f'{self.food_amount} {self.food_unit} {self.food}: {self.nutrition_amount} {self.nutrition_type.unit} {self.nutrition_type.name}'
class NutritionInformation(models.Model, PermissionModelMixin):
fats = models.DecimalField(default=0, decimal_places=16, max_digits=32)
carbohydrates = models.DecimalField(
@ -755,14 +782,6 @@ class NutritionInformation(models.Model, PermissionModelMixin):
return f'Nutrition {self.pk}'
# class NutritionType(models.Model, PermissionModelMixin):
# name = models.CharField(max_length=128)
# icon = models.CharField(max_length=16, blank=True, null=True)
# description = models.CharField(max_length=512, blank=True, null=True)
#
# space = models.ForeignKey(Space, on_delete=models.CASCADE)
# objects = ScopedManager(space='space')
class RecipeManager(models.Manager.from_queryset(models.QuerySet)):
def get_queryset(self):
return super(RecipeManager, self).get_queryset().annotate(rating=Avg('cooklog__rating')).annotate(last_cooked=Max('cooklog__created_at'))

View File

@ -29,7 +29,7 @@ from cookbook.models import (Automation, BookmarkletImport, Comment, CookLog, Cu
RecipeBookEntry, RecipeImport, ShareLink, ShoppingList,
ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage,
Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync,
SyncLog, Unit, UserFile, UserPreference, UserSpace, ViewLog, UnitConversion)
SyncLog, Unit, UserFile, UserPreference, UserSpace, ViewLog, UnitConversion, FoodNutrition, NutritionType)
from cookbook.templatetags.custom_tags import markdown
from recipes.settings import AWS_ENABLED, MEDIA_URL
@ -619,6 +619,7 @@ class IngredientSimpleSerializer(WritableNestedModelSerializer):
used_in_recipes = serializers.SerializerMethodField('get_used_in_recipes')
amount = CustomDecimalField()
conversions = serializers.SerializerMethodField('get_conversions')
nutritions = serializers.SerializerMethodField('get_nutritions')
def get_used_in_recipes(self, obj):
return list(Recipe.objects.filter(steps__ingredients=obj.id).values('id', 'name'))
@ -629,7 +630,7 @@ class IngredientSimpleSerializer(WritableNestedModelSerializer):
for c in UnitConversion.objects.filter(space=self.context['request'].space).filter(Q(food__isnull=True) | Q(food=obj.food)).filter(Q(base_unit=obj.unit) | Q(converted_unit=obj.unit)):
if obj.unit == c.base_unit:
conversions.append({
'amount': obj.amount * (c.converted_amount/c.base_amount),
'amount': obj.amount * (c.converted_amount / c.base_amount),
'unit': UnitSerializer(c.converted_unit, context={'request': self.context['request']}).data,
})
else:
@ -640,6 +641,23 @@ class IngredientSimpleSerializer(WritableNestedModelSerializer):
return conversions
def get_nutritions(self, ingredient):
nutritions = {}
for nt in NutritionType.objects.filter(space=self.context['request'].space).all():
nutritions[nt.id] = None
food_nutrition = ingredient.food.foodnutrition_set.all()
for fn in food_nutrition:
if fn.food_unit == ingredient.unit:
nutritions[fn.nutrition_type.id] = ingredient.amount / fn.food_amount * fn.nutrition_amount
else:
conversions = self.get_conversions(ingredient)
for c in conversions:
if fn.food_unit.id == c['unit']['id']:
nutritions[fn.nutrition_type.id] = c['amount'] / fn.food_amount * fn.nutrition_amount
return nutritions
def create(self, validated_data):
validated_data['space'] = self.context['request'].space
return super().create(validated_data)
@ -651,7 +669,7 @@ class IngredientSimpleSerializer(WritableNestedModelSerializer):
class Meta:
model = Ingredient
fields = (
'id', 'food', 'unit', 'amount', 'conversions', 'note', 'order',
'id', 'food', 'unit', 'amount', 'nutritions', 'conversions', 'note', 'order',
'is_header', 'no_amount', 'original_text', 'used_in_recipes',
'always_use_plural_unit', 'always_use_plural_food',
)