mirror of https://github.com/snachodog/mybuddy.git
Add temperature tracking.
This commit is contained in:
parent
4c1b333293
commit
4397d4a406
|
@ -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()
|
||||
|
|
|
@ -96,6 +96,10 @@
|
|||
@extend .fa-stop;
|
||||
}
|
||||
|
||||
.icon-temperature {
|
||||
@extend .fa-thermometer-three-quarters;
|
||||
}
|
||||
|
||||
.icon-timer {
|
||||
@extend .fa-clock-o;
|
||||
}
|
||||
|
|
|
@ -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' %}">
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'),
|
||||
},
|
||||
),
|
||||
]
|
|
@ -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(
|
||||
|
|
|
@ -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 %}
|
|
@ -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 %}
|
|
@ -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 %}
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
21
core/urls.py
21
core/urls.py
|
@ -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(
|
||||
|
|
|
@ -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.
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.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue