From 6efe4ab08d4b272781e6571851677a1fc7cad4b3 Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Wed, 15 Mar 2023 17:30:23 +0100 Subject: [PATCH] base unit conversions --- cookbook/helper/unit_conversion_helper.py | 77 ++++++++++++-------- cookbook/migrations/0194_unit_base_unit.py | 18 +++++ cookbook/models.py | 1 + cookbook/tests/other/test_unit_conversion.py | 25 +++++++ 4 files changed, 92 insertions(+), 29 deletions(-) create mode 100644 cookbook/migrations/0194_unit_base_unit.py create mode 100644 cookbook/tests/other/test_unit_conversion.py diff --git a/cookbook/helper/unit_conversion_helper.py b/cookbook/helper/unit_conversion_helper.py index b79164b28..315e9537d 100644 --- a/cookbook/helper/unit_conversion_helper.py +++ b/cookbook/helper/unit_conversion_helper.py @@ -1,51 +1,70 @@ -from pint import UnitRegistry, UndefinedUnitError +from pint import UnitRegistry, UndefinedUnitError, PintError + +from cookbook.models import Ingredient, Unit + +CONVERT_TO_UNITS = { + 'metric': ['g', 'kg', 'ml', 'l'], + 'us': ['ounce', 'pound', 'fluid_ounce', 'pint', 'quart', 'gallon'], + 'uk': ['ounce', 'pound', 'imperial_fluid_ounce', 'imperial_pint', 'imperial_quart', 'imperial_gallon'], +} def base_conversions(ingredient_list): - ingredient_list = [{'amount': 1, 'unit': 'g'}, {'amount': 1, 'unit': 'Gramm'}, {'amount': 1, 'unit': 'Stück'}] ureg = UnitRegistry() - pint_converted_list = [] + pint_converted_list = ingredient_list.copy() for i in ingredient_list: try: - pint_converted_list.append(ureg.Quantity(f'{i["amount"]} {i["unit"]}')) - except UndefinedUnitError: + conversion_unit = i.unit.name + if i.unit.base_unit: + conversion_unit = i.unit.base_unit + quantitiy = ureg.Quantity(f'{i.amount} {conversion_unit}') + for u in CONVERT_TO_UNITS['metric'] + CONVERT_TO_UNITS['us'] + CONVERT_TO_UNITS['uk']: + converted = quantitiy.to(u) + ingredient = Ingredient(amount=converted.m, unit=Unit(name=str(converted.units)), food=ingredient_list[0].food, ) + if not any(x.unit.name == ingredient.unit.name for x in pint_converted_list): + pint_converted_list.append(ingredient) + except PintError: pass - print(pint_converted_list) + return pint_converted_list -def get_conversions(amount, unit, food): - conversions = [] - if unit: - for c in unit.unit_conversion_base_relation.all(): - r = _uc_convert(c, amount, unit, food) +def get_conversions(ingredient): + conversions = [ingredient] + if ingredient.unit: + for c in ingredient.unit.unit_conversion_base_relation.all(): + r = _uc_convert(c, ingredient.amount, ingredient.unit, ingredient.food) if r not in conversions: conversions.append(r) - for c in unit.unit_conversion_converted_relation.all(): - r = _uc_convert(c, amount, unit, food) + for c in ingredient.unit.unit_conversion_converted_relation.all(): + r = _uc_convert(c, ingredient.amount, ingredient.unit, ingredient.food) if r not in conversions: conversions.append(r) + conversions += base_conversions(conversions) + return conversions def _uc_convert(uc, amount, unit, food): if uc.food is None or uc.food == food: if unit == uc.base_unit: - return { - 'amount': amount * (uc.converted_amount / uc.base_amount), - 'unit': { - 'id': uc.converted_unit.id, - 'name': uc.converted_unit.name, - 'plural_name': uc.converted_unit.plural_name - }, - } + return Ingredient(amount=amount * (uc.converted_amount / uc.base_amount), unit=uc.converted_unit, food=food) + # return { + # 'amount': amount * (uc.converted_amount / uc.base_amount), + # 'unit': { + # 'id': uc.converted_unit.id, + # 'name': uc.converted_unit.name, + # 'plural_name': uc.converted_unit.plural_name + # }, + # } else: - return { - 'amount': amount * (uc.base_amount / uc.converted_amount), - 'unit': { - 'id': uc.base_unit.id, - 'name': uc.base_unit.name, - 'plural_name': uc.base_unit.plural_name - }, - } + return Ingredient(amount=amount * (uc.base_amount / uc.converted_amount), unit=uc.base_unit, food=food) + # return { + # 'amount': amount * (uc.base_amount / uc.converted_amount), + # 'unit': { + # 'id': uc.base_unit.id, + # 'name': uc.base_unit.name, + # 'plural_name': uc.base_unit.plural_name + # }, + # } diff --git a/cookbook/migrations/0194_unit_base_unit.py b/cookbook/migrations/0194_unit_base_unit.py new file mode 100644 index 000000000..f9e93df01 --- /dev/null +++ b/cookbook/migrations/0194_unit_base_unit.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.7 on 2023-03-15 14:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('cookbook', '0193_alter_unitconversion_base_unit_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='unit', + name='base_unit', + field=models.TextField(blank=True, default=None, max_length=256, null=True), + ), + ] diff --git a/cookbook/models.py b/cookbook/models.py index 8bf63532c..82813cb85 100644 --- a/cookbook/models.py +++ b/cookbook/models.py @@ -534,6 +534,7 @@ class Unit(ExportModelOperationsMixin('unit'), models.Model, PermissionModelMixi name = models.CharField(max_length=128, validators=[MinLengthValidator(1)]) plural_name = models.CharField(max_length=128, null=True, blank=True, default=None) description = models.TextField(blank=True, null=True) + base_unit = models.TextField(max_length=256, null=True, blank=True, default=None) space = models.ForeignKey(Space, on_delete=models.CASCADE) objects = ScopedManager(space='space') diff --git a/cookbook/tests/other/test_unit_conversion.py b/cookbook/tests/other/test_unit_conversion.py new file mode 100644 index 000000000..a1e0513db --- /dev/null +++ b/cookbook/tests/other/test_unit_conversion.py @@ -0,0 +1,25 @@ +from django_scopes import scopes_disabled + +from cookbook.helper.unit_conversion_helper import get_conversions +from cookbook.models import Unit, Food, Ingredient + + +def test_unit_conversions(space_1): + with scopes_disabled(): + unit_gram = Unit.objects.create(name='gram', base_unit='g', space=space_1) + unit_pcs = Unit.objects.create(name='pcs', base_unit='', space=space_1) + unit_floz1 = Unit.objects.create(name='fl. oz 1', base_unit='imperial_fluid_ounce', space=space_1) # US and UK use different volume systems (US vs imperial) + unit_floz2 = Unit.objects.create(name='fl. oz 2', base_unit='fluid_ounce', space=space_1) + + food_1 = Food.objects.create(name='Test Food 1', space=space_1) + + ingredient_food_1_gram = Ingredient.objects.create( + food=food_1, + unit=unit_gram, + amount=100, + space=space_1, + ) + + print('\n----------- TEST ---------------') + print(get_conversions(ingredient_food_1_gram)) +