first conversions working
This commit is contained in:
parent
666e4d282f
commit
3ced8c7a1e
@ -15,7 +15,7 @@ from .models import (BookmarkletImport, Comment, CookLog, Food, FoodInheritField
|
|||||||
Recipe, RecipeBook, RecipeBookEntry, RecipeImport, SearchPreference, ShareLink,
|
Recipe, RecipeBook, RecipeBookEntry, RecipeImport, SearchPreference, ShareLink,
|
||||||
ShoppingList, ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage,
|
ShoppingList, ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage,
|
||||||
Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync, SyncLog,
|
Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync, SyncLog,
|
||||||
TelegramBot, Unit, UserFile, UserPreference, ViewLog, Automation, UserSpace)
|
TelegramBot, Unit, UserFile, UserPreference, ViewLog, Automation, UserSpace, UnitConversion)
|
||||||
|
|
||||||
|
|
||||||
class CustomUserAdmin(UserAdmin):
|
class CustomUserAdmin(UserAdmin):
|
||||||
@ -201,6 +201,14 @@ class FoodAdmin(TreeAdmin):
|
|||||||
admin.site.register(Food, FoodAdmin)
|
admin.site.register(Food, FoodAdmin)
|
||||||
|
|
||||||
|
|
||||||
|
class UnitConversionAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('base_amount', 'base_unit', 'food', 'converted_amount', 'converted_unit')
|
||||||
|
search_fields = ('food__name', 'unit__name')
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(UnitConversion, UnitConversionAdmin)
|
||||||
|
|
||||||
|
|
||||||
class IngredientAdmin(admin.ModelAdmin):
|
class IngredientAdmin(admin.ModelAdmin):
|
||||||
list_display = ('food', 'amount', 'unit')
|
list_display = ('food', 'amount', 'unit')
|
||||||
search_fields = ('food__name', 'unit__name')
|
search_fields = ('food__name', 'unit__name')
|
||||||
|
34
cookbook/migrations/0187_unitconversion.py
Normal file
34
cookbook/migrations/0187_unitconversion.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2023-01-09 16:41
|
||||||
|
|
||||||
|
import cookbook.models
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django_prometheus.models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('cookbook', '0186_automation_order_alter_automation_type'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='UnitConversion',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('base_amount', models.DecimalField(decimal_places=16, default=0, max_digits=32)),
|
||||||
|
('converted_amount', models.DecimalField(decimal_places=16, default=0, max_digits=32)),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('updated_at', models.DateTimeField(auto_now=True)),
|
||||||
|
('base_unit', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='base_unit', to='cookbook.unit')),
|
||||||
|
('converted_unit', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='converted_unit', to='cookbook.unit')),
|
||||||
|
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)),
|
||||||
|
('food', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='cookbook.food')),
|
||||||
|
('space', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space')),
|
||||||
|
],
|
||||||
|
bases=(django_prometheus.models.ExportModelOperationsMixin('unit_conversion'), models.Model, cookbook.models.PermissionModelMixin),
|
||||||
|
),
|
||||||
|
]
|
@ -649,6 +649,25 @@ class Food(ExportModelOperationsMixin('food'), TreeModel, PermissionModelMixin):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class UnitConversion(ExportModelOperationsMixin('unit_conversion'), models.Model, PermissionModelMixin):
|
||||||
|
base_amount = models.DecimalField(default=0, decimal_places=16, max_digits=32)
|
||||||
|
base_unit = models.ForeignKey('Unit', on_delete=models.CASCADE, related_name='base_unit')
|
||||||
|
converted_amount = models.DecimalField(default=0, decimal_places=16, max_digits=32)
|
||||||
|
converted_unit = models.ForeignKey('Unit', on_delete=models.CASCADE, related_name='converted_unit')
|
||||||
|
|
||||||
|
food = models.ForeignKey('Food', on_delete=models.CASCADE, null=True, blank=True)
|
||||||
|
|
||||||
|
created_by = models.ForeignKey(User, on_delete=models.PROTECT)
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
updated_at = models.DateTimeField(auto_now=True)
|
||||||
|
|
||||||
|
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
||||||
|
objects = ScopedManager(space='space')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'{self.base_amount} {self.base_unit} -> {self.converted_amount} {self.converted_unit} {self.food}'
|
||||||
|
|
||||||
|
|
||||||
class Ingredient(ExportModelOperationsMixin('ingredient'), models.Model, PermissionModelMixin):
|
class Ingredient(ExportModelOperationsMixin('ingredient'), models.Model, PermissionModelMixin):
|
||||||
# delete method on Food and Unit checks if they are part of a Recipe, if it is raises a ProtectedError instead of cascading the delete
|
# delete method on Food and Unit checks if they are part of a Recipe, if it is raises a ProtectedError instead of cascading the delete
|
||||||
food = models.ForeignKey(Food, on_delete=models.CASCADE, null=True, blank=True)
|
food = models.ForeignKey(Food, on_delete=models.CASCADE, null=True, blank=True)
|
||||||
|
@ -29,7 +29,7 @@ from cookbook.models import (Automation, BookmarkletImport, Comment, CookLog, Cu
|
|||||||
RecipeBookEntry, RecipeImport, ShareLink, ShoppingList,
|
RecipeBookEntry, RecipeImport, ShareLink, ShoppingList,
|
||||||
ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage,
|
ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage,
|
||||||
Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync,
|
Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync,
|
||||||
SyncLog, Unit, UserFile, UserPreference, UserSpace, ViewLog)
|
SyncLog, Unit, UserFile, UserPreference, UserSpace, ViewLog, UnitConversion)
|
||||||
from cookbook.templatetags.custom_tags import markdown
|
from cookbook.templatetags.custom_tags import markdown
|
||||||
from recipes.settings import AWS_ENABLED, MEDIA_URL
|
from recipes.settings import AWS_ENABLED, MEDIA_URL
|
||||||
|
|
||||||
@ -610,10 +610,28 @@ class IngredientSimpleSerializer(WritableNestedModelSerializer):
|
|||||||
unit = UnitSerializer(allow_null=True)
|
unit = UnitSerializer(allow_null=True)
|
||||||
used_in_recipes = serializers.SerializerMethodField('get_used_in_recipes')
|
used_in_recipes = serializers.SerializerMethodField('get_used_in_recipes')
|
||||||
amount = CustomDecimalField()
|
amount = CustomDecimalField()
|
||||||
|
conversions = serializers.SerializerMethodField('get_conversions')
|
||||||
|
|
||||||
def get_used_in_recipes(self, obj):
|
def get_used_in_recipes(self, obj):
|
||||||
return list(Recipe.objects.filter(steps__ingredients=obj.id).values('id', 'name'))
|
return list(Recipe.objects.filter(steps__ingredients=obj.id).values('id', 'name'))
|
||||||
|
|
||||||
|
def get_conversions(self, obj):
|
||||||
|
conversions = []
|
||||||
|
|
||||||
|
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),
|
||||||
|
'unit': UnitSerializer(c.converted_unit, context={'request': self.context['request']}).data,
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
conversions.append({
|
||||||
|
'amount': obj.amount * (c.base_amount / c.converted_amount),
|
||||||
|
'unit': UnitSerializer(c.base_unit, context={'request': self.context['request']}).data,
|
||||||
|
})
|
||||||
|
|
||||||
|
return conversions
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
validated_data['space'] = self.context['request'].space
|
validated_data['space'] = self.context['request'].space
|
||||||
return super().create(validated_data)
|
return super().create(validated_data)
|
||||||
@ -625,7 +643,7 @@ class IngredientSimpleSerializer(WritableNestedModelSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Ingredient
|
model = Ingredient
|
||||||
fields = (
|
fields = (
|
||||||
'id', 'food', 'unit', 'amount', 'note', 'order',
|
'id', 'food', 'unit', 'amount', 'conversions', 'note', 'order',
|
||||||
'is_header', 'no_amount', 'original_text', 'used_in_recipes',
|
'is_header', 'no_amount', 'original_text', 'used_in_recipes',
|
||||||
'always_use_plural_unit', 'always_use_plural_food',
|
'always_use_plural_unit', 'always_use_plural_food',
|
||||||
)
|
)
|
||||||
|
28829
vue/yarn.lock
28829
vue/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user