diff --git a/db.sqlite3 b/db.sqlite3 index d5b662d186ea31f45cd6375642f024d3033c0174..3ad39d4692cb4dc816c59fc54d308d666ebb4941 100644 Binary files a/db.sqlite3 and b/db.sqlite3 differ diff --git a/trackerapp/__pycache__/forms.cpython-310.pyc b/trackerapp/__pycache__/forms.cpython-310.pyc index f573af21cdd39d7f8960202a925d191d1ef09332..c6c15f138c1fad23da35c2efc50a51718d02a736 100644 Binary files a/trackerapp/__pycache__/forms.cpython-310.pyc and b/trackerapp/__pycache__/forms.cpython-310.pyc differ diff --git a/trackerapp/__pycache__/models.cpython-310.pyc b/trackerapp/__pycache__/models.cpython-310.pyc index 63a4c3db3074499e3a56b54077552cbe540696eb..80f90e1a10179562336f66ff85bb0a8c43e825c2 100644 Binary files a/trackerapp/__pycache__/models.cpython-310.pyc and b/trackerapp/__pycache__/models.cpython-310.pyc differ diff --git a/trackerapp/__pycache__/urls.cpython-310.pyc b/trackerapp/__pycache__/urls.cpython-310.pyc index 2b9b011d2fd7ed51da148659cb42df4f0a0bd526..f334190b43edbe971c6dac07eda8ee339a6719a1 100644 Binary files a/trackerapp/__pycache__/urls.cpython-310.pyc and b/trackerapp/__pycache__/urls.cpython-310.pyc differ diff --git a/trackerapp/__pycache__/views.cpython-310.pyc b/trackerapp/__pycache__/views.cpython-310.pyc index e6deb63d294d9e91c5c811c1526e55996016638e..506a6954f22cd848a65c8775bdbf000d2e4dae8d 100644 Binary files a/trackerapp/__pycache__/views.cpython-310.pyc and b/trackerapp/__pycache__/views.cpython-310.pyc differ diff --git a/trackerapp/forms.py b/trackerapp/forms.py index 35603d0bef9c12b7194b9c3e5d6986914f358d18..994c5aacb8f20cdbdd918cbb6b97022d229612b8 100644 --- a/trackerapp/forms.py +++ b/trackerapp/forms.py @@ -41,35 +41,35 @@ class WorkoutForm(forms.ModelForm): } # exercise form creation - class ExerciseForm(forms.ModelForm): +class ExerciseForm(forms.ModelForm): - #Meta Class - class Meta: - model = Exercise - type = forms.ChoiceField(widget=forms.Select(choices=Exercise.TYPES)) - fields = ['name', 'type', 'set_repCount', 'workingWeight', 'workingTime', 'restTime', 'workout'] + #Meta Class + class Meta: + model = Exercise + type = forms.ChoiceField(widget=forms.Select(choices=Exercise.TYPES)) + fields = ['name', 'type', 'set_Rep_Count', 'working_Weight', 'working_Time', 'rest_Time', 'workout'] - widgets = { - 'name' : forms.TextInput(attrs={ - 'class' : 'formfield', - 'placeholder' : 'Exercise Name', - }), - 'set_repCount' : forms.TextInput(attrs={ - 'class' : 'formfield', - 'placeholder' : 'e.g. 100kg, 100lbs(Optional)', - }), - 'workingWeight' : forms.TextInput(attrs={ - 'class' : 'formfield', - 'placeholder' : 'Format: "Set Number"x"Rep Number e.g. 5x5"(Optional)', - }), - 'workingTime' : forms.TimeInput(attrs={ - 'class' : 'formfield', - 'placeholder' : 'Format: minutes:seconds(Optional)', - }), - 'restTime' : forms.TimeInput(attrs={ - 'class' : 'formfield', - 'placeholder' : 'Format: minutes:seconds(Optional)', - }), - 'workout' : forms.HiddenInput() - } + widgets = { + 'name' : forms.TextInput(attrs={ + 'class' : 'formfield', + 'placeholder' : 'Exercise Name', + }), + 'set_Rep_Count' : forms.TextInput(attrs={ + 'class' : 'formfield', + 'placeholder' : 'Format: "Set Number"x"Rep Number e.g. 5x10"(Optional)', + }), + 'working_Weight' : forms.TextInput(attrs={ + 'class' : 'formfield', + 'placeholder' : 'e.g. 100kg, 100lbs (Optional)' + }), + 'working_Time' : forms.TimeInput(attrs={ + 'class' : 'formfield', + 'placeholder' : 'Format: hh:mm:ss(Optional)', + }), + 'rest_Time' : forms.TimeInput(attrs={ + 'class' : 'formfield', + 'placeholder' : 'Format: hh:mm:ss(Optional)', + }), + 'workout' : forms.HiddenInput() + } \ No newline at end of file diff --git a/trackerapp/migrations/0012_alter_exercise_resttime_alter_exercise_workingtime.py b/trackerapp/migrations/0012_alter_exercise_resttime_alter_exercise_workingtime.py new file mode 100644 index 0000000000000000000000000000000000000000..241c1245d1b0246d1863f3443b37ba56125234b7 --- /dev/null +++ b/trackerapp/migrations/0012_alter_exercise_resttime_alter_exercise_workingtime.py @@ -0,0 +1,23 @@ +# Generated by Django 4.1.3 on 2022-12-06 13:01 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('trackerapp', '0011_alter_exercise_type'), + ] + + operations = [ + migrations.AlterField( + model_name='exercise', + name='restTime', + field=models.DurationField(blank=True, null=True), + ), + migrations.AlterField( + model_name='exercise', + name='workingTime', + field=models.DurationField(blank=True, null=True), + ), + ] diff --git a/trackerapp/migrations/0013_rename_workingweight_exercise_working_weight_and_more.py b/trackerapp/migrations/0013_rename_workingweight_exercise_working_weight_and_more.py new file mode 100644 index 0000000000000000000000000000000000000000..8a7f90c3cfc65029416e41a0fab8e52030e668ed --- /dev/null +++ b/trackerapp/migrations/0013_rename_workingweight_exercise_working_weight_and_more.py @@ -0,0 +1,45 @@ +# Generated by Django 4.1.3 on 2022-12-06 15:15 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('trackerapp', '0012_alter_exercise_resttime_alter_exercise_workingtime'), + ] + + operations = [ + migrations.RenameField( + model_name='exercise', + old_name='workingWeight', + new_name='working_Weight', + ), + migrations.RemoveField( + model_name='exercise', + name='restTime', + ), + migrations.RemoveField( + model_name='exercise', + name='set_repCount', + ), + migrations.RemoveField( + model_name='exercise', + name='workingTime', + ), + migrations.AddField( + model_name='exercise', + name='rest_Time', + field=models.DurationField(blank=True, max_length=8, null=True), + ), + migrations.AddField( + model_name='exercise', + name='set_Rep_Count', + field=models.CharField(blank=True, max_length=5), + ), + migrations.AddField( + model_name='exercise', + name='working_Time', + field=models.DurationField(blank=True, max_length=8, null=True), + ), + ] diff --git a/trackerapp/migrations/__pycache__/0012_alter_exercise_resttime_alter_exercise_workingtime.cpython-310.pyc b/trackerapp/migrations/__pycache__/0012_alter_exercise_resttime_alter_exercise_workingtime.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..da2397d3067d8fd85cc8740004302b6f144e73a6 Binary files /dev/null and b/trackerapp/migrations/__pycache__/0012_alter_exercise_resttime_alter_exercise_workingtime.cpython-310.pyc differ diff --git a/trackerapp/migrations/__pycache__/0013_rename_workingweight_exercise_working_weight_and_more.cpython-310.pyc b/trackerapp/migrations/__pycache__/0013_rename_workingweight_exercise_working_weight_and_more.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3d601da13ec1728ce70ff3c2406949d4e0496914 Binary files /dev/null and b/trackerapp/migrations/__pycache__/0013_rename_workingweight_exercise_working_weight_and_more.cpython-310.pyc differ diff --git a/trackerapp/models.py b/trackerapp/models.py index 5a40d9fd7dba15acda480fd86d5c3ef746081397..ed90379aa7100ac90200f661bc218066dda2db1d 100644 --- a/trackerapp/models.py +++ b/trackerapp/models.py @@ -42,10 +42,10 @@ class Exercise(models.Model): type = models.CharField(max_length = 10, choices = TYPES, default = "resistance") - set_repCount = models.CharField(max_length = 3, blank=True) - workingWeight = models.CharField(max_length = 16, blank=True) - workingTime = models.DurationField(blank=True) - restTime = models.DurationField(blank=True) + set_Rep_Count = models.CharField(max_length = 5, blank=True) + working_Weight = models.CharField(max_length = 16, blank=True) + working_Time = models.DurationField(max_length = 8, blank=True, null=True) + rest_Time = models.DurationField(max_length = 8, blank=True, null=True) workout = models.ForeignKey(Workout, on_delete=models.CASCADE) diff --git a/trackerapp/templates/trackerapp/detail_view.html b/trackerapp/templates/trackerapp/detail_view.html index c489f0b9f109c6e76a32128677c6d8bbb641b8d2..75a771b9a51b3d3c47694769ed2d67748407154b 100644 --- a/trackerapp/templates/trackerapp/detail_view.html +++ b/trackerapp/templates/trackerapp/detail_view.html @@ -1,15 +1,17 @@ {% extends "base.html" %} {% block content %} <body> - <h2>{{ plan.name }}</h2> <p> {{ plan.description }}</p> <input type="button" onclick="location.href='{% url 'tracker_update' plan.id %}';" value="Edit" /> <input type="button" onclick="location.href='{% url 'tracker_delete' plan.id %}';" value="Delete" /> + <input type="button" onclick="location.href='{% url 'tracker_index' %}';" + value="Back" /> <hr/> - {% include 'trackerapp/workouts_index.html' with pid=plan.id%} + {% include 'trackerapp/workouts_index.html' with pid=plan.id %} <input type="button" onclick="location.href='{% url 'workouts_new' pid=plan.id %}';" value="Add Workout"/> + </body> {% endblock content %} \ No newline at end of file diff --git a/trackerapp/templates/trackerapp/exercises_create_view.html b/trackerapp/templates/trackerapp/exercises_create_view.html new file mode 100644 index 0000000000000000000000000000000000000000..c99b0dce85fe74931c78cdd6e88b8fc062a9938a --- /dev/null +++ b/trackerapp/templates/trackerapp/exercises_create_view.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} +{% block content %} +<h2>Enter a exercise</h2> +<form method="POST" enctype="multipart/form-data"> + <!-- Security token --> + {% csrf_token %} + <!-- Using the formset --> + {{ form.as_p }} + <input type="submit" value="Submit"> +</form> +{% endblock content %} \ No newline at end of file diff --git a/trackerapp/templates/trackerapp/exercises_detail_view.html b/trackerapp/templates/trackerapp/exercises_detail_view.html new file mode 100644 index 0000000000000000000000000000000000000000..f2cec7b7305844c1fe9192c45bc9c6ece0b519ee --- /dev/null +++ b/trackerapp/templates/trackerapp/exercises_detail_view.html @@ -0,0 +1,17 @@ +{% extends "base.html" %} +{% block content %} + <body> + <h2>{{ exercise.name }}</h2> + <p> {{ exercise.type }}</p> + <p> {{ exercise.set_repCount }}</p> + <p> {{ exercise.workingWeight }}</p> + <p> {{ exercise.workingTime }}</p> + <p> {{ exercise.restTime }}</p> + <input type="button" onclick="location.href='{% url 'exercises_update' eid=exercise.id %}';" + value="Edit" /> + <input type="button" onclick="location.href='{% url 'exercises_delete' eid=exercise.id %}';" + value="Delete" /> + <input type="button" onclick="location.href='{% url 'workouts_detail' wid=exercise.workout.id %}';" + value="Back" /> + </body> +{% endblock content %} \ No newline at end of file diff --git a/trackerapp/templates/trackerapp/exercises_index.html b/trackerapp/templates/trackerapp/exercises_index.html new file mode 100644 index 0000000000000000000000000000000000000000..030c0788084ae8175249b56d0f29598f862eed12 --- /dev/null +++ b/trackerapp/templates/trackerapp/exercises_index.html @@ -0,0 +1,35 @@ +<h2>Exercises List</h2> +<table> + <tr> + <th>Name</th> + <th>Type</th> + <th>Set Rep Count (Optional)</th> + <th>Working Weight (Optional)</th> + <th>Working Time (Optional)</th> + <th>Rest Time (Optional)</th> + </tr> + {% for exercise in exercise_list %} + <tr> + <td> + <a href="{% url 'exercises_detail' exercise.id %}"> + {{ exercise.name }} + </a> + </td> + <td> + {{ exercise.type }} + </td> + <td> + {{ exercise.set_repCount }} + </td> + <td> + {{ exercise.workingWeight }} + </td> + <td> + {{ exercise.workingTime }} + </td> + <td> + {{ exercise.restTime }} + </td> + </tr> + {% endfor %} +</table> \ No newline at end of file diff --git a/trackerapp/templates/trackerapp/exercises_update_view.html b/trackerapp/templates/trackerapp/exercises_update_view.html new file mode 100644 index 0000000000000000000000000000000000000000..c8e5c1c996a5381239fbbee589b025edcee5b0d1 --- /dev/null +++ b/trackerapp/templates/trackerapp/exercises_update_view.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} +{% block content %} +<h2>Update this exercise</h2> +<form method="POST" enctype="multipart/form-data"> + <!-- Security token --> + {% csrf_token %} + <!-- Using the formset --> + {{ form.as_p }} + <input type="submit" value="Update"> +</form> +{% endblock content %} \ No newline at end of file diff --git a/trackerapp/templates/trackerapp/workouts_detail_view.html b/trackerapp/templates/trackerapp/workouts_detail_view.html index c6f3eb6df00223219578d5cb211d08683ccf2eaf..b25f0746242d2193283a40dcd871fe8c88303fef 100644 --- a/trackerapp/templates/trackerapp/workouts_detail_view.html +++ b/trackerapp/templates/trackerapp/workouts_detail_view.html @@ -1,14 +1,17 @@ {% extends "base.html" %} +{% load i18n %} {% block content %} <body> - <h2>{{ plan.name }}</h2> - <h3>{{ workout.name }}</h3> + <h2>{{ workout.name }}</h2> <p> {{ workout.weekday }}</p> <input type="button" onclick="location.href='{% url 'workouts_update' wid=workout.id %}';" value="Edit" /> <input type="button" onclick="location.href='{% url 'workouts_delete' wid=workout.id %}';" value="Delete" /> + <input type="button" onclick="location.href='{% url 'tracker_detail' pid=workout.plan.id %}';" + value="Back" /> <hr/> - + {% include "trackerapp/exercises_index.html" with wid=workout.id %} + <input type="button" onclick="location.href='{% url 'exercises_new' wid=workout.id %}';" value="Add Exercise"/> </body> {% endblock content %} \ No newline at end of file diff --git a/trackerapp/tests.py b/trackerapp/tests.py index 681a5b6279495bf552da6d1b85412f11da06de83..fc47ecfae580c91647c98d8bb46e33b3eab337e3 100644 --- a/trackerapp/tests.py +++ b/trackerapp/tests.py @@ -2,8 +2,8 @@ from django.db.backends.sqlite3.base import IntegrityError from django.db import transaction from django.test import TestCase from django.urls import reverse -from .models import Plan, Workout -from .forms import WorkoutForm +from .models import Plan, Workout, Exercise +from .forms import PlanForm, WorkoutForm, ExerciseForm class PlanTests(TestCase): @@ -14,6 +14,7 @@ class PlanTests(TestCase): p = Plan(name = "PPL", description = "A higher volume workout that focuses on different muscle groups per day") p.save() + def test_saved_plans(self): db_count = Plan.objects.all().count() p = Plan(name = "Test Plan", description = "Test Description") @@ -51,6 +52,24 @@ class PlanTests(TestCase): self.assertTrue(form.is_valid()) def test_post_create_empty_workout(self): + data = { + "name" : "", + "weekday" : "Monday", + "plan" : Plan.objects.get(pk=1) + } + form = WorkoutForm(data) + self.assertFalse(form.is_valid()) + + def test_post_create_exercise(self): + data = { + "name" : "Full Body 1", + "weekday" : "Monday", + "plan" : Plan.objects.get(pk=1) + } + form = WorkoutForm(data) + self.assertTrue(form.is_valid()) + + def test_post_create_empty_exercise(self): data = { "name" : "", "weekday" : "Monday", diff --git a/trackerapp/urls.py b/trackerapp/urls.py index 8391decb6380b0e21c181dccc6733a2e77879967..fc6b649f80c00f8c82bf6f5eb15de562e3e7e829 100644 --- a/trackerapp/urls.py +++ b/trackerapp/urls.py @@ -5,14 +5,14 @@ urlpatterns = [ # workout plan lists path('', views.index_view, name='tracker_index'), # workout plan details (shows list of workouts over the course of a week) - path('<int:pk>', views.PlanDetailView, name='tracker_detail'), + path('<int:pid>', views.PlanDetailView, name='tracker_detail'), # create new workout plans path('new', views.create_view, name='tracker_new'), # edit workout plans path('<int:pid>/edit', views.update_view, name='tracker_update'), # delete workout plans path('<int:pid>/delete', views.delete_view, name='tracker_delete'), - # view individual workouts + # view workouts list path('<int:pid>/workouts', views.WorkoutListView, name='workouts_index'), # workout details (shows list of exercises) path('workouts/<int:wid>', views.WorkoutDetailView, name='workouts_detail'), @@ -21,10 +21,15 @@ urlpatterns = [ # update new workouts path('workouts/<int:wid>/edit', views.UpdateWorkoutsView, name='workouts_update'), # delete workouts - path('workouts/<int:wid>/delete', views.DeleteWorkoutView, name='workouts_delete'), - # exercise list + path('workouts/<int:wid>/delete', views.DeleteWorkoutsView, name='workouts_delete'), + # view exercises list + path('<int:wid>/exercises', views.ExerciseListView, name='exercises_index'), # exercise details + path('exercises/<int:eid>', views.ExerciseDetailView, name='exercises_detail'), # create new exercise + path('<int:wid>/exercises/new', views.CreateExercisesView, name='exercises_new'), # edit exercise + path('exercises/<int:eid>/edit', views.UpdateExercisesView, name='exercises_update'), # delete exercise + path('exercises/<int:eid>/delete', views.DeleteExercisesView, name='exercises_delete'), ] diff --git a/trackerapp/views.py b/trackerapp/views.py index 5ce11938c36e1655455685b1316cd45d28b6b1d7..3645491628f77527f88b80ee4dc3244d8b94e277 100644 --- a/trackerapp/views.py +++ b/trackerapp/views.py @@ -2,8 +2,8 @@ from django.shortcuts import get_object_or_404, render, redirect from django.http import HttpResponse from django.urls import reverse_lazy from django.contrib import messages -from .forms import PlanForm, WorkoutForm -from .models import Plan, Workout +from .forms import PlanForm, WorkoutForm, ExerciseForm +from .models import Plan, Workout, Exercise def index_view(request): @@ -11,23 +11,33 @@ def index_view(request): context["plan_list"] = Plan.objects.all() return render(request, "trackerapp/index.html", context) -def WorkoutListView(request, pid): +def PlanDetailView(request, pid): context = {} + context["plan"] = Plan.objects.get(id=pid) context["workout_list"] = Workout.objects.filter(plan__id=pid) - return render(request, "trackerapp/workouts_index.html", context) + return render(request, "trackerapp/detail_view.html", context) -def PlanDetailView(request, pk): +def WorkoutListView(request, pid): context = {} - context["plan"] = Plan.objects.get(id=pk) - context["workout_list"] = Workout.objects.filter(plan__id=pk) - return render(request, "trackerapp/detail_view.html", context) + context["workout_list"] = Workout.objects.filter(plan__id=pid) + return render(request, "trackerapp/workouts_index.html", context) def WorkoutDetailView(request, wid): context = {} - context["plan"] = Plan.objects.all() context["workout"] = Workout.objects.get(id=wid) + context["exercise_list"] = Exercise.objects.filter(workout__id=wid) return render(request, "trackerapp/workouts_detail_view.html", context) +def ExerciseListView(request, wid): + context = {} + context["exercise_list"] = Exercise.objects.filter(workout__id=wid) + return render(request, "trackerapp/exercises_index.html", context) + +def ExerciseDetailView(request, eid): + context = {} + context["exercise"] = Exercise.objects.get(id=eid) + return render(request, "trackerapp/exercises_detail_view.html", context) + def create_view(request): context = {} form = PlanForm(request.POST or None) @@ -52,20 +62,20 @@ def CreateWorkoutsView(request, pid): context['form'] = form context['form'].fields['plan'].initial = pid - return render(request, "trackerapp/workouts_create_view.html", context) + return render(request, "trackerapp/workouts_create_view.html", context) -def UpdateWorkoutsView(request, wid): +def CreateExercisesView(request, wid): context = {} - obj = get_object_or_404(Workout, id = wid) - form = WorkoutForm(request.POST or None, instance = obj) + form = ExerciseForm(request.POST or None) if(request.method == 'POST'): - if form.is_valid(): + if(form.is_valid()): form.save() - messages.add_message(request, messages.SUCCESS, 'Workout Plan Updated') return redirect('workouts_detail', wid = wid) - + context['form'] = form - return render(request, "trackerapp/workouts_update_view.html", context) + context['form'].fields['workout'].initial = wid + return render(request, "trackerapp/exercises_create_view.html", context) + def update_view(request, pid): context = {} @@ -76,9 +86,35 @@ def update_view(request, pid): form.save() messages.add_message(request, messages.SUCCESS, 'Workout Plan Updated') return redirect('tracker_detail', pid = pid) - + context['form'] = form return render(request, "trackerapp/update_view.html", context) + +def UpdateWorkoutsView(request, wid): + context = {} + obj = get_object_or_404(Workout, id = wid) + form = WorkoutForm(request.POST or None, instance = obj) + if(request.method == 'POST'): + if form.is_valid(): + form.save() + messages.add_message(request, messages.SUCCESS, 'Workout Plan Updated') + return redirect('workouts_detail', wid = wid) + + context['form'] = form + return render(request, "trackerapp/workouts_update_view.html", context) + +def UpdateExercisesView(request, eid): + context = {} + obj = get_object_or_404(Exercise, id = eid) + form = ExerciseForm(request.POST or None, instance = obj) + if(request.method == 'POST'): + if form.is_valid(): + form.save() + messages.add_message(request, messages.SUCCESS, 'Exercise Updated') + return redirect('exercises_detail', eid = eid) + + context['form'] = form + return render(request, "trackerapp/exercises_update_view.html", context) def delete_view(request, pid): obj = get_object_or_404(Plan, id = pid) @@ -86,10 +122,16 @@ def delete_view(request, pid): messages.add_message(request, messages.SUCCESS, 'Workout Plan Deleted') return redirect('tracker_index') -def DeleteWorkoutView(request, wid): +def DeleteWorkoutsView(request, wid): workout = Workout.objects.get(pk=wid) pid = workout.plan_id workout.delete() return redirect('tracker_detail', pid) + +def DeleteExercisesView(request, eid): + exercise = Exercise.objects.get(pk=eid) + wid = exercise.workout_id + exercise.delete() + return redirect('workouts_detail', wid) \ No newline at end of file