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- Gramskg- Kilogramsoz- Ounceslb- Pounds
Volume Units
ml- Millilitersl- Literstsp- Teaspoonstbsp- Tablespoonscup- Cupsfl_oz- Fluid Ouncespt- Pintsqt- Quarts
Count Units
piece- Individual pieceseach- 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 percentagesvolume_ml- Calculated volume for referencepercentage- 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.592Volume 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.5735Count 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 amountunit- User-selected unitingredient_id- Reference to ingredient
Read Fields (Calculated)
weight_grams- Calculated weight for baker's percentagesvolume_ml- Calculated volume for referenceingredient- Full ingredient details
Migration Strategy
Data Preservation
The migration process preserves all existing recipe data:
- Add New Fields:
quantityandunitfields added with defaults - Migrate Data: Existing
weight_gramsvalues copied toquantitywithunit='g' - Maintain Compatibility: All existing calculations continue to work
Migration Files
0002_add_flexible_measurements.py- Adds new fields0003_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 == 150Future 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.