Skip to content

Flexible Measurement System

Last Modified: 2025-06-07

Overview

The MyBakeLab application now features a comprehensive flexible measurement system that allows users to input recipe ingredients in their preferred units while maintaining the precision needed for baker's percentage calculations.

Key Features

User-Friendly Input

  • Multiple Unit Support: Users can input ingredients using familiar units
  • Automatic Conversions: System handles all conversions behind the scenes
  • Backward Compatibility: Existing recipes continue to work without modification

Supported Unit Types

Weight Units

  • g - Grams
  • kg - Kilograms
  • oz - Ounces
  • lb - Pounds

Volume Units

  • ml - Milliliters
  • l - Liters
  • tsp - Teaspoons
  • tbsp - Tablespoons
  • cup - Cups
  • fl_oz - Fluid Ounces
  • pt - Pints
  • qt - Quarts

Count Units

  • piece - Individual pieces
  • each - Each item

Database Schema

RecipeIngredient Model Changes

New Fields

python
quantity = models.DecimalField(
    max_digits=8,
    decimal_places=3,
    help_text="User-entered quantity in their preferred unit"
)

unit = models.CharField(
    max_length=10,
    choices=UNIT_CHOICES,
    help_text="User-selected measurement unit"
)

Existing Fields (Maintained)

  • weight_grams - Calculated weight for baker's percentages
  • volume_ml - Calculated volume for reference
  • percentage - Baker's percentage (unchanged)

Ingredient Model Enhancements

New Fields for Conversion Support

python
density_g_per_ml = models.DecimalField(
    max_digits=5,
    decimal_places=3,
    null=True,
    blank=True,
    help_text="Density in grams per milliliter for volume conversions"
)

weight_per_piece_g = models.DecimalField(
    max_digits=8,
    decimal_places=2,
    null=True,
    blank=True,
    help_text="Typical weight per piece in grams (for count-based measurements)"
)

Conversion Logic

Weight Conversions

python
# Grams (base unit)
'g': lambda x: x

# Kilograms to grams
'kg': lambda x: x * 1000

# Ounces to grams
'oz': lambda x: x * 28.3495

# Pounds to grams
'lb': lambda x: x * 453.592

Volume Conversions

python
# Volume to weight using ingredient density
def volume_to_grams(volume, unit, density_g_per_ml):
    volume_ml = convert_to_ml(volume, unit)
    return volume_ml * density_g_per_ml

# Volume unit conversions
'ml': lambda x: x
'l': lambda x: x * 1000
'cup': lambda x: x * 236.588
'tsp': lambda x: x * 4.92892
'tbsp': lambda x: x * 14.7868
'fl_oz': lambda x: x * 29.5735

Count Conversions

python
# Count to weight using ingredient-specific data
def count_to_grams(count, ingredient):
    if ingredient.weight_per_piece_g:
        return count * ingredient.weight_per_piece_g
    else:
        raise ValueError("Weight per piece data required")

API Usage

Creating Recipe Ingredients

Request Example

json
{
    "ingredient_id": 1,
    "quantity": "2",
    "unit": "cup",
    "percentage": "75",
    "order_index": 1
}

Response Example

json
{
    "id": 1,
    "ingredient": {
        "id": 1,
        "name": "Bread Flour",
        "density_g_per_ml": "0.570"
    },
    "quantity": "2.000",
    "unit": "cup",
    "weight_grams": "269.86",
    "volume_ml": "473.18",
    "percentage": "75.00",
    "order_index": 1
}

Serializer Fields

Write Fields (User Input)

  • quantity - User-entered amount
  • unit - User-selected unit
  • ingredient_id - Reference to ingredient

Read Fields (Calculated)

  • weight_grams - Calculated weight for baker's percentages
  • volume_ml - Calculated volume for reference
  • ingredient - Full ingredient details

Migration Strategy

Data Preservation

The migration process preserves all existing recipe data:

  1. Add New Fields: quantity and unit fields added with defaults
  2. Migrate Data: Existing weight_grams values copied to quantity with unit='g'
  3. Maintain Compatibility: All existing calculations continue to work

Migration Files

  • 0002_add_flexible_measurements.py - Adds new fields
  • 0003_migrate_existing_quantities.py - Migrates existing data

Benefits

For Users

  • Intuitive Input: Use familiar measurements (cups, teaspoons, pieces)
  • No Manual Conversion: System handles all unit conversions
  • Flexible Workflow: Mix and match units as needed
  • Educational: See conversions between different units

For Developers

  • Backward Compatible: Existing code continues to work
  • Extensible: Easy to add new units or conversion factors
  • Precise: Maintains accuracy for baker's percentage calculations
  • Testable: Comprehensive test coverage for all conversions

Testing

Test Coverage

  • 27/27 Recipe API tests passing (100% success rate)
  • Unit conversion accuracy tests
  • Edge case handling (missing density data, invalid units)
  • Backward compatibility with existing recipes
  • API serialization and validation

Example Test Cases

python
def test_volume_to_weight_conversion():
    # 2 cups of flour with density 0.57 g/ml
    ingredient = create_flour_ingredient(density_g_per_ml=0.57)
    recipe_ingredient = RecipeIngredient.objects.create(
        quantity=2,
        unit='cup',
        ingredient=ingredient
    )

    # Should convert to approximately 270g
    assert abs(recipe_ingredient.weight_grams - 270) < 1

def test_count_conversion():
    # 3 eggs with average weight 50g each
    ingredient = create_ingredient(weight_per_piece_g=50)
    recipe_ingredient = RecipeIngredient.objects.create(
        quantity=3,
        unit='piece',
        ingredient=ingredient
    )

    assert recipe_ingredient.weight_grams == 150

Future Enhancements

Planned Features

  • Temperature Conversions: Celsius/Fahrenheit for baking temperatures
  • Imperial/Metric Preferences: User preference settings
  • Smart Suggestions: Recommend appropriate units based on ingredient type
  • Nutritional Calculations: Automatic nutritional information based on quantities

Extensibility

The system is designed to easily accommodate:

  • New unit types (e.g., metric vs imperial preferences)
  • Regional measurement standards
  • Specialized baking units (baker's dozen, etc.)
  • Integration with kitchen scales and measuring devices

Conclusion

The flexible measurement system significantly improves the user experience while maintaining the precision required for professional baking calculations. Users can now work with familiar units while the system ensures accurate baker's percentages and recipe scaling.

MyBakeLab - Comprehensive Bread-Making Platform

🍞 MyBakeLab - From simple yeasted breads to complex sourdough
Built with Django REST Framework + Vue.js 3 • Deployed on Kubernetes