mybuddy/core/models.py

703 lines
21 KiB
Python
Raw Normal View History

2017-08-13 15:20:09 +00:00
# -*- coding: utf-8 -*-
import random
2022-03-08 13:48:27 +00:00
import re
from datetime import timedelta
2022-02-20 11:40:06 +00:00
from typing import Iterable, Optional
from django.conf import settings
from django.core.cache import cache
from django.core.exceptions import ValidationError
2017-08-11 18:32:02 +00:00
from django.db import models
from django.utils.text import slugify
from django.utils import timezone
from django.utils.text import format_lazy
from django.utils.translation import gettext_lazy as _
2022-02-15 21:24:13 +00:00
from django.core.validators import RegexValidator
2022-03-02 22:31:11 +00:00
from taggit.managers import TaggableManager as TaggitTaggableManager
from taggit.models import TagBase, GenericTaggedItemBase
2022-02-27 20:12:01 +00:00
random.seed()
2022-02-15 21:24:13 +00:00
2022-02-27 19:00:12 +00:00
2017-11-10 02:15:09 +00:00
def validate_date(date, field_name):
"""
Confirm that a date is not in the future.
:param date: a timezone aware date instance.
:param field_name: the name of the field being checked.
:return:
"""
if date and date > timezone.localdate():
raise ValidationError(
2022-02-10 00:00:30 +00:00
{field_name: _("Date can not be in the future.")}, code="date_invalid"
)
2017-11-10 02:15:09 +00:00
def validate_duration(model, max_duration=timedelta(hours=24)):
"""
Basic sanity checks for models with a duration
:param model: a model instance with 'start' and 'end' attributes
:param max_duration: maximum allowed duration between start and end time
:return:
"""
if model.start and model.end:
if model.start > model.end:
2017-11-01 20:14:42 +00:00
raise ValidationError(
2022-02-10 00:00:30 +00:00
_("Start time must come before end time."), code="end_before_start"
)
if model.end - model.start > max_duration:
2022-02-10 00:00:30 +00:00
raise ValidationError(_("Duration too long."), code="max_duration")
2017-08-11 18:32:02 +00:00
2017-08-13 14:48:16 +00:00
def validate_unique_period(queryset, model):
"""
Confirm that model's start and end date do not intersect with other
instances.
:param queryset: a queryset of instances to check against.
:param model: a model instance with 'start' and 'end' attributes
:return:
"""
if model.id:
queryset = queryset.exclude(id=model.id)
if model.start and model.end:
if queryset.filter(start__lt=model.end, end__gt=model.start):
raise ValidationError(
2022-02-10 00:00:30 +00:00
_("Another entry intersects the specified time period."),
code="period_intersection",
)
def validate_time(time, field_name):
"""
Confirm that a time is not in the future.
:param time: a timezone aware datetime instance.
:param field_name: the name of the field being checked.
:return:
"""
if time and time > timezone.localtime():
raise ValidationError(
2022-02-10 00:00:30 +00:00
{field_name: _("Date/time can not be in the future.")}, code="time_invalid"
)
2022-02-15 21:24:13 +00:00
def random_color():
2022-02-27 19:00:12 +00:00
TAG_COLORS = [
2022-03-08 11:55:50 +00:00
"#ff0000",
"#00ff00",
"#0000ff",
"#ff00ff",
"#ffff00",
"#00ffff",
"#ff7f7f",
"#7fff7f",
"#7f7fff",
"#ff7fff",
"#ffff7f",
"#7fffff",
"#7f0000",
"#007f00",
"#00007f",
"#7f007f",
"#7f7f00",
"#007f7f",
2022-02-27 19:00:12 +00:00
]
2022-02-15 21:24:13 +00:00
return TAG_COLORS[random.randrange(0, len(TAG_COLORS))]
2022-02-15 09:13:35 +00:00
2022-02-27 19:00:12 +00:00
class Tag(TagBase):
2022-02-15 09:13:35 +00:00
class Meta:
2022-04-03 23:42:23 +00:00
verbose_name = _("Tag")
verbose_name_plural = _("Tags")
2022-02-27 19:00:12 +00:00
2022-02-15 09:13:35 +00:00
color = models.CharField(
verbose_name=_("Color"),
2022-02-15 09:13:35 +00:00
max_length=32,
2022-02-15 21:24:13 +00:00
default=random_color,
2022-03-08 11:55:50 +00:00
validators=[RegexValidator(r"^#[0-9a-fA-F]{6}$")],
2022-02-15 09:13:35 +00:00
)
last_used = models.DateTimeField(
verbose_name=_("Last used"),
2022-02-27 20:12:01 +00:00
default=timezone.now,
2022-02-15 09:13:35 +00:00
blank=False,
)
2022-03-08 13:48:27 +00:00
@property
def complementary_color(self):
DARK, LIGHT = "#101010", "#EFEFEF"
2022-03-08 13:48:27 +00:00
if not self.color:
return DARK
r, g, b = [int(x, 16) for x in re.match("#(..)(..)(..)", self.color).groups()]
yiq = ((r * 299) + (g * 587) + (b * 114)) // 1000
if yiq >= 128:
return DARK
else:
return LIGHT
2022-02-15 09:13:35 +00:00
class Tagged(GenericTaggedItemBase):
2022-02-15 09:13:35 +00:00
tag = models.ForeignKey(
Tag,
verbose_name=_("Tag"),
2022-02-15 09:13:35 +00:00
on_delete=models.CASCADE,
related_name="%(app_label)s_%(class)s_items",
)
2022-02-20 11:40:06 +00:00
def save_base(self, *args, **kwargs):
"""
Update last_used of the used tag, whenever it is used in a
save-operation.
"""
2022-02-27 20:12:01 +00:00
self.tag.last_used = timezone.now()
2022-02-20 11:40:06 +00:00
self.tag.save()
return super().save_base(*args, **kwargs)
2022-03-02 22:31:11 +00:00
class TaggableManager(TaggitTaggableManager):
"""
2022-03-08 11:01:51 +00:00
Replace the default help_text with
"""
2022-02-27 19:00:12 +00:00
def __init__(self, *args, **kwargs):
kwargs["help_text"] = _(
"Click on the tags to add (+) or remove (-) tags or use the text editor to create new tags."
)
super().__init__(*args, **kwargs)
def formfield(self, *args, **kwargs):
# Local import required because .widgets imports .models
from core.widgets import TagsEditor
kwargs["widget"] = TagsEditor
return super().formfield(*args, **kwargs)
2022-02-27 19:00:12 +00:00
2017-08-16 12:49:58 +00:00
class Child(models.Model):
2022-02-10 00:00:30 +00:00
model_name = "child"
first_name = models.CharField(max_length=255, verbose_name=_("First name"))
2021-12-29 21:41:39 +00:00
last_name = models.CharField(
2022-02-10 00:00:30 +00:00
blank=True, max_length=255, verbose_name=_("Last name")
)
2022-02-10 00:00:30 +00:00
birth_date = models.DateField(blank=False, null=False, verbose_name=_("Birth date"))
slug = models.SlugField(
allow_unicode=True,
blank=False,
editable=False,
max_length=100,
unique=True,
2022-02-10 00:00:30 +00:00
verbose_name=_("Slug"),
)
picture = models.ImageField(
2022-02-10 00:00:30 +00:00
blank=True, null=True, upload_to="child/picture/", verbose_name=_("Picture")
)
2017-08-13 14:48:16 +00:00
objects = models.Manager()
2022-02-10 00:00:30 +00:00
cache_key_count = "core.child.count"
2017-08-13 14:48:16 +00:00
class Meta:
2022-02-10 00:00:30 +00:00
default_permissions = ("view", "add", "change", "delete")
ordering = ["last_name", "first_name"]
verbose_name = _("Child")
verbose_name_plural = _("Children")
2017-08-13 14:48:16 +00:00
def __str__(self):
2021-12-29 21:41:39 +00:00
return self.name()
2017-08-13 14:48:16 +00:00
2017-08-18 12:08:23 +00:00
def save(self, *args, **kwargs):
self.slug = slugify(self, allow_unicode=True)
2017-08-18 12:08:23 +00:00
super(Child, self).save(*args, **kwargs)
cache.set(self.cache_key_count, Child.objects.count(), None)
def delete(self, using=None, keep_parents=False):
super(Child, self).delete(using, keep_parents)
cache.set(self.cache_key_count, Child.objects.count(), None)
2017-08-18 12:08:23 +00:00
def name(self, reverse=False):
2021-12-29 21:41:39 +00:00
if not self.last_name:
return self.first_name
if reverse:
2022-02-10 00:00:30 +00:00
return "{}, {}".format(self.last_name, self.first_name)
return "{} {}".format(self.first_name, self.last_name)
@classmethod
def count(cls):
2022-02-10 00:00:30 +00:00
"""Get a (cached) count of total number of Child instances."""
return cache.get_or_set(cls.cache_key_count, Child.objects.count, None)
2017-08-13 14:48:16 +00:00
2017-08-13 19:51:25 +00:00
class DiaperChange(models.Model):
2022-02-10 00:00:30 +00:00
model_name = "diaperchange"
2017-12-03 21:52:27 +00:00
child = models.ForeignKey(
2022-02-10 00:00:30 +00:00
"Child",
on_delete=models.CASCADE,
2022-02-10 00:00:30 +00:00
related_name="diaper_change",
verbose_name=_("Child"),
2019-04-19 02:55:55 +00:00
)
2022-02-10 00:00:30 +00:00
time = models.DateTimeField(blank=False, null=False, verbose_name=_("Time"))
wet = models.BooleanField(verbose_name=_("Wet"))
solid = models.BooleanField(verbose_name=_("Solid"))
color = models.CharField(
blank=True,
choices=[
2022-02-10 00:00:30 +00:00
("black", _("Black")),
("brown", _("Brown")),
("green", _("Green")),
("yellow", _("Yellow")),
],
max_length=255,
2022-02-10 00:00:30 +00:00
verbose_name=_("Color"),
)
2022-02-10 00:00:30 +00:00
amount = models.FloatField(blank=True, null=True, verbose_name=_("Amount"))
notes = models.TextField(blank=True, null=True, verbose_name=_("Notes"))
tags = TaggableManager(blank=True, through=Tagged)
2017-08-13 19:51:25 +00:00
objects = models.Manager()
class Meta:
2022-02-10 00:00:30 +00:00
default_permissions = ("view", "add", "change", "delete")
ordering = ["-time"]
verbose_name = _("Diaper Change")
verbose_name_plural = _("Diaper Changes")
2017-08-13 19:51:25 +00:00
def __str__(self):
2022-02-10 00:00:30 +00:00
return str(_("Diaper Change"))
2017-08-13 19:51:25 +00:00
2017-08-18 15:00:58 +00:00
def attributes(self):
attributes = []
if self.wet:
2022-02-10 00:00:30 +00:00
attributes.append(self._meta.get_field("wet").verbose_name)
2017-08-18 15:00:58 +00:00
if self.solid:
2022-02-10 00:00:30 +00:00
attributes.append(self._meta.get_field("solid").verbose_name)
2017-08-18 15:00:58 +00:00
if self.color:
attributes.append(self.get_color_display())
2017-08-18 15:00:58 +00:00
return attributes
2017-11-01 20:14:42 +00:00
def clean(self):
2022-02-10 00:00:30 +00:00
validate_time(self.time, "time")
2017-11-01 20:14:42 +00:00
# One or both of Wet and Solid is required.
if not self.wet and not self.solid:
raise ValidationError(
2022-02-10 00:00:30 +00:00
_("Wet and/or solid is required."), code="wet_or_solid"
)
2017-11-01 20:14:42 +00:00
2017-08-13 19:51:25 +00:00
2017-08-13 15:59:14 +00:00
class Feeding(models.Model):
2022-02-10 00:00:30 +00:00
model_name = "feeding"
2017-12-03 21:52:27 +00:00
child = models.ForeignKey(
2022-02-10 00:00:30 +00:00
"Child",
on_delete=models.CASCADE,
2022-02-10 00:00:30 +00:00
related_name="feeding",
verbose_name=_("Child"),
)
2022-02-10 00:00:30 +00:00
start = models.DateTimeField(blank=False, null=False, verbose_name=_("Start time"))
end = models.DateTimeField(blank=False, null=False, verbose_name=_("End time"))
duration = models.DurationField(
2022-02-10 00:00:30 +00:00
editable=False, null=True, verbose_name=_("Duration")
)
type = models.CharField(
choices=[
2022-02-10 00:00:30 +00:00
("breast milk", _("Breast milk")),
("formula", _("Formula")),
("fortified breast milk", _("Fortified breast milk")),
("solid food", _("Solid food")),
],
max_length=255,
2022-02-10 00:00:30 +00:00
verbose_name=_("Type"),
)
method = models.CharField(
choices=[
2022-02-10 00:00:30 +00:00
("bottle", _("Bottle")),
("left breast", _("Left breast")),
("right breast", _("Right breast")),
("both breasts", _("Both breasts")),
("parent fed", _("Parent fed")),
("self fed", _("Self fed")),
],
max_length=255,
2022-02-10 00:00:30 +00:00
verbose_name=_("Method"),
)
2022-02-10 00:00:30 +00:00
amount = models.FloatField(blank=True, null=True, verbose_name=_("Amount"))
notes = models.TextField(blank=True, null=True, verbose_name=_("Notes"))
tags = TaggableManager(blank=True, through=Tagged)
2017-08-13 15:59:14 +00:00
objects = models.Manager()
class Meta:
2022-02-10 00:00:30 +00:00
default_permissions = ("view", "add", "change", "delete")
ordering = ["-start"]
verbose_name = _("Feeding")
verbose_name_plural = _("Feedings")
2017-08-13 15:59:14 +00:00
def __str__(self):
2022-02-10 00:00:30 +00:00
return str(_("Feeding"))
2017-08-13 15:59:14 +00:00
def save(self, *args, **kwargs):
if self.start and self.end:
self.duration = self.end - self.start
super(Feeding, self).save(*args, **kwargs)
def clean(self):
2022-02-10 00:00:30 +00:00
validate_time(self.start, "start")
validate_time(self.end, "end")
validate_duration(self)
validate_unique_period(Feeding.objects.filter(child=self.child), self)
2022-02-27 19:00:12 +00:00
2017-08-13 20:48:16 +00:00
class Note(models.Model):
2022-02-10 00:00:30 +00:00
model_name = "note"
2017-12-03 21:52:27 +00:00
child = models.ForeignKey(
2022-02-10 00:00:30 +00:00
"Child", on_delete=models.CASCADE, related_name="note", verbose_name=_("Child")
)
2022-02-10 00:00:30 +00:00
note = models.TextField(verbose_name=_("Note"))
time = models.DateTimeField(
2022-02-10 00:00:30 +00:00
default=timezone.now, blank=False, verbose_name=_("Time")
)
tags = TaggableManager(blank=True, through=Tagged)
2017-08-13 20:48:16 +00:00
objects = models.Manager()
class Meta:
2022-02-10 00:00:30 +00:00
default_permissions = ("view", "add", "change", "delete")
ordering = ["-time"]
verbose_name = _("Note")
verbose_name_plural = _("Notes")
2017-08-13 20:48:16 +00:00
def __str__(self):
2022-02-10 00:00:30 +00:00
return str(_("Note"))
2017-08-13 20:48:16 +00:00
class NapsManager(models.Manager):
def get_queryset(self):
qs = super(NapsManager, self).get_queryset()
return qs.filter(id__in=[obj.id for obj in qs if obj.nap])
2017-08-13 14:48:16 +00:00
class Sleep(models.Model):
2022-02-10 00:00:30 +00:00
model_name = "sleep"
2017-12-03 21:52:27 +00:00
child = models.ForeignKey(
2022-02-10 00:00:30 +00:00
"Child", on_delete=models.CASCADE, related_name="sleep", verbose_name=_("Child")
)
2022-02-10 00:00:30 +00:00
napping = models.BooleanField(editable=False, null=True, verbose_name=_("Napping"))
start = models.DateTimeField(blank=False, null=False, verbose_name=_("Start time"))
end = models.DateTimeField(blank=False, null=False, verbose_name=_("End time"))
duration = models.DurationField(
2022-02-10 00:00:30 +00:00
editable=False, null=True, verbose_name=_("Duration")
)
2022-02-10 00:00:30 +00:00
notes = models.TextField(blank=True, null=True, verbose_name=_("Notes"))
tags = TaggableManager(blank=True, through=Tagged)
2017-08-13 14:48:16 +00:00
objects = models.Manager()
naps = NapsManager()
2017-08-13 14:48:16 +00:00
class Meta:
2022-02-10 00:00:30 +00:00
default_permissions = ("view", "add", "change", "delete")
ordering = ["-start"]
verbose_name = _("Sleep")
verbose_name_plural = _("Sleep")
2017-08-13 14:48:16 +00:00
def __str__(self):
2022-02-10 00:00:30 +00:00
return str(_("Sleep"))
2017-08-13 19:05:44 +00:00
@property
def nap(self):
nap_start_min = timezone.datetime.strptime(
2022-02-10 00:00:30 +00:00
settings.BABY_BUDDY["NAP_START_MIN"], "%H:%M"
).time()
nap_start_max = timezone.datetime.strptime(
2022-02-10 00:00:30 +00:00
settings.BABY_BUDDY["NAP_START_MAX"], "%H:%M"
).time()
local_start_time = timezone.localtime(self.start).time()
return nap_start_min <= local_start_time <= nap_start_max
def save(self, *args, **kwargs):
if self.start and self.end:
self.duration = self.end - self.start
self.napping = self.nap
super(Sleep, self).save(*args, **kwargs)
def clean(self):
2022-02-10 00:00:30 +00:00
validate_time(self.start, "start")
validate_time(self.end, "end")
validate_duration(self)
validate_unique_period(Sleep.objects.filter(child=self.child), self)
2017-08-13 19:05:44 +00:00
2019-05-17 04:33:26 +00:00
class Temperature(models.Model):
2022-02-10 00:00:30 +00:00
model_name = "temperature"
2019-05-17 04:33:26 +00:00
child = models.ForeignKey(
2022-02-10 00:00:30 +00:00
"Child",
2019-05-17 04:33:26 +00:00
on_delete=models.CASCADE,
2022-02-10 00:00:30 +00:00
related_name="temperature",
verbose_name=_("Child"),
2019-05-17 04:33:26 +00:00
)
temperature = models.FloatField(
2022-02-10 00:00:30 +00:00
blank=False, null=False, verbose_name=_("Temperature")
2019-05-17 04:33:26 +00:00
)
2022-02-10 00:00:30 +00:00
time = models.DateTimeField(blank=False, null=False, verbose_name=_("Time"))
notes = models.TextField(blank=True, null=True, verbose_name=_("Notes"))
tags = TaggableManager(blank=True, through=Tagged)
2019-05-17 04:33:26 +00:00
objects = models.Manager()
class Meta:
2022-02-10 00:00:30 +00:00
default_permissions = ("view", "add", "change", "delete")
ordering = ["-time"]
verbose_name = _("Temperature")
verbose_name_plural = _("Temperature")
2019-05-17 04:33:26 +00:00
def __str__(self):
2022-02-10 00:00:30 +00:00
return str(_("Temperature"))
2019-05-17 04:33:26 +00:00
def clean(self):
2022-02-10 00:00:30 +00:00
validate_time(self.time, "time")
2019-05-17 04:33:26 +00:00
class Timer(models.Model):
2022-02-10 00:00:30 +00:00
model_name = "timer"
2020-01-28 21:56:28 +00:00
child = models.ForeignKey(
2022-02-10 00:00:30 +00:00
"Child",
2020-01-28 21:56:28 +00:00
blank=True,
null=True,
on_delete=models.CASCADE,
2022-02-10 00:00:30 +00:00
related_name="timers",
verbose_name=_("Child"),
2020-01-28 21:56:28 +00:00
)
name = models.CharField(
2022-02-10 00:00:30 +00:00
blank=True, max_length=255, null=True, verbose_name=_("Name")
)
start = models.DateTimeField(
2022-02-10 00:00:30 +00:00
default=timezone.now, blank=False, verbose_name=_("Start time")
)
end = models.DateTimeField(
2022-02-10 00:00:30 +00:00
blank=True, editable=False, null=True, verbose_name=_("End time")
)
duration = models.DurationField(
2022-02-10 00:00:30 +00:00
editable=False, null=True, verbose_name=_("Duration")
)
2022-02-10 00:00:30 +00:00
active = models.BooleanField(default=True, editable=False, verbose_name=_("Active"))
2017-12-03 21:52:27 +00:00
user = models.ForeignKey(
2022-02-10 00:00:30 +00:00
"auth.User",
on_delete=models.CASCADE,
2022-02-10 00:00:30 +00:00
related_name="timers",
verbose_name=_("User"),
)
objects = models.Manager()
class Meta:
2022-02-10 00:00:30 +00:00
default_permissions = ("view", "add", "change", "delete")
ordering = ["-active", "-start", "-end"]
verbose_name = _("Timer")
verbose_name_plural = _("Timers")
def __str__(self):
2022-02-10 00:00:30 +00:00
return self.name or str(format_lazy(_("Timer #{id}"), id=self.id))
2020-01-28 21:56:28 +00:00
@property
def title_with_child(self):
2022-02-10 00:00:30 +00:00
"""Get Timer title with child name in parenthesis."""
title = str(self)
# Only actually add the name if there is more than one Child instance.
if title and self.child and Child.count() > 1:
2022-02-10 00:00:30 +00:00
title = format_lazy("{title} ({child})", title=title, child=self.child)
return title
2020-01-28 21:56:28 +00:00
@property
def user_username(self):
2022-02-10 00:00:30 +00:00
"""Get Timer user's name with a preference for the full name."""
if self.user.get_full_name():
return self.user.get_full_name()
return self.user.get_username()
@classmethod
def from_db(cls, db, field_names, values):
instance = super(Timer, cls).from_db(db, field_names, values)
if not instance.duration:
instance.duration = timezone.now() - instance.start
return instance
def restart(self):
"""Restart the timer."""
self.start = timezone.now()
self.end = None
self.duration = None
self.active = True
self.save()
def stop(self, end=None):
"""Stop the timer."""
if not end:
end = timezone.now()
self.end = end
self.save()
def save(self, *args, **kwargs):
self.active = self.end is None
self.name = self.name or None
if self.start and self.end:
self.duration = self.end - self.start
else:
self.duration = None
super(Timer, self).save(*args, **kwargs)
def clean(self):
2022-02-10 00:00:30 +00:00
validate_time(self.start, "start")
if self.end:
2022-02-10 00:00:30 +00:00
validate_time(self.end, "end")
validate_duration(self)
2017-08-13 19:05:44 +00:00
class TummyTime(models.Model):
2022-02-10 00:00:30 +00:00
model_name = "tummytime"
2017-12-03 21:52:27 +00:00
child = models.ForeignKey(
2022-02-10 00:00:30 +00:00
"Child",
on_delete=models.CASCADE,
2022-02-10 00:00:30 +00:00
related_name="tummy_time",
verbose_name=_("Child"),
)
2022-02-10 00:00:30 +00:00
start = models.DateTimeField(blank=False, null=False, verbose_name=_("Start time"))
end = models.DateTimeField(blank=False, null=False, verbose_name=_("End time"))
duration = models.DurationField(
2022-02-10 00:00:30 +00:00
editable=False, null=True, verbose_name=_("Duration")
)
milestone = models.CharField(
2022-02-10 00:00:30 +00:00
blank=True, max_length=255, verbose_name=_("Milestone")
)
tags = TaggableManager(blank=True, through=Tagged)
2017-08-13 19:05:44 +00:00
objects = models.Manager()
class Meta:
2022-02-10 00:00:30 +00:00
default_permissions = ("view", "add", "change", "delete")
ordering = ["-start"]
verbose_name = _("Tummy Time")
verbose_name_plural = _("Tummy Time")
2017-08-13 19:05:44 +00:00
def __str__(self):
2022-02-10 00:00:30 +00:00
return str(_("Tummy Time"))
2017-08-13 19:05:44 +00:00
def save(self, *args, **kwargs):
if self.start and self.end:
self.duration = self.end - self.start
super(TummyTime, self).save(*args, **kwargs)
def clean(self):
2022-02-10 00:00:30 +00:00
validate_time(self.start, "start")
validate_time(self.end, "end")
validate_duration(self)
2022-02-10 00:00:30 +00:00
validate_unique_period(TummyTime.objects.filter(child=self.child), self)
2017-11-10 02:15:09 +00:00
class Weight(models.Model):
2022-02-10 00:00:30 +00:00
model_name = "weight"
2017-12-03 21:52:27 +00:00
child = models.ForeignKey(
2022-02-10 00:00:30 +00:00
"Child",
on_delete=models.CASCADE,
2022-02-10 00:00:30 +00:00
related_name="weight",
verbose_name=_("Child"),
)
2022-02-10 00:00:30 +00:00
weight = models.FloatField(blank=False, null=False, verbose_name=_("Weight"))
date = models.DateField(blank=False, null=False, verbose_name=_("Date"))
notes = models.TextField(blank=True, null=True, verbose_name=_("Notes"))
tags = TaggableManager(blank=True, through=Tagged)
2017-11-10 02:15:09 +00:00
objects = models.Manager()
class Meta:
2022-02-10 00:00:30 +00:00
default_permissions = ("view", "add", "change", "delete")
ordering = ["-date"]
verbose_name = _("Weight")
verbose_name_plural = _("Weight")
2017-11-10 02:15:09 +00:00
def __str__(self):
2022-02-10 00:00:30 +00:00
return str(_("Weight"))
2017-11-10 02:15:09 +00:00
def clean(self):
2022-02-10 00:00:30 +00:00
validate_date(self.date, "date")
2021-12-30 03:32:55 +00:00
class Height(models.Model):
2022-02-10 00:00:30 +00:00
model_name = "height"
child = models.ForeignKey(
2022-02-10 00:00:30 +00:00
"Child",
on_delete=models.CASCADE,
2022-02-10 00:00:30 +00:00
related_name="height",
verbose_name=_("Child"),
)
2022-02-10 00:00:30 +00:00
height = models.FloatField(blank=False, null=False, verbose_name=_("Height"))
date = models.DateField(blank=False, null=False, verbose_name=_("Date"))
notes = models.TextField(blank=True, null=True, verbose_name=_("Notes"))
tags = TaggableManager(blank=True, through=Tagged)
objects = models.Manager()
class Meta:
2022-02-10 00:00:30 +00:00
default_permissions = ("view", "add", "change", "delete")
ordering = ["-date"]
verbose_name = _("Height")
verbose_name_plural = _("Height")
def __str__(self):
2022-02-10 00:00:30 +00:00
return str(_("Height"))
def clean(self):
2022-02-10 00:00:30 +00:00
validate_date(self.date, "date")
2021-12-30 03:32:55 +00:00
class HeadCircumference(models.Model):
2022-02-10 00:00:30 +00:00
model_name = "head_circumference"
child = models.ForeignKey(
2022-02-10 00:00:30 +00:00
"Child",
on_delete=models.CASCADE,
2022-02-10 00:00:30 +00:00
related_name="head_circumference",
verbose_name=_("Child"),
)
head_circumference = models.FloatField(
2022-02-10 00:00:30 +00:00
blank=False, null=False, verbose_name=_("Head Circumference")
)
2022-02-10 00:00:30 +00:00
date = models.DateField(blank=False, null=False, verbose_name=_("Date"))
notes = models.TextField(blank=True, null=True, verbose_name=_("Notes"))
tags = TaggableManager(blank=True, through=Tagged)
objects = models.Manager()
class Meta:
2022-02-10 00:00:30 +00:00
default_permissions = ("view", "add", "change", "delete")
ordering = ["-date"]
verbose_name = _("Head Circumference")
verbose_name_plural = _("Head Circumference")
def __str__(self):
2022-02-10 00:00:30 +00:00
return str(_("Head Circumference"))
def clean(self):
2022-02-10 00:00:30 +00:00
validate_date(self.date, "date")
2021-12-30 03:32:55 +00:00
class BMI(models.Model):
2022-02-10 00:00:30 +00:00
model_name = "bmi"
child = models.ForeignKey(
2022-02-10 00:00:30 +00:00
"Child", on_delete=models.CASCADE, related_name="bmi", verbose_name=_("Child")
)
2022-02-10 00:00:30 +00:00
bmi = models.FloatField(blank=False, null=False, verbose_name=_("BMI"))
date = models.DateField(blank=False, null=False, verbose_name=_("Date"))
notes = models.TextField(blank=True, null=True, verbose_name=_("Notes"))
tags = TaggableManager(blank=True, through=Tagged)
objects = models.Manager()
class Meta:
2022-02-10 00:00:30 +00:00
default_permissions = ("view", "add", "change", "delete")
ordering = ["-date"]
verbose_name = _("BMI")
verbose_name_plural = _("BMI")
def __str__(self):
2022-02-10 00:00:30 +00:00
return str(_("BMI"))
def clean(self):
2022-02-10 00:00:30 +00:00
validate_date(self.date, "date")