class Born(model.Model): """ Abstract base class that adds a `birth_date` field and a virtual field "Age". .. attribute:: birth_date An :class:`IncompleteDateField <lino.core.fields.IncompleteDateField>`. .. attribute:: age Virtual field displaying the age in years. """ class Meta: abstract = True birth_date = fields.IncompleteDateField(blank=True, verbose_name=_("Birth date")) def get_age(self, today=None): """Return the age (in years) of this human. See :meth:`lino.utils.IncompleteDateField.get_age`. """ if self.birth_date: return self.birth_date.get_age(today or settings.SITE.today()) def get_exact_age(self, today=None): """ Return the age as a :class:`datetime.timedelta` object. `ar` is the requesting :class:`ActionRequest` which can be `None` because it is ignored. Optional keyword argument `today` should be a :class:`datetime.date` instance to replace the actual current date. This is used if you want the age at a given date in the past or the future. The default value calls :meth:`dd.Site.today`. """ if self.birth_date and self.birth_date.year: if today is None: today = settings.SITE.today() try: return today - self.birth_date.as_date() except ValueError: pass @fields.displayfield(_("Age")) def age(self, request, today=None): a = self.get_exact_age(today) if a is None: return unicode(_('unknown')) s = _("%d years") % (a.days / 365) if self.birth_date and self.birth_date.is_complete(): return s return u"±" + s
class Born(model.Model): """ Abstract base class that adds a `birth_date` field and a virtual field "Age". .. attribute:: birth_date An :class:`IncompleteDateField <lino.core.fields.IncompleteDateField>`. .. attribute:: age Virtual field displaying the age in years. """ class Meta(object): abstract = True birth_date = fields.IncompleteDateField(blank=True, verbose_name=_("Birth date")) def get_age(self, today=None): """ Return the age (in years) of this human. See :meth:`lino.utils.IncompleteDateField.get_age`. """ if self.birth_date: return self.birth_date.get_age(today or settings.SITE.today()) def get_exact_age(self, today=None): """ Return the age as a :class:`datetime.timedelta` object. Optional keyword argument `today` should be a :class:`datetime.date` instance to replace the actual current date. This is used if you want the age at a given date in the past or the future. The default value calls :meth:`dd.Site.today`. """ # print(20160202, self.birth_date, self) if self.birth_date and self.birth_date.year: if today is None: today = settings.SITE.today() try: return today - self.birth_date.as_date() except ValueError: pass @fields.displayfield(_("Age")) def age(self, ar, today=None): a = self.get_exact_age(today) if a is None: return str(_('unknown')) years = old_div(a.days, 365) if years == 1: s = _("{} year").format(years) else: s = _("{} years").format(years) if years <= 4: months = old_div(a.days - years * 365, 30) if months == 1: s += " " + _("{} month").format(months) else: s += " " + _("{} months").format(months) if self.birth_date and self.birth_date.is_complete(): return s return u"±" + s @classmethod def setup_parameters(cls, fields): fields.update(aged_from=models.IntegerField( _("Aged from"), blank=True, null=True, help_text=_("Select only persons aged at least " "the given number of years.")), aged_to=models.IntegerField( _("Aged to"), blank=True, null=True, help_text=_("Select only persons aged at most " "the given number of years."))) super(Born, cls).setup_parameters(fields) @classmethod def get_request_queryset(cls, ar, **filter): qs = super(Born, cls).get_request_queryset(ar, **filter) pv = ar.param_values today = settings.SITE.today() if pv.aged_from: min_date = today - \ datetime.timedelta(days=pv.aged_from * 365) qs = qs.filter(birth_date__lte=min_date.strftime("%Y-%m-%d")) if pv.aged_to: max_date = today - \ datetime.timedelta(days=pv.aged_to * 365) qs = qs.filter(birth_date__gte=max_date.strftime("%Y-%m-%d")) return qs @classmethod def get_title_tags(self, ar): for t in super(Born, self).get_title_tags(ar): yield t pv = ar.param_values if pv.aged_from or pv.aged_to: yield str( _("Aged %(min)s to %(max)s") % dict(min=pv.aged_from or '...', max=pv.aged_to or '...'))