/apps/users/models.py
Python | 535 lines | 488 code | 16 blank | 31 comment | 0 complexity | 76ba4bde36f3d2984c466616f21e7715 MD5 | raw file
- #-*- coding: utf-8 -*-
- """ users models """
- from datetime import date, datetime, timedelta
- from chartit import DataPool, Chart
- from django.db import models
- from django.contrib.auth.models import User
- from django.core.exceptions import ObjectDoesNotExist
- from django.utils.translation import ugettext_lazy as _
- from .constants import PhysicalActivity, Gender, Goal
- class Base_Macronutrients(models.Model):
- """ abstract class that contains the base macronutrients fields """
- carbohydrates = models.FloatField(
- _(u'carbohydrates'), default=0, editable=False)
- protein = models.FloatField(
- _(u'proteins'), default=0, editable=False)
- fat = models.FloatField(_(u'grasas'), default=0, editable=False)
- calories = models.FloatField(_(u'calories'), default=0, editable=False)
- class Meta:
- """ model meta options """
- abstract = True
- def calculate_calories(self):
- """
- returns the calories based on the quantity of carbohydrates, protein
- and fat
- """
- return self.carbohydrates * 4 + self.protein * 4 + self.fat * 9
- # def save(self, *args, **kwargs):
- # """ recalculates the calories before saving """
- # self.calories = self.calculate_calories()
- # super(self.__class__, self).save(*args, **kwargs)
- class UserProfile(models.Model):
- """ stores additional user information """
- height = models.FloatField(_('height'), help_text=_(u'In meters.'))
- weight = models.FloatField(_('weight'), help_text=_(u'In kilos.'))
- physical_activity = models.CharField(
- _('physical activity'), max_length=1, choices=PhysicalActivity.CHOICES)
- goal = models.CharField(_('goal'), max_length=1, choices=Goal.CHOICES)
- gender = models.CharField(
- _('gender'), max_length=1, choices=Gender.CHOICES)
- birthday = models.DateField(_('birthday'))
- body_fat_percent = models.FloatField(
- _('body fat percent'), help_text=_("example: 13.1"))
- bmr = models.FloatField(help_text=_(u'Basal Metabollic Rate'))
- tee = models.FloatField(help_text=_(u'Total Energy Expenditure'))
- # rdi (recommended dietary intake)
- recalculate_rdis = models.BooleanField(
- _('Calculate RDIs'), default=True,
- help_text=_('Let the application calculate the recommended dietary '
- 'intake values')
- )
- rdi_carbohydrates = models.FloatField(
- _(u'carbohydrates'),
- help_text=_(u'Recommended dietary intake in grams.'))
- rdi_protein = models.FloatField(
- _(u'protein'), help_text=_(u'Recommended dietary intake in grams.'))
- rdi_fat = models.FloatField(
- _(u'fat'), help_text=_(u'Recommended dietary intake in grams.'))
- calories = models.FloatField(_('calories'))
- # user = models.ForeignKey(User, unique=True)
- user = models.OneToOneField(User, verbose_name=_('user'))
- class Meta:
- """ model meta options """
- ordering = ['user__last_name']
- verbose_name = _('User Profile')
- verbose_name_plural = _('User Profiles')
- def __unicode__(self):
- return u'%s' % self.user.get_full_name()
- @property
- def lean_body_mass(self):
- """ returns the lean body mass """
- return self.weight * (1 - (self.body_fat_percent/100))
- def calculate_bmr(self):
- """
- returns the calculated Basal Metabollic Rate using the Katch-McArdle
- formula.
- """
- return 370 + (21.6 * self.lean_body_mass)
- def get_bmr(self):
- """
- returns the Basal Metabollic Rate (if it doesn't exist it's
- calculated)
- """
- if not self.bmr:
- return self.calculate_bmr()
- return self.bmr
- def calculate_tee(self):
- """ returns the calculated Total Energy Expenditure """
- return self.get_bmr() * PhysicalActivity.get_activity_factor(
- self.physical_activity) * Goal.get_calories_factor(self.goal)
- def get_tee(self):
- """
- returns the Total Energy Expenditure (if it doesn't exist it's
- calculated)
- """
- if not self.tee:
- self.calculate_tee()
- return self.tee
- @property
- def protein_requirement(self):
- """
- returns the protein's requirement based on the physical activity and
- lean body mass
- # note: instead of weight the lean_body_mass used to be used here...
- """
- return PhysicalActivity.get_protein_requirement(
- self.physical_activity) * self.weight * \
- Goal.get_protein_factor(self.goal)
- @property
- def fat_requirement(self):
- """ returns the fat's requirement based on goal """
- return self.rdi_protein * Goal.get_fat_factor(self.goal)
- @property
- def carbs_requirement(self):
- """ returns the carbs' requirement based on goal """
- # # carbs calculated from the rest o calories
- # carbs = (
- # self.get_tee() - (self.rdi_protein * 4) - (self.rdi_fat * 9)
- # ) / 4
- return Goal.get_carbs_factor(self.goal) * self.weight
-
- def calculate_rdis(self):
- """
- Your lean body mass is just your body weight minus your body fat.
- # protein:
- factor proteing in grams for lean body mass
- upper limit: 0.82g/lb or 1.8/kg (very safe) 1g/lb (safe)
- to preserver or build: 0.82g/lb or 1.8/kg
- maintain lean body mass: 0.73g/lb?
- when cutting: no more than 0.82g/lb (to 2g/lb?)
-
- .5 - no sports or training
- .6 - jogger or light fitness training (light activity)
- .7 - moderate training, 3x per week
- .8 - moderate daily weight training or aerobics
- .9 - heavy weight training (very active)
- (Intense weight training 3-4 days per week or other
- daily high volume exercise)
- 1.0 - heavy weight training daily ( Elite Athlete or weight
- training >5 days per week)
- 1.5 - heavy weight training daily, plus cardio 3x per week
- # carbs
- # from http://www.labrada.com/blog/lees-corner/how-to-use-a-low-carb-diet-to-burn-fat-without-losing-muscle/
- bulking: 1.5 - 2 g/pound
- 2:1 ratio of carbs to protein?
- reduced carb diet to get ripped: 0.75 - 1 g of complex carb/pound
- # fat
- To get and stay lean multiply your daily grams of protein by 21%
- Grams of Protein * .21 = Your Daily Grams of fat
- volume training: factor = 0.42
- cutting: 17 and 28 percent of your total calorie intake
- """
- self.rdi_protein = self.protein_requirement
- self.rdi_fat = self.fat_requirement
- self.rdi_carbohydrates = self.carbs_requirement
- def calculate_calories(self):
- """
- returns the calories based on the quantity of carbohydrates, protein
- and fat
- """
- return self.rdi_carbohydrates * 4 + self.rdi_protein * 4 + \
- self.rdi_fat * 9
- def save(self, *args, **kwargs):
- """
- * Recalculates the calories, bmr and tee before saving
- * If recalculate_rdis is selected then recalculates the rdis
- """
- self.bmr = self.calculate_bmr()
- self.tee = self.calculate_tee()
- if self.recalculate_rdis:
- self.calculate_rdis()
- self.calories = self.calculate_calories()
- super(self.__class__, self).save(*args, **kwargs)
- def get_rdis(self):
- """ returns a tuple with the profile RDI values """
- return (self.rdi_protein, self.rdi_carbohydrates, self.rdi_fat)
- def pie_chart(self):
- """ Creates the Chart obj and returns it """
- user_data = \
- DataPool(
- series=[{
- 'options': {
- 'source': UserProfile.objects.filter(id=self.id),
- 'categories':['rdi_carbohydrates',
- 'rdi_protein', 'user',
- 'rdi_fat']
- },
- 'terms': ['rdi_carbohydrates', 'rdi_protein', 'user',
- 'rdi_fat']
- }]
- )
- cht = Chart(datasource=user_data,
- series_options=[{
- 'options':{
- 'type': 'column',
- 'stacking':False},
- 'terms':{
- 'user':['rdi_carbohydrates', 'rdi_protein',
- 'rdi_fat'], }
- }],
- chart_options={
- 'title': {'text': 'Column Chart of RDI (Recommended \
- Diertary Intake)'},
- 'xAxis': {
- 'title': {
- 'text': 'Base Macronutrients'}},
- 'yAxis': {
- 'title': {
- 'text': 'Grams'}}})
- return cht
- def get_latest_daily_consume(self):
- """
- returns the lastest daily consume or if it does not exist returns None
- """
- try:
- last_daily_consume = self.user.daily_consume_set.latest('id')
- except ObjectDoesNotExist:
- return None
- else:
- return last_daily_consume
- # def create_user_profile(sender, instance, created, **kwargs):
- # """ """
- # if created:
- # UserProfile.objects.create(user=instance)
- # post_save.connect(create_user_profile, sender=User)
- class Daily_Consume(Base_Macronutrients):
- """ stores the user daily consume """
- date = models.DateField(_('date'), default=date.today)
- user = models.ForeignKey('auth.User', verbose_name=_('user'))
- class Meta:
- """ model meta options """
- ordering = ['-date']
- verbose_name = _('Daily consume')
- verbose_name_plural = _('Daily consumes')
- def __unicode__(self):
- return u'%s' % self.date.strftime('%d/%m/%y')
- def update_values(self):
- """ udpates the base macronutrients values """
- self.carbohydrates = 0
- self.protein = 0
- self.fat = 0
- self.calories = 0
- for meal in self.meal_set.all():
- self.carbohydrates += meal.carbohydrates
- self.protein += meal.protein
- self.fat += meal.fat
- self.calories += meal.calories
- self.save()
- def save(self, *args, **kwargs):
- """ recalculates the calories before saving """
- #self.calories = self.calculate_calories()
- super(Daily_Consume, self).save(*args, **kwargs)
- def data_total_intake_chart(self):
- """ returns the rdi's values and the intake of the day """
- profile = self.user.userprofile
- return (
- (profile.rdi_protein, profile.rdi_carbohydrates, profile.rdi_fat),
- (self.protein, self.carbohydrates, self.fat),
- (profile.calories, self.calories)
- )
- def week_day(self, obj_id):
- """
- returns the fully weekday name and the month day of the Daily_Consume
- date with id = obj_id
- """
- return Daily_Consume.objects.get(id=obj_id).date.strftime('%A %d')
- def weekly_chart(self):
- """ Creates the Chart obj and returns it """
- monday = self.date - timedelta(days=(self.date.isocalendar()[2] - 1))
- sunday = monday + timedelta(days=6)
- user_data = \
- DataPool(
- series=[{
- 'options': {
- 'source': Daily_Consume.objects.filter(
- user=self.user).filter(date__gte=monday).filter(
- date__lte=sunday),
- },
- 'terms': ['protein',
- 'carbohydrates',
- 'fat',
- 'id'
- ]
- }]
- )
- cht = Chart(datasource=user_data,
- series_options=[{
- 'options':{
- 'type': 'line',
- 'stacking': False},
- 'terms':{
- 'id':['protein',
- 'carbohydrates',
- 'fat'
- ], }
- }],
- chart_options={
- 'title': {'text': "Current Week's Dietary Intake"},
- 'xAxis': {
- 'title': {
- 'text': 'Day'}},
- 'yAxis': {
- 'title': {
- 'text': 'Grams'}}},
- x_sortf_mapf_mts=(None, self.week_day, False)
- )
- return cht
- def meal_number(self, obj_id):
- """
- returns a string with the meal's time
- """
- return Meal.objects.get(id=obj_id).time.strftime('%I:%M %p')
- def day_consume_chart(self):
- """ Creates the Chart obj and returns it """
- user_data = \
- DataPool(
- series=[{
- 'options': {
- 'source': self.meal_set.all(),
- },
- 'terms': ['protein', 'carbohydrates', 'fat', 'id']
- }]
- )
- cht = Chart(datasource=user_data,
- series_options=[{
- 'options':{
- 'type': 'line',
- 'stacking': False},
- 'terms':{
- 'id':['protein',
- 'carbohydrates',
- 'fat',
- ], }
- }],
- chart_options={
- 'title': {'text': "Day's Dietary Intake"},
- 'xAxis': {
- 'title': {
- 'text': 'Meals'}},
- 'yAxis': {
- 'title': {
- 'text': 'Grams'}}},
- x_sortf_mapf_mts=(None, self.meal_number, False)
- )
- return cht
- def get_current_time():
- """ returns the current time """
- return datetime.now().time()
- class Meal(Base_Macronutrients):
- """ stores the macronutrients of one meal """
- time = models.TimeField(_('time'), default=get_current_time)
- daily_consume = models.ForeignKey(
- Daily_Consume, verbose_name=_('daily consume'))
- foods = models.ManyToManyField(
- 'foods.Food', through='MealFood', verbose_name=_('foods'))
- class Meta:
- """ meta class definitions """
- verbose_name = _('Meal')
- verbose_name_plural = _('Meals')
- def __unicode__(self):
- return u'%s %s' % (self.daily_consume.date.strftime(
- '%d/%m/%y'), self.time.strftime('%I:%M:%S %p'))
- def update_values(self):
- """
- recalculates the macronutrients and calories based on the food amount
- of food selected.
- Updates the values in the related daily_consume object
- """
- self.carbohydrates = 0
- self.protein = 0
- self.fat = 0
- self.calories = 0
- tmp = 0
- for mealfood in self.mealfood_set.all():
- # tmp = mealfood.grams / mealfood.food.grams
- if mealfood.grams:
- tmp = mealfood.grams / mealfood.food.grams
- else:
- tmp = (mealfood.presentation.grams / mealfood.food.grams)
- if mealfood.presentation_multiplier:
- tmp *= float(mealfood.presentation_multiplier)
- self.carbohydrates += tmp * mealfood.food.carbohydrates
- self.protein += tmp * mealfood.food.protein
- self.fat += tmp * mealfood.food.fat
- self.calories += tmp * mealfood.food.calories
- self.save()
- self.daily_consume.update_values()
- def meal_number(self, obj_id):
- """
- returns a string with the meal's time
- """
- return Meal.objects.get(id=obj_id).time.strftime('%I:%M %p')
- def day_consume_chart(self):
- """ Creates the Chart obj and returns it """
- user_data = \
- DataPool(
- series=[{
- 'options': {
- 'source': Meal.objects.filter(
- daily_consume=self.daily_consume),
- },
- 'terms': ['protein', 'carbohydrates', 'fat', 'id']
- }]
- )
- cht = Chart(datasource=user_data,
- series_options=[{
- 'options':{
- 'type': 'line',
- 'stacking': False},
- 'terms':{
- 'id':['protein',
- 'carbohydrates',
- 'fat',
- ], }
- }],
- chart_options={
- 'title': {'text': "Day's Dietary Intake"},
- 'xAxis': {
- 'title': {
- 'text': 'Meals'}},
- 'yAxis': {
- 'title': {
- 'text': 'Grams'}}},
- x_sortf_mapf_mts=(None, self.meal_number, False)
- )
- return cht
- def get_macronutrients_values(self):
- """
- returns the proteins, carbohydrates and fats of the current meal
- """
- return (self.protein, self.carbohydrates, self.fat)
- class MealFood(models.Model):
- """ intermediary table between Meal and Food """
- meal = models.ForeignKey(Meal, verbose_name=_('meal'))
- food = models.ForeignKey('foods.Food', verbose_name=_('food'))
- grams = models.FloatField(_('grams'), blank=True, null=True)
- presentation = models.ForeignKey(
- 'foods.Presentation', blank=True, null=True,
- verbose_name=_('presentation')
- )
- presentation_multiplier = models.DecimalField(
- _('presentation multiplier'),
- max_digits=4, decimal_places=2,
- help_text=_('Multiplies the presentation per X times'),
- blank=True, null=True
- )
- class Meta:
- """ meta class definitions """
- verbose_name = _('Meal-Food')
- verbose_name_plural = _('Meals-Foods')
- def save(self, *args, **kwargs):
- """
- saves the mealfood object and updates the macronutrients and calories
- values of the related meal
- """
- super(self.__class__, self).save(*args, **kwargs)
- self.meal.update_values()
- def get_html_options_presentations(self):
- """ returns the html just the options presentations of the food """
- options = "<option value=''>Select a presentation</option>"
- tpl = "<option value='{}'{}>{}</option>"
- if self.presentation:
- for presentation in self.food.presentation_set.all():
- if self.presentation == presentation:
- selected = " selected='selected'"
- else:
- selected = ""
- options += tpl.format(
- presentation.id, selected, presentation.name)
- else:
- options = self.food.get_html_options_presentations()
- return options