Add temperature tracking.

This commit is contained in:
Christopher C. Wells 2019-05-16 21:33:26 -07:00
parent 4c1b333293
commit 4397d4a406
26 changed files with 19926 additions and 4 deletions

View File

@ -66,9 +66,14 @@ class Command(BaseCommand):
:returns:
"""
self.time = self.child.birth_date
last_weight_entry_time = self.time
self.weight = uniform(2.0, 5.0)
self.temperature = round(uniform(95.0, 102.0), 2)
self._add_temperature_entry()
self.weight = round(uniform(8.0, 12.0), 2)
self._add_weight_entry()
last_weight_entry_time = self.time
self._add_note_entry()
while self.time < self.time_now:
self._add_sleep_entry()
@ -81,6 +86,8 @@ class Command(BaseCommand):
if choice([True, False]):
self._add_diaperchange_entry()
self._add_tummytime_entry()
if choice([True, False]):
self._add_temperature_entry()
if (self.time - last_weight_entry_time).days > 6:
self._add_weight_entry()
last_weight_entry_time = self.time
@ -165,6 +172,19 @@ class Command(BaseCommand):
).save()
self.time = end
@transaction.atomic
def _add_temperature_entry(self):
"""
Add a Temperature entry. This assumes a weekly interval.
:returns:
"""
self.temperature = round(uniform(95.0, 102.0), 2)
models.Temperature.objects.create(
child=self.child,
temperature=self.temperature,
time=self.time
).save()
@transaction.atomic
def _add_tummytime_entry(self):
"""
@ -197,6 +217,6 @@ class Command(BaseCommand):
self.weight += uniform(0.1, 0.3)
models.Weight.objects.create(
child=self.child,
weight=self.weight,
weight=round(self.weight, 2),
date=self.time.date()
).save()

View File

@ -96,6 +96,10 @@
@extend .fa-stop;
}
.icon-temperature {
@extend .fa-thermometer-three-quarters;
}
.icon-timer {
@extend .fa-clock-o;
}

View File

@ -45,6 +45,12 @@
{% trans "Sleep" %}
</a>
{% endif %}
{% if perms.core.add_temperature %}
<a class="dropdown-item p-2" href="{% url 'core:temperature-add' %}">
<i class="icon icon-temperature" aria-hidden="true"></i>
{% trans "Temperature" %}
</a>
{% endif %}
{% if perms.core.add_tummytime %}
<a class="dropdown-item p-2" href="{% url 'core:tummytime-add' %}">
<i class="icon icon-tummytime" aria-hidden="true"></i>
@ -116,6 +122,20 @@
</a>
{% endif %}
{% if perms.core.view_temperature %}
<a class="dropdown-item{% if request.path == '/temperature/' %} active{% endif %}"
href="{% url 'core:temperature-list' %}">
<i class="icon icon-temperature" aria-hidden="true"></i>
{% trans "Temperature" %}
</a>
{% endif %}
{% if perms.core.add_temperature %}
<a class="dropdown-item pl-5{% if request.path == '/temperature/add/' %} active{% endif %}"
href="{% url 'core:temperature-add' %}"><i class="icon icon-add" aria-hidden="true"></i>
{% trans "Temperature reading" %}
</a>
{% endif %}
{% if perms.core.view_weight %}
<a class="dropdown-item{% if request.path == '/weight/' %} active{% endif %}"
href="{% url 'core:weight-list' %}">

View File

@ -45,6 +45,13 @@ class SleepAdmin(admin.ModelAdmin):
search_fields = ('child__first_name', 'child__last_name',)
@admin.register(models.Temperature)
class TemperatureAdmin(admin.ModelAdmin):
list_display = ('child', 'temperature', 'time',)
list_filter = ('child',)
search_fields = ('child__first_name', 'child__last_name', 'temperature',)
@admin.register(models.Timer)
class TimerAdmin(admin.ModelAdmin):
list_display = ('name', 'start', 'end', 'duration', 'active', 'user')

View File

@ -174,6 +174,22 @@ class SleepForm(forms.ModelForm):
return instance
class TemperatureForm(forms.ModelForm):
class Meta:
model = models.Temperature
fields = ['child', 'temperature', 'time']
widgets = {
'time': forms.DateTimeInput(attrs={
'class': 'datetimepicker-input',
'data-target': '#datetimepicker_time',
}),
}
def __init__(self, *args, **kwargs):
kwargs = set_default_child(kwargs)
super(TemperatureForm, self).__init__(*args, **kwargs)
class TimerForm(forms.ModelForm):
class Meta:
model = models.Timer

View File

@ -0,0 +1,29 @@
# Generated by Django 2.2 on 2019-05-17 03:54
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('core', '0006_auto_20190502_1701'),
]
operations = [
migrations.CreateModel(
name='Temperature',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('temperature', models.FloatField(verbose_name='Temperature')),
('time', models.DateTimeField(verbose_name='Time')),
('child', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='temperature', to='core.Child', verbose_name='Child')),
],
options={
'verbose_name': 'Temperature',
'verbose_name_plural': 'Temperature',
'ordering': ['-time'],
'default_permissions': ('view', 'add', 'change', 'delete'),
},
),
]

View File

@ -326,6 +326,40 @@ class Sleep(models.Model):
validate_unique_period(Sleep.objects.filter(child=self.child), self)
class Temperature(models.Model):
model_name = 'temperature'
child = models.ForeignKey(
'Child',
on_delete=models.CASCADE,
related_name='temperature',
verbose_name=_('Child')
)
temperature = models.FloatField(
blank=False,
null=False,
verbose_name=_('Temperature')
)
time = models.DateTimeField(
blank=False,
null=False,
verbose_name=_('Time')
)
objects = models.Manager()
class Meta:
default_permissions = ('view', 'add', 'change', 'delete')
ordering = ['-time']
verbose_name = _('Temperature')
verbose_name_plural = _('Temperature')
def __str__(self):
return str(_('Temperature'))
def clean(self):
validate_time(self.time, 'time')
class Timer(models.Model):
model_name = 'timer'
name = models.CharField(

View File

@ -0,0 +1,18 @@
{% extends 'babybuddy/page.html' %}
{% load i18n widget_tweaks %}
{% block title %}{% trans "Delete a Temperature Reading" %}{% endblock %}
{% block breadcrumbs %}
<li class="breadcrumb-item"><a href="{% url 'core:temperature-list' %}">{% trans "Temperature" %}</a></li>
<li class="breadcrumb-item active" aria-current="page">{% trans "Delete" %}</li>
{% endblock %}
{% block content %}
<form role="form" method="post">
{% csrf_token %}
{% blocktrans %}<h1>Are you sure you want to delete <span class="text-info">{{ object }}</span>?</h1>{% endblocktrans %}
<input type="submit" value="{% trans "Delete" %}" class="btn btn-danger" />
<a href="{% url 'core:temperature-list' %}" class="btn btn-default">{% trans "Cancel" %}</a>
</form>
{% endblock %}

View File

@ -0,0 +1,39 @@
{% extends 'babybuddy/page.html' %}
{% load i18n %}
{% block title %}
{% if object %}
{{ object }}
{% else %}
{% trans "Add a Temperature Reading" %}
{% endif %}
{% endblock %}
{% block breadcrumbs %}
<li class="breadcrumb-item"><a href="{% url 'core:temperature-list' %}">{% trans "Temperature" %}</a></li>
{% if object %}
<li class="breadcrumb-item active" aria-current="page">{% trans "Update" %}</li>
{% else %}
<li class="breadcrumb-item active" aria-current="page">{% trans "Add a Temperature Reading" %}</li>
{% endif %}
{% endblock %}
{% block content %}
{% if object %}
{% blocktrans %}<h1>Update <span class="text-info">{{ object }}</span></h1>{% endblocktrans %}
{% else %}
<h1>{% trans "Add a Temperature Entry" %}</h1>
{% endif %}
{% include 'babybuddy/form.html' %}
{% endblock %}
{% block javascript %}
<script type="text/javascript">
$(function () {
$('#datetimepicker_time').datetimepicker({
defaultDate: 'now',
format: 'YYYY-MM-DD HH:mm'
});
});
</script>
{% endblock %}

View File

@ -0,0 +1,63 @@
{% extends 'babybuddy/page.html' %}
{% load i18n widget_tweaks %}
{% block title %}{% trans "Temperature" %}{% endblock %}
{% block breadcrumbs %}
<li class="breadcrumb-item active" aria-current="page">{% trans "Temperature" %}</li>
{% endblock %}
{% block content %}
<h1>{% trans "Temperature" %}</h1>
{% include 'babybuddy/filter.html' %}
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead class="thead-inverse">
<tr>
<th>{% trans "Child" %}</th>
<th>{% trans "Temperature" %}</th>
<th>{% trans "Time" %}</th>
<th class="text-center">{% trans "Actions" %}</th>
</tr>
</thead>
<tbody>
{% for object in object_list %}
<tr>
<th scope="row"><a href="{% url 'core:child' object.child.slug %}">{{ object.child }}</a></th>
<td>{{ object.temperature }}</td>
<td>{{ object.time }}</td>
<td class="text-center">
<div class="btn-group btn-group-sm" role="group" aria-label="{% trans "Actions" %}">
{% if perms.core.change_temperature %}
<a href="{% url 'core:temperature-update' object.id %}" class="btn btn-primary">
<i class="icon icon-update" aria-hidden="true"></i>
</a>
{% endif %}
{% if perms.core.delete_temperature %}
<a href="{% url 'core:temperature-delete' object.id %}" class="btn btn-danger">
<i class="icon icon-delete" aria-hidden="true"></i>
</a>
{% endif %}
</div>
</td>
</tr>
{% empty %}
<tr>
<th colspan="4">{% trans "No temperature entries found." %}</th>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% include 'babybuddy/paginator.html' %}
{% if perms.core.add_temperature %}
<a href="{% url 'core:temperature-add' %}" class="btn btn-sm btn-success">
<i class="icon icon-temperature" aria-hidden="true"></i> {% trans "Add a Temperature Reading" %}
</a>
{% endif %}
{% endblock %}

View File

@ -121,6 +121,17 @@ class FormsTestCase(TestCase):
page = self.c.post('/sleep/{}/'.format(entry.id), params)
self.assertEqual(page.status_code, 302)
def test_temperature_forms(self):
params = {
'child': 1,
'temperature': '98.6',
'time': '2000-01-01 2:21'
}
entry = models.Temperature.objects.first()
page = self.c.post('/temperature/{}/'.format(entry.id), params)
self.assertEqual(page.status_code, 302)
def test_timer_forms(self):
start_time = timezone.localtime()
timer = models.Timer.objects.create(user=self.user, start=start_time)

View File

@ -120,6 +120,26 @@ class SleepTestCase(TestCase):
self.assertEqual(sleep.duration, sleep.end - sleep.start)
class TemperatureTestCase(TestCase):
def setUp(self):
call_command('migrate', verbosity=0)
self.child = models.Child.objects.create(
first_name='First',
last_name='Last',
birth_date=timezone.localdate()
)
self.temp = models.Temperature.objects.create(
child=self.child,
time=timezone.localtime() - timezone.timedelta(days=1),
temperature=98.6
)
def test_temperature_create(self):
self.assertEqual(self.temp, models.Temperature.objects.first())
self.assertEqual(str(self.temp), 'Temperature')
self.assertEqual(self.temp.temperature, 98.6)
class TimerTestCase(TestCase):
def setUp(self):
call_command('migrate', verbosity=0)

View File

@ -97,6 +97,18 @@ class ViewsTestCase(TestCase):
page = self.c.get('/sleep/{}/delete/'.format(entry.id))
self.assertEqual(page.status_code, 200)
def test_temperature_views(self):
page = self.c.get('/temperature/')
self.assertEqual(page.status_code, 200)
page = self.c.get('/temperature/add/')
self.assertEqual(page.status_code, 200)
entry = models.Temperature.objects.first()
page = self.c.get('/temperature/{}/'.format(entry.id))
self.assertEqual(page.status_code, 200)
page = self.c.get('/temperature/{}/delete/'.format(entry.id))
self.assertEqual(page.status_code, 200)
def test_timer_views(self):
page = self.c.get('/timers/')
self.assertEqual(page.status_code, 200)

View File

@ -72,6 +72,27 @@ urlpatterns = [
name='sleep-delete'
),
path(
'temperature/',
views.TemperatureList.as_view(),
name='temperature-list'
),
path(
'temperature/add/',
views.TemperatureAdd.as_view(),
name='temperature-add'
),
path(
'temperature/<int:pk>/',
views.TemperatureUpdate.as_view(),
name='temperature-update'
),
path(
'temperature/<int:pk>/delete/',
views.TemperatureDelete.as_view(),
name='temperature-delete'
),
path('timers/', views.TimerList.as_view(), name='timer-list'),
path('timer/add/', views.TimerAdd.as_view(), name='timer-add'),
path(

View File

@ -218,6 +218,36 @@ class SleepDelete(CoreDeleteView):
success_url = reverse_lazy('core:sleep-list')
class TemperatureList(PermissionRequired403Mixin, BabyBuddyFilterView):
model = models.Temperature
template_name = 'core/temperature_list.html'
permission_required = ('core.view_temperature',)
paginate_by = 10
filterset_fields = ('child',)
class TemperatureAdd(CoreAddView):
model = models.Temperature
permission_required = ('core.add_temperature',)
form_class = forms.TemperatureForm
success_url = reverse_lazy('core:temperature-list')
success_message = _('%(model)s reading added!')
class TemperatureUpdate(CoreUpdateView):
model = models.Temperature
permission_required = ('core.change_temperature',)
fields = ['child', 'temperature', 'time']
success_url = reverse_lazy('core:temperature-list')
success_message = _('%(model)s reading for %(child)s updated.')
class TemperatureDelete(CoreDeleteView):
model = models.Temperature
permission_required = ('core.delete_temperature',)
success_url = reverse_lazy('core:temperature-list')
class TimerList(PermissionRequired403Mixin, BabyBuddyFilterView):
model = models.Timer
template_name = 'core/timer_list.html'

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long