class Meal(models.Model): """ A meal """ # Metaclass to set some other properties class Meta: ordering = ["time", ] plan = models.ForeignKey(NutritionPlan, verbose_name=_('Nutrition plan'), editable=False, on_delete=models.CASCADE) order = models.IntegerField(verbose_name=_('Order'), blank=True, editable=False) time = Html5TimeField(null=True, blank=True, verbose_name=_('Time (approx)')) def __str__(self): """ Return a more human-readable representation """ return "{0} Meal".format(self.order) def get_owner_object(self): """ Returns the object that has owner information """ return self.plan def get_nutritional_values(self, use_metric=True): """ Sums the nutrional info of all items in the meal :param use_metric Flag that controls the units used """ nutritional_info = {'energy': 0, 'protein': 0, 'carbohydrates': 0, 'carbohydrates_sugar': 0, 'fat': 0, 'fat_saturated': 0, 'fibres': 0, 'sodium': 0} # Get the calculated values from the meal item and add them for item in self.mealitem_set.select_related(): values = item.get_nutritional_values(use_metric=use_metric) for key in nutritional_info.keys(): nutritional_info[key] += values[key] # Only 2 decimal places, anything else doesn't make sense for i in nutritional_info: nutritional_info[i] = Decimal(nutritional_info[i]).quantize(TWOPLACES) return nutritional_info
class MealItem(models.Model): ''' An item (component) of a meal ''' # Metaclass to set some other properties class Meta: ordering = [ "time", ] meal = models.ForeignKey(Meal, verbose_name=_('Nutrition plan'), editable=False) ingredient = models.ForeignKey(Ingredient, verbose_name=_('Ingredient')) weight_unit = models.ForeignKey( IngredientWeightUnit, verbose_name=_('Weight unit'), null=True, blank=True, ) order = models.IntegerField(verbose_name=_('Order'), blank=True, editable=False) amount = models.DecimalField( decimal_places=2, max_digits=6, verbose_name=_('Amount'), validators=[MinValueValidator(1), MaxValueValidator(1000)]) PLANNED = 'PLANNED' EATEN = 'EATEN' TYPE_CHOICES = ((PLANNED, 'Planned'), (EATEN, 'Eaten')) type = models.CharField(max_length=20, choices=TYPE_CHOICES, default=PLANNED) time = Html5TimeField(null=True, blank=True, verbose_name=_('Time (approx)')) def __str__(self): ''' Return a more human-readable representation ''' return u"{0}g ingredient {1}".format(self.amount, self.ingredient_id) def get_owner_object(self): ''' Returns the object that has owner information ''' return self.meal.plan def get_unit_type(self): ''' Returns the type of unit used: - a value in grams - a 'human' unit like 'a cup' or 'a slice' ''' if self.weight_unit: return MEALITEM_WEIGHT_UNIT else: return MEALITEM_WEIGHT_GRAM def get_nutritional_values(self, use_metric=True): ''' Sums the nutrional info for the ingredient in the MealItem :param use_metric Flag that controls the units used ''' nutritional_info = { 'energy': 0, 'protein': 0, 'carbohydrates': 0, 'carbohydrates_sugar': 0, 'fat': 0, 'fat_saturated': 0, 'fibres': 0, 'sodium': 0 } # Calculate the base weight of the item if self.get_unit_type() == MEALITEM_WEIGHT_GRAM: item_weight = self.amount else: item_weight = (self.amount * self.weight_unit.amount * self.weight_unit.gram) nutritional_info[ 'energy'] += self.ingredient.energy * item_weight / 100 nutritional_info[ 'protein'] += self.ingredient.protein * item_weight / 100 nutritional_info[ 'carbohydrates'] += self.ingredient.carbohydrates * item_weight / 100 if self.ingredient.carbohydrates_sugar: nutritional_info['carbohydrates_sugar'] += self.ingredient.carbohydrates_sugar \ * item_weight / 100 nutritional_info['fat'] += self.ingredient.fat * item_weight / 100 if self.ingredient.fat_saturated: nutritional_info[ 'fat_saturated'] += self.ingredient.fat_saturated * item_weight / 100 if self.ingredient.fibres: nutritional_info[ 'fibres'] += self.ingredient.fibres * item_weight / 100 if self.ingredient.sodium: nutritional_info[ 'sodium'] += self.ingredient.sodium * item_weight / 100 # If necessary, convert weight units if not use_metric: for key, value in nutritional_info.items(): # Energy is not a weight! if key == 'energy': continue # Everything else, to ounces nutritional_info[key] = AbstractWeight(value, 'g').oz # Only 2 decimal places, anything else doesn't make sense for i in nutritional_info: nutritional_info[i] = Decimal( nutritional_info[i]).quantize(TWOPLACES) return nutritional_info def get_type(self): ''' Return the meal type. Either PLANNED or EATEN :return: ''' return self.type
class Meal(models.Model): ''' A meal ''' # Metaclass to set some other properties class Meta: ordering = [ "time", ] plan = models.ForeignKey(NutritionPlan, verbose_name=_('Nutrition plan'), editable=False) order = models.IntegerField(verbose_name=_('Order'), max_length=1, blank=True, editable=False) time = Html5TimeField(null=True, blank=True, verbose_name=_('Time (approx)')) def __unicode__(self): ''' Return a more human-readable representation ''' return u"{0} Meal".format(self.order) def get_owner_object(self): ''' Returns the object that has owner information ''' return self.plan def get_nutritional_values(self): ''' Sums the nutrional info of all items in the meal ''' nutritional_info = { 'energy': 0, 'protein': 0, 'carbohydrates': 0, 'carbohydrates_sugar': 0, 'fat': 0, 'fat_saturated': 0, 'fibres': 0, 'sodium': 0 } # Get the calculated values from the meal item and add them for item in self.mealitem_set.select_related(): values = item.get_nutritional_values() nutritional_info['energy'] += values['energy'] nutritional_info['protein'] += values['protein'] nutritional_info['carbohydrates'] += values['carbohydrates'] nutritional_info['carbohydrates_sugar'] += values[ 'carbohydrates_sugar'] nutritional_info['fat'] += values['fat'] nutritional_info['fat_saturated'] += values['fat_saturated'] nutritional_info['fibres'] += values['fibres'] nutritional_info['sodium'] += values['sodium'] # Only 2 decimal places, anything else doesn't make sense for i in nutritional_info: nutritional_info[i] = Decimal( nutritional_info[i]).quantize(TWOPLACES) return nutritional_info