cleanup migrations, remove pint to speed up base conversion and calculate properties on converted ingredients

This commit is contained in:
vabene1111
2023-05-06 22:21:27 +02:00
parent 2cc7278865
commit 19f5da77b2
14 changed files with 249 additions and 322 deletions

View File

@ -160,6 +160,7 @@ class OpenDataImporter:
update_list.append(Food(id=existing_food_id, open_data_slug=k, ))
Food.load_bulk(insert_list, None)
if len(update_list) > 0:
Food.objects.bulk_update(update_list, update_field_list)
self._update_slug_cache(Food, 'food')

View File

@ -33,7 +33,7 @@ class FoodPropertyHelper:
uch = UnitConversionHelper(self.space)
for i in ingredients:
conversions = [i] # uch.get_conversions(i)
conversions = uch.get_conversions(i)
for pt in property_types:
found_property = False
for p in i.food.foodproperty_set.all():

View File

@ -1,6 +1,7 @@
from django.core.cache import caches
from pint import UnitRegistry, UndefinedUnitError, PintError
from decimal import Decimal
from cookbook.helper.cache_helper import CacheHelper
from cookbook.models import Ingredient, Unit
@ -12,6 +13,38 @@ CONVERT_TO_UNITS = {
'uk': ['ounce', 'pound', 'imperial_fluid_ounce', 'imperial_pint', 'imperial_quart', 'imperial_gallon'],
}
CONVERSION_TABLE = {
'weight': {
'g': 1000,
'kg': 1,
'ounce': 35.274,
'pound': 2.20462
},
'volume': {
'ml': 1000,
'l': 1,
'fluid_ounce': 33.814,
'pint': 2.11338,
'quart': 1.05669,
'gallon': 0.264172,
'tbsp': 67.628,
'tsp': 202.884,
'imperial_fluid_ounce': 35.1951,
'imperial_pint': 1.75975,
'imperial_quart': 0.879877,
'imperial_gallon': 0.219969,
'imperial_tbsp': 56.3121,
'imperial_tsp': 168.936,
},
}
BASE_UNITS_WEIGHT = CONVERSION_TABLE['weight'].keys()
BASE_UNITS_VOLUME = CONVERSION_TABLE['volume'].keys()
class ConversionException(Exception):
pass
class UnitConversionHelper:
space = None
@ -23,6 +56,19 @@ class UnitConversionHelper:
"""
self.space = space
@staticmethod
def convert_from_to(from_unit, to_unit, amount):
system = None
if from_unit in BASE_UNITS_WEIGHT and to_unit in BASE_UNITS_WEIGHT:
system = 'weight'
if from_unit in BASE_UNITS_VOLUME and to_unit in BASE_UNITS_VOLUME:
system = 'volume'
if not system:
raise ConversionException('Trying to convert units not existing or not in one unit system (weight/volume)')
return Decimal(amount / Decimal(CONVERSION_TABLE[system][from_unit] / CONVERSION_TABLE[system][to_unit]))
def base_conversions(self, ingredient_list):
"""
Calculates all possible base unit conversions for each ingredient give.
@ -31,14 +77,12 @@ class UnitConversionHelper:
:param ingredient_list: list of ingredients to convert
:return: ingredient list with appended conversions
"""
ureg = UnitRegistry()
pint_converted_list = ingredient_list.copy()
base_conversion_ingredient_list = ingredient_list.copy()
for i in ingredient_list:
try:
conversion_unit = i.unit.name
if i.unit.base_unit:
conversion_unit = i.unit.base_unit
quantitiy = ureg.Quantity(f'{i.amount} {conversion_unit}')
# TODO allow setting which units to convert to? possibly only once conversions become visible
units = caches['default'].get(CacheHelper(self.space).BASE_UNITS_CACHE_KEY, None)
@ -48,16 +92,15 @@ class UnitConversionHelper:
for u in units:
try:
converted = quantitiy.to(u.base_unit)
ingredient = Ingredient(amount=Decimal(converted.m), unit=u, food=ingredient_list[0].food, )
if not any((x.unit.name == ingredient.unit.name or x.unit.base_unit == ingredient.unit.name) for x in pint_converted_list):
pint_converted_list.append(ingredient)
except PintError:
ingredient = Ingredient(amount=self.convert_from_to(conversion_unit, u.base_unit, i.amount), unit=u, food=ingredient_list[0].food, )
if not any((x.unit.name == ingredient.unit.name or x.unit.base_unit == ingredient.unit.name) for x in base_conversion_ingredient_list):
base_conversion_ingredient_list.append(ingredient)
except ConversionException:
pass
except PintError:
except Exception:
pass
return pint_converted_list
return base_conversion_ingredient_list
def get_conversions(self, ingredient):
"""
@ -94,21 +137,5 @@ class UnitConversionHelper:
if uc.food is None or uc.food == food:
if unit == uc.base_unit:
return Ingredient(amount=amount * (uc.converted_amount / uc.base_amount), unit=uc.converted_unit, food=food, space=self.space)
# 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 Ingredient(amount=amount * (uc.base_amount / uc.converted_amount), unit=uc.base_unit, food=food, space=self.space)
# 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
# },
# }

View File

@ -0,0 +1,181 @@
# Generated by Django 4.1.7 on 2023-05-06 19:16
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', '0188_space_no_sharing_limit'),
]
operations = [
migrations.CreateModel(
name='FoodProperty',
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)),
('property_amount', models.DecimalField(decimal_places=4, default=0, max_digits=32)),
],
bases=(models.Model, cookbook.models.PermissionModelMixin),
),
migrations.CreateModel(
name='PropertyType',
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)),
('category', models.CharField(blank=True, choices=[('NUTRITION', 'Nutrition'), ('ALLERGEN', 'Allergen'), ('PRICE', 'Price'), ('GOAL', 'Goal'), ('OTHER', 'Other')], max_length=64, null=True)),
('open_data_slug', models.CharField(blank=True, default=None, max_length=128, null=True)),
],
bases=(models.Model, cookbook.models.PermissionModelMixin),
),
migrations.CreateModel(
name='RecipeProperty',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('property_amount', models.DecimalField(decimal_places=4, default=0, max_digits=32)),
],
bases=(models.Model, cookbook.models.PermissionModelMixin),
),
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)),
('open_data_slug', models.CharField(blank=True, default=None, max_length=128, null=True)),
],
bases=(django_prometheus.models.ExportModelOperationsMixin('unit_conversion'), models.Model, cookbook.models.PermissionModelMixin),
),
migrations.AddField(
model_name='food',
name='fdc_id',
field=models.CharField(blank=True, default=None, max_length=128, null=True),
),
migrations.AddField(
model_name='food',
name='open_data_slug',
field=models.CharField(blank=True, default=None, max_length=128, null=True),
),
migrations.AddField(
model_name='food',
name='preferred_shopping_unit',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='preferred_shopping_unit', to='cookbook.unit'),
),
migrations.AddField(
model_name='food',
name='preferred_unit',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='preferred_unit', to='cookbook.unit'),
),
migrations.AddField(
model_name='supermarket',
name='open_data_slug',
field=models.CharField(blank=True, default=None, max_length=128, null=True),
),
migrations.AddField(
model_name='supermarketcategory',
name='open_data_slug',
field=models.CharField(blank=True, default=None, max_length=128, null=True),
),
migrations.AddField(
model_name='unit',
name='base_unit',
field=models.TextField(blank=True, default=None, max_length=256, null=True),
),
migrations.AddField(
model_name='unit',
name='open_data_slug',
field=models.CharField(blank=True, default=None, max_length=128, null=True),
),
migrations.AddConstraint(
model_name='supermarketcategoryrelation',
constraint=models.UniqueConstraint(fields=('supermarket', 'category'), name='unique_sm_category_relation'),
),
migrations.AddField(
model_name='unitconversion',
name='base_unit',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='unit_conversion_base_relation', to='cookbook.unit'),
),
migrations.AddField(
model_name='unitconversion',
name='converted_unit',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='unit_conversion_converted_relation', to='cookbook.unit'),
),
migrations.AddField(
model_name='unitconversion',
name='created_by',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='unitconversion',
name='food',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='cookbook.food'),
),
migrations.AddField(
model_name='unitconversion',
name='space',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'),
),
migrations.AddField(
model_name='recipeproperty',
name='property_type',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='cookbook.propertytype'),
),
migrations.AddField(
model_name='recipeproperty',
name='space',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'),
),
migrations.AddField(
model_name='propertytype',
name='space',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'),
),
migrations.AddField(
model_name='foodproperty',
name='food',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.food'),
),
migrations.AddField(
model_name='foodproperty',
name='food_unit',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.unit'),
),
migrations.AddField(
model_name='foodproperty',
name='property_type',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='cookbook.propertytype'),
),
migrations.AddField(
model_name='foodproperty',
name='space',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'),
),
migrations.AddField(
model_name='recipe',
name='properties',
field=models.ManyToManyField(blank=True, to='cookbook.recipeproperty'),
),
migrations.AddConstraint(
model_name='unitconversion',
constraint=models.UniqueConstraint(fields=('space', 'base_unit', 'converted_unit', 'food'), name='f_unique_conversion_per_space'),
),
migrations.AddConstraint(
model_name='propertytype',
constraint=models.UniqueConstraint(fields=('space', 'name'), name='property_type_unique_name_per_space'),
),
migrations.AddConstraint(
model_name='foodproperty',
constraint=models.UniqueConstraint(fields=('food', 'property_type', 'space'), name='food_property_unique_per_space'),
),
]

View File

@ -1,73 +0,0 @@
# Generated by Django 4.1.7 on 2023-03-25 05:48
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', '0188_space_no_sharing_limit'),
]
operations = [
migrations.AddField(
model_name='unit',
name='base_unit',
field=models.TextField(blank=True, default=None, max_length=256, null=True),
),
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='unit_conversion_base_relation', to='cookbook.unit')),
('converted_unit', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='unit_conversion_converted_relation', 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),
),
migrations.CreateModel(
name='FoodPropertyType',
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)),
('category', models.CharField(choices=[('NUTRITION', 'Nutrition'), ('ALLERGEN', 'Allergen'), ('PRICE', 'PRICE')], max_length=64)),
('space', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space')),
],
bases=(models.Model, cookbook.models.PermissionModelMixin),
),
migrations.CreateModel(
name='FoodProperty',
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.foodpropertytype')),
('space', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space')),
],
bases=(models.Model, cookbook.models.PermissionModelMixin),
),
migrations.AddConstraint(
model_name='foodpropertytype',
constraint=models.UniqueConstraint(fields=('space', 'name'), name='nutrition_type_unique_name_per_space'),
),
migrations.AddConstraint(
model_name='foodproperty',
constraint=models.UniqueConstraint(fields=('food', 'nutrition_type', 'space'), name='food_nutrition_unique_per_space'),
),
]

View File

@ -1,44 +0,0 @@
# Generated by Django 4.1.7 on 2023-03-25 06:04
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cookbook', '0189_unit_base_unit_unitconversion_foodpropertytype_and_more'),
]
operations = [
migrations.RemoveConstraint(
model_name='foodproperty',
name='food_nutrition_unique_per_space',
),
migrations.RemoveConstraint(
model_name='foodpropertytype',
name='nutrition_type_unique_name_per_space',
),
migrations.RenameField(
model_name='foodproperty',
old_name='nutrition_amount',
new_name='property_amount',
),
migrations.RenameField(
model_name='foodproperty',
old_name='nutrition_type',
new_name='property_type',
),
migrations.AlterField(
model_name='foodpropertytype',
name='category',
field=models.CharField(blank=True, choices=[('NUTRITION', 'Nutrition'), ('ALLERGEN', 'Allergen'), ('PRICE', 'PRICE')], max_length=64, null=True),
),
migrations.AddConstraint(
model_name='foodproperty',
constraint=models.UniqueConstraint(fields=('food', 'property_type', 'space'), name='food_property_unique_per_space'),
),
migrations.AddConstraint(
model_name='foodpropertytype',
constraint=models.UniqueConstraint(fields=('space', 'name'), name='food_property_type_unique_name_per_space'),
),
]

View File

@ -1,64 +0,0 @@
# Generated by Django 4.1.7 on 2023-04-30 20:11
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('cookbook', '0190_remove_foodproperty_food_nutrition_unique_per_space_and_more'),
]
operations = [
migrations.AddField(
model_name='food',
name='open_data_slug',
field=models.CharField(blank=True, default=None, max_length=128, null=True),
),
migrations.AddField(
model_name='foodpropertytype',
name='fdc_id',
field=models.CharField(blank=True, default=None, max_length=128, null=True),
),
migrations.AddField(
model_name='foodpropertytype',
name='open_data_slug',
field=models.CharField(blank=True, default=None, max_length=128, null=True),
),
migrations.AddField(
model_name='foodpropertytype',
name='preferred_shopping_unit',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='preferred_shopping_unit', to='cookbook.unit'),
),
migrations.AddField(
model_name='foodpropertytype',
name='preferred_unit',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='preferred_unit', to='cookbook.unit'),
),
migrations.AddField(
model_name='supermarket',
name='open_data_slug',
field=models.CharField(blank=True, default=None, max_length=128, null=True),
),
migrations.AddField(
model_name='supermarketcategory',
name='open_data_slug',
field=models.CharField(blank=True, default=None, max_length=128, null=True),
),
migrations.AddField(
model_name='unit',
name='open_data_slug',
field=models.CharField(blank=True, default=None, max_length=128, null=True),
),
migrations.AddField(
model_name='unitconversion',
name='open_data_slug',
field=models.CharField(blank=True, default=None, max_length=128, null=True),
),
migrations.AlterField(
model_name='foodpropertytype',
name='category',
field=models.CharField(blank=True, choices=[('NUTRITION', 'Nutrition'), ('ALLERGEN', 'Allergen'), ('PRICE', 'Price'), ('GOAL', 'Goal'), ('OTHER', 'Other')], max_length=64, null=True),
),
]

View File

@ -1,41 +0,0 @@
# Generated by Django 4.1.7 on 2023-05-01 10:41
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('cookbook', '0191_food_open_data_slug_foodpropertytype_fdc_id_and_more'),
]
operations = [
migrations.RemoveField(
model_name='foodpropertytype',
name='fdc_id',
),
migrations.RemoveField(
model_name='foodpropertytype',
name='preferred_shopping_unit',
),
migrations.RemoveField(
model_name='foodpropertytype',
name='preferred_unit',
),
migrations.AddField(
model_name='food',
name='fdc_id',
field=models.CharField(blank=True, default=None, max_length=128, null=True),
),
migrations.AddField(
model_name='food',
name='preferred_shopping_unit',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='preferred_shopping_unit', to='cookbook.unit'),
),
migrations.AddField(
model_name='food',
name='preferred_unit',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='preferred_unit', to='cookbook.unit'),
),
]

View File

@ -1,17 +0,0 @@
# Generated by Django 4.1.7 on 2023-05-04 05:57
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cookbook', '0192_remove_foodpropertytype_fdc_id_and_more'),
]
operations = [
migrations.AddConstraint(
model_name='unitconversion',
constraint=models.UniqueConstraint(fields=('space', 'base_unit', 'converted_unit', 'food'), name='f_unique_conversion_per_space'),
),
]

View File

@ -1,17 +0,0 @@
# Generated by Django 4.1.7 on 2023-05-04 13:24
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cookbook', '0193_unitconversion_f_unique_conversion_per_space'),
]
operations = [
migrations.AddConstraint(
model_name='supermarketcategoryrelation',
constraint=models.UniqueConstraint(fields=('supermarket', 'category'), name='unique_sm_category_relation'),
),
]

View File

@ -1,34 +0,0 @@
# Generated by Django 4.1.7 on 2023-05-06 16:33
import cookbook.models
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('cookbook', '0194_supermarketcategoryrelation_unique_sm_category_relation'),
]
operations = [
migrations.RenameModel(
old_name='FoodPropertyType',
new_name='PropertyType',
),
migrations.CreateModel(
name='RecipeProperty',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('property_amount', models.DecimalField(decimal_places=4, default=0, max_digits=32)),
('property_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='cookbook.propertytype')),
('space', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space')),
],
bases=(models.Model, cookbook.models.PermissionModelMixin),
),
migrations.AddField(
model_name='recipe',
name='properties',
field=models.ManyToManyField(blank=True, to='cookbook.recipeproperty'),
),
]

View File

@ -7,6 +7,13 @@ from cookbook.helper.unit_conversion_helper import UnitConversionHelper
from cookbook.models import Unit, Food, Ingredient, UnitConversion
def test_base_converter(space_1):
uch = UnitConversionHelper(space_1)
assert uch.convert_from_to('g', 'kg', 1234) == 1.234
assert uch.convert_from_to('kg', 'pound', 2) == 4.40924
# TODO add some more tests and test exception
def test_unit_conversions(space_1, space_2, u1_s1):
with scopes_disabled():
uch = UnitConversionHelper(space_1)
@ -159,4 +166,3 @@ def test_unit_conversions(space_1, space_2, u1_s1):
assert next(x for x in conversions if x.unit == unit_kg_space_2) is not None
assert next(x for x in conversions if x.unit == unit_kg_space_2).amount == 0.1
print(conversions)

View File

@ -821,6 +821,8 @@ class RecipeViewSet(viewsets.ModelViewSet):
'steps__ingredients__step_set',
'steps__ingredients__step_set__recipe_set',
'steps__ingredients__food',
'steps__ingredients__food__foodproperty_set',
'steps__ingredients__food__foodproperty_set__property_type',
'steps__ingredients__food__inherit_fields',
'steps__ingredients__food__supermarket_category',
'steps__ingredients__food__onhand_users',
@ -832,7 +834,8 @@ class RecipeViewSet(viewsets.ModelViewSet):
'steps__ingredients__unit__unit_conversion_base_relation__base_unit',
'steps__ingredients__unit__unit_conversion_converted_relation',
'steps__ingredients__unit__unit_conversion_converted_relation__converted_unit',
'cooklog_set').select_related('nutrition')
'cooklog_set',
).select_related('nutrition')
return super().get_queryset()

View File

@ -46,4 +46,3 @@ pytest-factoryboy==2.5.1
pyppeteer==1.0.2
validators==0.20.0
pytube==12.1.0
pint==0.20.1