Source code for accounts.models

# coding: utf-8

from datetime import date, datetime, timedelta
from pytz import UTC

from django.contrib.auth.models import User
from django.db.models import Count
from django.db.models.signals import post_save
from django.db import models
from django.dispatch import receiver

from app.health.models import Health
from app.shared.models import (
    CreatedAtMixin,
    SHA1TokenMixin,
)
from app.workouts.models import Sport
from .enums import SEX_SELECT


[docs]class UserProfile(models.Model): user = models.OneToOneField(User, related_name='profile') dob = models.DateField(null=True, blank=True) sex = models.CharField( max_length=1, choices=SEX_SELECT, null=True, blank=True, ) height = models.IntegerField(null=True, blank=True) @property def age(self): """ :return: user age in years :rtype: int """ delta = date.today() - self.dob return delta.days // 365 @property def sex_visible(self): """ :return: user sex for template :rtype: str """ for k, v in SEX_SELECT: if k == self.sex: return v @property def last_weight(self): """ Get last user weight :return: tuple of last weight and date of last weighting or None :rtype: tuple """ user = self.user health_list = Health.objects.filter(user=user, weight__isnull=False). \ order_by('-related_date') if health_list: return health_list[0].weight, health_list[0].related_date else: return None @property def bmi(self): """ Compute BMI for last weighting :return: tuple of user BMI and date of last weighting :rtype: tuple """ # validate height try: height_in_meters = float(self.height) / 100 except TypeError: return None # get weight and date try: weight, date_ = self.last_weight except TypeError: return None # compute BMI bmi = weight / height_in_meters ** 2 return round(bmi, 1), date_
[docs] def favourite_sport_method(self, **extra_filters): """ 1. get discipline with most workouts in last year 2. If there is no workouts in last year - get from all workouts :param extra_filters: extra sport queryset filters :return: favourite discipline object """ year_ago = datetime.now(tz=UTC) - timedelta(days=365) sport_base_qs = Sport.objects \ .filter( workout__user=self.user, workout__is_active=True, **extra_filters) \ .annotate(workouts_count=Count('workout')) favourite_sport = sport_base_qs \ .filter(workout__datetime_stop__gt=year_ago) \ .order_by('-workouts_count', '-workout__datetime_stop') \ .first() if favourite_sport: return favourite_sport else: return sport_base_qs \ .order_by('-workouts_count', '-workout__datetime_stop') \ .first()
@property def favourite_sport(self): """ 1. get discipline with most workouts in last year 2. If there is no workouts in last year - get from all workouts :return: favourite discipline object """ return self.favourite_sport_method() @property def favourite_sport_with_distance(self): """ Get favourite discipline with displayable distance. 1. get discipline with most workouts in last year 2. If there is no workouts in last year - get from all workouts :return: favourite discipline with displayable distance object """ return self.favourite_sport_method(show_distances=True)
[docs] def get_sports_in_year(self, year=None): """ Returns list of sports from workouts in given calendar year sorted by workouts number. If year is not given use current year. :param year: int, year :return: sports from given year workouts :rtype: list """ year = year or date.today().year sports = Sport.objects \ .filter( workout__user=self.user, workout__is_active=True, workout__datetime_stop__year=year) \ .annotate(workouts_count=Count('workout')) \ .filter(workouts_count__gt=0) \ .order_by('-workouts_count', '-workout__datetime_stop') return list(sports)
[docs]class UserActivation(CreatedAtMixin, SHA1TokenMixin): user = models.OneToOneField( User, verbose_name=u'Użytkownik', related_name='activation') class Meta: verbose_name = u'aktywacja użytkownika' verbose_name_plural = u'aktywacje użytkowników' @property def activation_link(self): """ Returns user activation link :returns: complete user activation link :rtype: str """ return self.get_activation_link('registration_activation')
[docs]class PasswordReset(CreatedAtMixin, SHA1TokenMixin): user = models.OneToOneField(User, related_name='password_reset')
[docs]class EmailActivation(CreatedAtMixin, SHA1TokenMixin): user = models.OneToOneField(User, related_name='email_activation') email = models.EmailField(verbose_name='Adres email') @property def activation_link(self): """ Get new email activation link :returns: complete email change activation link :rtype: str """ return self.get_activation_link('email_change_confirm')
@receiver(post_save, sender=User)
[docs]def on_user_create(sender, instance, created, **kwargs): if created: # create user activation UserActivation.objects.create(user=instance) # create user extented profile UserProfile.objects.create(user=instance)