mirror of https://github.com/snachodog/mybuddy.git
Add weight tracking.
This commit is contained in:
parent
f947d37285
commit
067be4bf07
|
@ -5,8 +5,7 @@ from rest_framework import serializers
|
|||
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from core.models import (Child, DiaperChange, Feeding, Note, Sleep, Timer,
|
||||
TummyTime)
|
||||
from core import models
|
||||
|
||||
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
|
@ -17,7 +16,7 @@ class UserSerializer(serializers.ModelSerializer):
|
|||
|
||||
class ChildSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = Child
|
||||
model = models.Child
|
||||
fields = ('first_name', 'last_name', 'birth_date', 'slug')
|
||||
lookup_field = 'slug'
|
||||
|
||||
|
@ -26,7 +25,7 @@ class DiaperChangeSerializer(serializers.HyperlinkedModelSerializer):
|
|||
child = ChildSerializer()
|
||||
|
||||
class Meta:
|
||||
model = DiaperChange
|
||||
model = models.DiaperChange
|
||||
fields = ('child', 'time', 'wet', 'solid', 'color')
|
||||
|
||||
|
||||
|
@ -34,7 +33,7 @@ class FeedingSerializer(serializers.HyperlinkedModelSerializer):
|
|||
child = ChildSerializer()
|
||||
|
||||
class Meta:
|
||||
model = Feeding
|
||||
model = models.Feeding
|
||||
fields = ('child', 'start', 'end', 'duration', 'type', 'method',
|
||||
'amount')
|
||||
|
||||
|
@ -43,7 +42,7 @@ class NoteSerializer(serializers.HyperlinkedModelSerializer):
|
|||
child = ChildSerializer()
|
||||
|
||||
class Meta:
|
||||
model = Note
|
||||
model = models.Note
|
||||
fields = ('child', 'note', 'time')
|
||||
|
||||
|
||||
|
@ -51,7 +50,7 @@ class SleepSerializer(serializers.HyperlinkedModelSerializer):
|
|||
child = ChildSerializer()
|
||||
|
||||
class Meta:
|
||||
model = Sleep
|
||||
model = models.Sleep
|
||||
fields = ('child', 'start', 'end', 'duration')
|
||||
|
||||
|
||||
|
@ -59,7 +58,7 @@ class TimerSerializer(serializers.HyperlinkedModelSerializer):
|
|||
user = UserSerializer()
|
||||
|
||||
class Meta:
|
||||
model = Timer
|
||||
model = models.Timer
|
||||
fields = ('name', 'start', 'end', 'duration', 'active', 'user')
|
||||
|
||||
|
||||
|
@ -67,5 +66,13 @@ class TummyTimeSerializer(serializers.HyperlinkedModelSerializer):
|
|||
child = ChildSerializer()
|
||||
|
||||
class Meta:
|
||||
model = TummyTime
|
||||
model = models.TummyTime
|
||||
fields = ('child', 'start', 'end', 'duration', 'milestone')
|
||||
|
||||
|
||||
class WeightSerializer(serializers.HyperlinkedModelSerializer):
|
||||
child = ChildSerializer()
|
||||
|
||||
class Meta:
|
||||
model = models.Weight
|
||||
fields = ('child', 'weight', 'date')
|
||||
|
|
19
api/urls.py
19
api/urls.py
|
@ -4,17 +4,18 @@ from __future__ import unicode_literals
|
|||
from django.conf.urls import url, include
|
||||
from rest_framework import routers
|
||||
|
||||
from .views import (ChildViewSet, DiaperChangeViewSet, FeedingViewSet,
|
||||
NoteViewSet, SleepViewSet, TimerViewSet, TummyTimeViewSet)
|
||||
from . import views
|
||||
|
||||
|
||||
router = routers.DefaultRouter()
|
||||
router.register(r'children', ChildViewSet)
|
||||
router.register(r'changes', DiaperChangeViewSet)
|
||||
router.register(r'feedings', FeedingViewSet)
|
||||
router.register(r'notes', NoteViewSet)
|
||||
router.register(r'sleep', SleepViewSet)
|
||||
router.register(r'timers', TimerViewSet)
|
||||
router.register(r'tummy-times', TummyTimeViewSet)
|
||||
router.register(r'children', views.ChildViewSet)
|
||||
router.register(r'changes', views.DiaperChangeViewSet)
|
||||
router.register(r'feedings', views.FeedingViewSet)
|
||||
router.register(r'notes', views.NoteViewSet)
|
||||
router.register(r'sleep', views.SleepViewSet)
|
||||
router.register(r'timers', views.TimerViewSet)
|
||||
router.register(r'tummy-times', views.TummyTimeViewSet)
|
||||
router.register(r'weight', views.WeightViewSet)
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^api/', include(router.urls)),
|
||||
|
|
41
api/views.py
41
api/views.py
|
@ -3,52 +3,55 @@ from __future__ import unicode_literals
|
|||
|
||||
from rest_framework import viewsets
|
||||
|
||||
from core.models import (Child, DiaperChange, Feeding, Note, Sleep, Timer,
|
||||
TummyTime)
|
||||
from core import models
|
||||
|
||||
from .serializers import (ChildSerializer, DiaperChangeSerializer,
|
||||
FeedingSerializer, NoteSerializer, SleepSerializer,
|
||||
TimerSerializer, TummyTimeSerializer,)
|
||||
from . import serializers
|
||||
|
||||
|
||||
class ChildViewSet(viewsets.ModelViewSet):
|
||||
queryset = Child.objects.all()
|
||||
serializer_class = ChildSerializer
|
||||
queryset = models.Child.objects.all()
|
||||
serializer_class = serializers.ChildSerializer
|
||||
lookup_field = 'slug'
|
||||
filter_fields = ('first_name', 'last_name', 'slug')
|
||||
|
||||
|
||||
class DiaperChangeViewSet(viewsets.ModelViewSet):
|
||||
queryset = DiaperChange.objects.all()
|
||||
serializer_class = DiaperChangeSerializer
|
||||
queryset = models.DiaperChange.objects.all()
|
||||
serializer_class = serializers.DiaperChangeSerializer
|
||||
filter_fields = ('child', 'wet', 'solid', 'color')
|
||||
|
||||
|
||||
class FeedingViewSet(viewsets.ModelViewSet):
|
||||
queryset = Feeding.objects.all()
|
||||
serializer_class = FeedingSerializer
|
||||
queryset = models.Feeding.objects.all()
|
||||
serializer_class = serializers.FeedingSerializer
|
||||
filter_fields = ('child', 'type', 'method')
|
||||
|
||||
|
||||
class NoteViewSet(viewsets.ModelViewSet):
|
||||
queryset = Note.objects.all()
|
||||
serializer_class = NoteSerializer
|
||||
queryset = models.Note.objects.all()
|
||||
serializer_class = serializers.NoteSerializer
|
||||
filter_fields = ('child',)
|
||||
|
||||
|
||||
class SleepViewSet(viewsets.ModelViewSet):
|
||||
queryset = Sleep.objects.all()
|
||||
serializer_class = SleepSerializer
|
||||
queryset = models.Sleep.objects.all()
|
||||
serializer_class = serializers.SleepSerializer
|
||||
filter_fields = ('child',)
|
||||
|
||||
|
||||
class TimerViewSet(viewsets.ModelViewSet):
|
||||
queryset = Timer.objects.all()
|
||||
serializer_class = TimerSerializer
|
||||
queryset = models.Timer.objects.all()
|
||||
serializer_class = serializers.TimerSerializer
|
||||
filter_fields = ('active', 'user')
|
||||
|
||||
|
||||
class TummyTimeViewSet(viewsets.ModelViewSet):
|
||||
queryset = TummyTime.objects.all()
|
||||
serializer_class = TummyTimeSerializer
|
||||
queryset = models.TummyTime.objects.all()
|
||||
serializer_class = serializers.TummyTimeSerializer
|
||||
filter_fields = ('child',)
|
||||
|
||||
|
||||
class WeightViewSet(viewsets.ModelViewSet):
|
||||
queryset = models.Weight.objects.all()
|
||||
serializer_class = serializers.WeightSerializer
|
||||
filter_fields = ('child',)
|
||||
|
|
|
@ -10,7 +10,7 @@ from django.utils import timezone
|
|||
|
||||
from faker import Factory
|
||||
|
||||
from core.models import Child, DiaperChange, Feeding, Note, Sleep, TummyTime
|
||||
from core import models
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
@ -42,7 +42,7 @@ class Command(BaseCommand):
|
|||
# User first day of data that will created for birth date.
|
||||
birth_date = (timezone.localtime() - timedelta(days=days))
|
||||
for i in range(0, children):
|
||||
child = Child.objects.create(
|
||||
child = models.Child.objects.create(
|
||||
first_name=self.faker.first_name(),
|
||||
last_name=self.faker.last_name(),
|
||||
birth_date=birth_date
|
||||
|
@ -67,7 +67,7 @@ class Command(BaseCommand):
|
|||
if solid:
|
||||
wet = False
|
||||
color = choice(
|
||||
DiaperChange._meta.get_field('color').choices)[0]
|
||||
models.DiaperChange._meta.get_field('color').choices)[0]
|
||||
else:
|
||||
wet = True
|
||||
color = ''
|
||||
|
@ -75,7 +75,7 @@ class Command(BaseCommand):
|
|||
time = date + timedelta(minutes=randint(0, 60 * 24))
|
||||
|
||||
if time < now:
|
||||
DiaperChange.objects.create(
|
||||
models.DiaperChange.objects.create(
|
||||
child=child,
|
||||
time=time,
|
||||
wet=wet,
|
||||
|
@ -85,7 +85,8 @@ class Command(BaseCommand):
|
|||
|
||||
last_end = date
|
||||
while last_end < date + timedelta(days=1):
|
||||
method = choice(Feeding._meta.get_field('method').choices)[0]
|
||||
method = choice(models.Feeding._meta.get_field(
|
||||
'method').choices)[0]
|
||||
if method is 'bottle':
|
||||
amount = Decimal('%d.%d' % (randint(0, 6), randint(0, 9)))
|
||||
else:
|
||||
|
@ -96,11 +97,11 @@ class Command(BaseCommand):
|
|||
if end > now:
|
||||
break
|
||||
|
||||
Feeding.objects.create(
|
||||
models.Feeding.objects.create(
|
||||
child=child,
|
||||
start=start,
|
||||
end=end,
|
||||
type=choice(Feeding._meta.get_field('type').choices)[0],
|
||||
type=choice(models.Feeding._meta.get_field('type').choices)[0],
|
||||
method=method,
|
||||
amount=amount
|
||||
).save()
|
||||
|
@ -109,7 +110,8 @@ class Command(BaseCommand):
|
|||
last_end = date
|
||||
|
||||
# Adjust last_end if the last sleep entry crossed in to date.
|
||||
last_entry = Sleep.objects.filter(child=child).order_by('end').last()
|
||||
last_entry = models.Sleep.objects.filter(
|
||||
child=child).order_by('end').last()
|
||||
if last_entry:
|
||||
last_entry_end = timezone.localtime(last_entry.end)
|
||||
if last_entry_end > last_end:
|
||||
|
@ -124,7 +126,8 @@ class Command(BaseCommand):
|
|||
if end > now:
|
||||
break
|
||||
|
||||
Sleep.objects.create(child=child, start=start, end=end).save()
|
||||
models.Sleep.objects.create(
|
||||
child=child, start=start, end=end).save()
|
||||
last_end = end
|
||||
|
||||
last_end = date
|
||||
|
@ -139,7 +142,7 @@ class Command(BaseCommand):
|
|||
if end > now:
|
||||
break
|
||||
|
||||
TummyTime.objects.create(
|
||||
models.TummyTime.objects.create(
|
||||
child=child,
|
||||
start=start,
|
||||
end=end,
|
||||
|
@ -147,8 +150,14 @@ class Command(BaseCommand):
|
|||
).save()
|
||||
last_end = end
|
||||
|
||||
models.Weight.objects.create(
|
||||
child=child,
|
||||
weight=Decimal('%d.%d' % (randint(3, 15), randint(0, 9))),
|
||||
date=date.date()
|
||||
).save()
|
||||
|
||||
note = self.faker.sentence()
|
||||
Note.objects.create(
|
||||
models.Note.objects.create(
|
||||
child=child,
|
||||
note=note,
|
||||
time=date + timedelta(minutes=randint(0, 60 * 24))
|
||||
|
|
|
@ -103,3 +103,7 @@
|
|||
.icon-user {
|
||||
@extend .fa-user;
|
||||
}
|
||||
|
||||
.icon-weight {
|
||||
@extend .fa-balance-scale;
|
||||
}
|
||||
|
|
|
@ -43,6 +43,11 @@
|
|||
<i class="icon icon-tummytime" aria-hidden="true"></i> Tummy Time
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if perms.core.add_weight %}
|
||||
<a class="dropdown-item p-2" href="{% url 'weight-add' %}">
|
||||
<i class="icon icon-weight" aria-hidden="true"></i> Weight
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -91,6 +96,16 @@
|
|||
href="{% url 'note-add' %}"><i class="icon icon-add" aria-hidden="true"></i> Note</a>
|
||||
{% endif %}
|
||||
|
||||
{% if perms.core.view_weight %}
|
||||
<a class="dropdown-item{% if request.path == '/weight/' %} active{% endif %}" href="{% url 'weight-list' %}">
|
||||
<i class="icon icon-weight" aria-hidden="true"></i> Weight
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if perms.core.add_weight %}
|
||||
<a class="dropdown-item pl-5{% if request.path == '/weight/add/' %} active{% endif %}"
|
||||
href="{% url 'weight-add' %}"><i class="icon icon-add" aria-hidden="true"></i> Weight entry</a>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</li>
|
||||
|
||||
|
|
|
@ -3,25 +3,24 @@ from __future__ import unicode_literals
|
|||
|
||||
from django.contrib import admin
|
||||
|
||||
from .models import (Child, DiaperChange, Feeding, Note, Sleep, Timer,
|
||||
TummyTime)
|
||||
from core import models
|
||||
|
||||
|
||||
@admin.register(Child)
|
||||
@admin.register(models.Child)
|
||||
class ChildAdmin(admin.ModelAdmin):
|
||||
list_display = ('first_name', 'last_name', 'birth_date', 'slug')
|
||||
list_filter = ('last_name',)
|
||||
search_fields = ('first_name', 'last_name', 'birth_date',)
|
||||
|
||||
|
||||
@admin.register(DiaperChange)
|
||||
@admin.register(models.DiaperChange)
|
||||
class DiaperChangeAdmin(admin.ModelAdmin):
|
||||
list_display = ('child', 'time', 'wet', 'solid', 'color')
|
||||
list_filter = ('child', 'wet', 'solid', 'color')
|
||||
search_fields = ('child__first_name', 'child__last_name',)
|
||||
|
||||
|
||||
@admin.register(Feeding)
|
||||
@admin.register(models.Feeding)
|
||||
class FeedingAdmin(admin.ModelAdmin):
|
||||
list_display = ('start', 'end', 'duration', 'child', 'type', 'method',
|
||||
'amount')
|
||||
|
@ -30,29 +29,36 @@ class FeedingAdmin(admin.ModelAdmin):
|
|||
'method',)
|
||||
|
||||
|
||||
@admin.register(Note)
|
||||
@admin.register(models.Note)
|
||||
class NoteAdmin(admin.ModelAdmin):
|
||||
list_display = ('time', 'child', 'note',)
|
||||
list_filter = ('child',)
|
||||
search_fields = ('child__last_name',)
|
||||
|
||||
|
||||
@admin.register(Sleep)
|
||||
@admin.register(models.Sleep)
|
||||
class SleepAdmin(admin.ModelAdmin):
|
||||
list_display = ('start', 'end', 'duration', 'child', 'nap')
|
||||
list_filter = ('child',)
|
||||
search_fields = ('child__first_name', 'child__last_name',)
|
||||
|
||||
|
||||
@admin.register(Timer)
|
||||
@admin.register(models.Timer)
|
||||
class TimerAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'start', 'end', 'duration', 'active', 'user')
|
||||
list_filter = ('active', 'user')
|
||||
search_fields = ('name', 'user')
|
||||
|
||||
|
||||
@admin.register(TummyTime)
|
||||
@admin.register(models.TummyTime)
|
||||
class TummyTimeAdmin(admin.ModelAdmin):
|
||||
list_display = ('start', 'end', 'duration', 'child', 'milestone',)
|
||||
list_filter = ('child',)
|
||||
search_fields = ('child__first_name', 'child__last_name', 'milestone',)
|
||||
|
||||
|
||||
@admin.register(models.Weight)
|
||||
class WeightAdmin(admin.ModelAdmin):
|
||||
list_display = ('child', 'weight', 'date',)
|
||||
list_filter = ('child',)
|
||||
search_fields = ('child__first_name', 'child__last_name', 'weight',)
|
||||
|
|
|
@ -205,3 +205,19 @@ class TummyTimeForm(forms.ModelForm):
|
|||
timer.stop(instance.end)
|
||||
instance.save()
|
||||
return instance
|
||||
|
||||
|
||||
class WeightForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = models.Weight
|
||||
fields = ['child', 'weight', 'date']
|
||||
widgets = {
|
||||
'date': forms.DateInput(attrs={
|
||||
'class': 'datepicker-input',
|
||||
'data-target': '#datetimepicker_date',
|
||||
}),
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs = set_default_child(kwargs)
|
||||
super(WeightForm, self).__init__(*args, **kwargs)
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.6 on 2017-11-10 02:07
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0002_auto_20171028_1257'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Weight',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('weight', models.FloatField()),
|
||||
('date', models.DateField()),
|
||||
('child', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='weight', to='core.Child')),
|
||||
],
|
||||
options={
|
||||
'default_permissions': ('view', 'add', 'change', 'delete'),
|
||||
'verbose_name_plural': 'Weight',
|
||||
'ordering': ['-date'],
|
||||
},
|
||||
),
|
||||
]
|
|
@ -10,6 +10,19 @@ from django.template.defaultfilters import slugify
|
|||
from django.utils import timezone
|
||||
|
||||
|
||||
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(
|
||||
{field_name: 'Date can not be in the future.'},
|
||||
code='date_invalid')
|
||||
|
||||
|
||||
def validate_duration(model, max_duration=timedelta(hours=24)):
|
||||
"""
|
||||
Basic sanity checks for models with a duration
|
||||
|
@ -325,3 +338,23 @@ class TummyTime(models.Model):
|
|||
validate_duration(self)
|
||||
validate_unique_period(
|
||||
TummyTime.objects.filter(child=self.child), self)
|
||||
|
||||
|
||||
class Weight(models.Model):
|
||||
model_name = 'weight'
|
||||
child = models.ForeignKey('Child', related_name='weight')
|
||||
weight = models.FloatField(blank=False, null=False)
|
||||
date = models.DateField(blank=False, null=False)
|
||||
|
||||
objects = models.Manager()
|
||||
|
||||
class Meta:
|
||||
default_permissions = ('view', 'add', 'change', 'delete')
|
||||
ordering = ['-date']
|
||||
verbose_name_plural = 'Weight'
|
||||
|
||||
def __str__(self):
|
||||
return 'Weight'
|
||||
|
||||
def clean(self):
|
||||
validate_date(self.date, 'date')
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
{% extends 'babybuddy/page.html' %}
|
||||
{% load widget_tweaks %}
|
||||
|
||||
{% block title %}Delete a Weight Entry{% endblock %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<li class="breadcrumb-item"><a href="{% url 'weight-list' %}">Weight</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Delete</li>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form role="form" method="post">
|
||||
{% csrf_token %}
|
||||
<h1>Are you sure you want to delete <span class="text-info">{{ object }}</span>?</h1>
|
||||
<input type="submit" value="Delete" class="btn btn-danger" />
|
||||
<a href="{% url 'weight-list' %}" class="btn btn-default">Cancel</a>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -0,0 +1,38 @@
|
|||
{% extends 'babybuddy/page.html' %}
|
||||
|
||||
{% block title %}
|
||||
{% if object %}
|
||||
{{ object }}
|
||||
{% else %}
|
||||
Add a Weight Entry
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<li class="breadcrumb-item"><a href="{% url 'weight-list' %}">Weight</a></li>
|
||||
{% if object %}
|
||||
<li class="breadcrumb-item active" aria-current="page">Update</li>
|
||||
{% else %}
|
||||
<li class="breadcrumb-item active" aria-current="page">Add a Weight Entry</li>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% if object %}
|
||||
<h1>Update <span class="text-info">{{ object }}</span></h1>
|
||||
{% else %}
|
||||
<h1>Add a Weight Entry</h1>
|
||||
{% endif %}
|
||||
{% include 'babybuddy/form.html' %}
|
||||
{% endblock %}
|
||||
|
||||
{% block javascript %}
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
$('#datetimepicker_date').datetimepicker({
|
||||
defaultDate: 'now',
|
||||
format: 'YYYY-MM-DD'
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -0,0 +1,63 @@
|
|||
{% extends 'babybuddy/page.html' %}
|
||||
{% load widget_tweaks %}
|
||||
|
||||
{% block title %}Weight{% endblock %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<li class="breadcrumb-item active" aria-current="page">Weight</li>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Weight</h1>
|
||||
{% include 'babybuddy/filter.html' %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead class="thead-inverse">
|
||||
<tr>
|
||||
<th>Child</th>
|
||||
<th>Weight</th>
|
||||
<th>Date</th>
|
||||
<th class="text-center">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for object in object_list %}
|
||||
<tr>
|
||||
<th scope="row"><a href="{% url 'child' object.child.slug %}">{{ object.child }}</a></th>
|
||||
<td>{{ object.weight }}</td>
|
||||
<td>{{ object.date }}</td>
|
||||
<td class="text-center">
|
||||
<div class="btn-group btn-group-sm" role="group" aria-label="Actions">
|
||||
|
||||
{% if perms.core.change_weight %}
|
||||
<a href="{% url 'weight-update' object.id %}" class="btn btn-primary">
|
||||
<i class="icon icon-update" aria-hidden="true"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
{% if perms.core.delete_weight %}
|
||||
<a href="{% url 'weight-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">No weight entries found.</th>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% include 'babybuddy/paginator.html' %}
|
||||
|
||||
{% if perms.core.add_weight %}
|
||||
<a href="{% url 'weight-add' %}" class="btn btn-sm btn-success">
|
||||
<i class="icon icon-weight" aria-hidden="true"></i> Add a Weight Entry
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
|
@ -180,6 +180,31 @@ class FormsTestCase(TestCase):
|
|||
page = self.c.post('/tummy-time/{}/'.format(entry.id), params)
|
||||
self.assertEqual(page.status_code, 302)
|
||||
|
||||
def test_weight_forms(self):
|
||||
params = {
|
||||
'child': 1,
|
||||
'weight': '8.5',
|
||||
'date': '2000-01-01'
|
||||
}
|
||||
|
||||
entry = models.Weight.objects.first()
|
||||
page = self.c.post('/weight/{}/'.format(entry.id), params)
|
||||
self.assertEqual(page.status_code, 302)
|
||||
|
||||
def test_validate_date(self):
|
||||
future = (timezone.localdate() + timezone.timedelta(days=1))
|
||||
params = {
|
||||
'child': 1,
|
||||
'weight': '8.5',
|
||||
'date': future.strftime('%Y-%m-%d')
|
||||
}
|
||||
entry = models.Weight.objects.first()
|
||||
|
||||
page = self.c.post('/weight/{}/'.format(entry.id), params)
|
||||
self.assertEqual(page.status_code, 200)
|
||||
self.assertFormError(page, 'form', 'date',
|
||||
'Date can not be in the future.')
|
||||
|
||||
def test_validate_duration(self):
|
||||
params = {
|
||||
'child': 1,
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.test import TestCase
|
||||
from django.test import Client as HttpClient
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.management import call_command
|
||||
from django.test import TestCase
|
||||
from django.test import Client as HttpClient
|
||||
from django.utils import timezone
|
||||
|
||||
from faker import Factory
|
||||
|
||||
|
@ -40,6 +41,11 @@ class ViewsTestCase(TestCase):
|
|||
entry = models.Child.objects.first()
|
||||
page = self.c.get('/children/{}/'.format(entry.slug))
|
||||
self.assertEqual(page.status_code, 200)
|
||||
page = self.c.get(
|
||||
'/children/{}/'.format(entry.slug),
|
||||
{'date': timezone.localdate() - timezone.timedelta(days=1)})
|
||||
self.assertEqual(page.status_code, 200)
|
||||
|
||||
page = self.c.get('/children/{}/edit/'.format(entry.slug))
|
||||
self.assertEqual(page.status_code, 200)
|
||||
page = self.c.get('/children/{}/delete/'.format(entry.slug))
|
||||
|
@ -124,3 +130,15 @@ class ViewsTestCase(TestCase):
|
|||
self.assertEqual(page.status_code, 200)
|
||||
page = self.c.get('/tummy-time/{}/delete/'.format(entry.id))
|
||||
self.assertEqual(page.status_code, 200)
|
||||
|
||||
def test_weight_views(self):
|
||||
page = self.c.get('/weight/')
|
||||
self.assertEqual(page.status_code, 200)
|
||||
page = self.c.get('/weight/add/')
|
||||
self.assertEqual(page.status_code, 200)
|
||||
|
||||
entry = models.Weight.objects.first()
|
||||
page = self.c.get('/weight/{}/'.format(entry.id))
|
||||
self.assertEqual(page.status_code, 200)
|
||||
page = self.c.get('/weight/{}/delete/'.format(entry.id))
|
||||
self.assertEqual(page.status_code, 200)
|
||||
|
|
|
@ -68,4 +68,11 @@ urlpatterns = [
|
|||
name='tummytime-update'),
|
||||
url(r'^tummy-time/(?P<pk>[0-9]+)/delete/$',
|
||||
views.TummyTimeDelete.as_view(), name='tummytime-delete'),
|
||||
|
||||
url(r'^weight/$', views.WeightList.as_view(), name='weight-list'),
|
||||
url(r'^weight/add/$', views.WeightAdd.as_view(), name='weight-add'),
|
||||
url(r'^weight/(?P<pk>[0-9]+)/$', views.WeightUpdate.as_view(),
|
||||
name='weight-update'),
|
||||
url(r'^weight/(?P<pk>[0-9]+)/delete/$', views.WeightDelete.as_view(),
|
||||
name='weight-delete'),
|
||||
]
|
||||
|
|
|
@ -298,3 +298,31 @@ class TummyTimeDelete(PermissionRequiredMixin, DeleteView):
|
|||
model = models.TummyTime
|
||||
permission_required = ('core.delete_tummytime',)
|
||||
success_url = '/tummy-time'
|
||||
|
||||
|
||||
class WeightList(PermissionRequiredMixin, FilterView):
|
||||
model = models.Weight
|
||||
template_name = 'core/weight_list.html'
|
||||
permission_required = ('core.view_weight',)
|
||||
paginate_by = 10
|
||||
filter_fields = ('child',)
|
||||
|
||||
|
||||
class WeightAdd(PermissionRequiredMixin, CreateView):
|
||||
model = models.Weight
|
||||
permission_required = ('core.add_weight',)
|
||||
form_class = forms.WeightForm
|
||||
success_url = '/weight'
|
||||
|
||||
|
||||
class WeightUpdate(PermissionRequiredMixin, UpdateView):
|
||||
model = models.Weight
|
||||
permission_required = ('core.change_weight',)
|
||||
fields = ['child', 'weight', 'date']
|
||||
success_url = '/weight'
|
||||
|
||||
|
||||
class WeightDelete(PermissionRequiredMixin, DeleteView):
|
||||
model = models.Weight
|
||||
permission_required = ('core.delete_weight',)
|
||||
success_url = '/weight'
|
||||
|
|
Loading…
Reference in New Issue