Compare commits

...

10 Commits

Author SHA1 Message Date
James Turk
7bfa16c10a add old shaft files for reference, can delete them as they're used 2015-12-15 11:49:18 -05:00
James Turk
e23b136b3a LiftOptions 2015-06-16 17:03:04 -04:00
James Turk
f9ff40312b test with different units and bars 2015-04-12 23:59:21 -04:00
James Turk
647531f96c plates_for_weight
also add different weight_lb for bars
2015-04-12 23:46:43 -04:00
James Turk
d70de69f3d improve fitnotes importer 2015-04-12 23:06:52 -04:00
James Turk
9ec636fbef fix a couple of issues 2015-04-12 13:40:03 -04:00
James Turk
f0a8f6b75c lifting portion of form works 2015-04-10 17:31:12 -04:00
James Turk
2f9fbc4d90 add bar setting 2015-04-10 17:30:35 -04:00
James Turk
213e79a20f fitnotes cleanup 2015-04-10 15:21:15 -04:00
James Turk
51a4126763 no tests for inventory for now 2015-04-10 15:18:37 -04:00
31 changed files with 776 additions and 79 deletions

View File

@ -1,3 +0,0 @@
from django.contrib import admin
# Register your models here.

View File

@ -26,30 +26,24 @@ def import_fitnotes_db(filename, user, fitnotes_to_lift=DEFAULT_MAPPING):
# lift name => id
lift_ids = {_clean_name(l.name): l.id for l in Lift.objects.all()}
# build mapping FitNotes exercise id => our lift id
lift_id_mapping = {}
conn = sqlite3.connect(filename)
cur = conn.cursor()
for fnid, ename in cur.execute('SELECT _id, name FROM exercise WHERE exercise_type_id=0'):
cleaned = _clean_name(ename)
if cleaned not in fitnotes_to_lift:
lift_id_mapping[fnid] = cleaned
else:
lift_id_mapping[fnid] = lift_ids[fitnotes_to_lift[cleaned]]
with transaction.atomic():
Set.objects.filter(source='fitnotes').delete()
for fnid, date, weight_kg, reps in cur.execute(
'SELECT exercise_id, date, metric_weight, reps FROM training_log'):
count = 0
for fname, date, weight_kg, reps in cur.execute(
'SELECT name, date, metric_weight, reps FROM training_log, exercise '
'WHERE exercise_type_id=0 and exercise_id=exercise._id'
):
# error if mapping wasn't found and there's a workout using it
if isinstance(lift_id_mapping[fnid], str):
raise ValueError('no known conversion for fitnotes exercise "{}"'.format(
lift_id_mapping[fnid]))
lift_id = lift_id_mapping[fnid]
try:
lift_id = lift_ids[fitnotes_to_lift[_clean_name(fname)]]
except KeyError:
raise ValueError('no known conversion for fitnotes exercise "{}"'.format(fname))
Set.objects.create(lift_id=lift_id, date=date, weight_kg=weight_kg, reps=reps,
source='fitnotes', user=user)
count += 1
return count

View File

@ -1,3 +0,0 @@
from django.db import models
# Create your models here.

Binary file not shown.

View File

@ -31,7 +31,8 @@ class TestFitnotesImport(TestCase):
def test_basic_import(self):
# ensure that the data comes in
import_fitnotes_db('fitnotes/testdata/example.fitnotes', self.user, self.good_mapping)
num = import_fitnotes_db('fitnotes/testdata/example.fitnotes', self.user, self.good_mapping)
assert num == 9
assert Set.objects.filter(lift=self.bench).count() == 4
assert Set.objects.filter(lift=self.squat).count() == 5
@ -53,10 +54,9 @@ class TestFitnotesImport(TestCase):
import_fitnotes_db('fitnotes/testdata/example.fitnotes', self.user, self.bad_mapping)
assert Set.objects.filter(lift=self.bench).count() == 0
def test_bad_data_import(self):
def test_bad_data_doesnt_overwrite(self):
# good db then bad db, should fail without screwing up existing data
import_fitnotes_db('fitnotes/testdata/example.fitnotes', self.user, self.good_mapping)
with self.assertRaises(Exception):
# baddata.fitnotes has all lift ids set to 9999
import_fitnotes_db('fitnotes/testdata/baddata.fitnotes', self.user, self.good_mapping)
with self.assertRaises(ValueError):
import_fitnotes_db('fitnotes/testdata/example.fitnotes', self.user, self.bad_mapping)
assert Set.objects.count() == 9

View File

@ -3,5 +3,5 @@ from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^upload/$', views.fitnotes_upload),
url(r'^$', views.fitnotes_upload),
]

View File

@ -16,6 +16,7 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', auto_created=True, serialize=False, primary_key=True)),
('name', models.CharField(max_length=100)),
('weight_kg', models.DecimalField(max_digits=7, decimal_places=3)),
('weight_lb', models.DecimalField(max_digits=7, decimal_places=3)),
],
),
migrations.CreateModel(

View File

@ -7,8 +7,8 @@ from django.db import models, migrations
def make_bars(apps, schema_editor):
Bar = apps.get_model('inventory', 'Bar')
Bar.objects.bulk_create([
Bar(name="Women's Olympic", weight_kg='15'),
Bar(name="Men's Olympic", weight_kg='20'),
Bar(id=1, name="Men's Olympic", weight_kg='20', weight_lb='45'),
Bar(id=2, name="Women's Olympic", weight_kg='15', weight_lb='35'),
])

View File

@ -1,22 +1,24 @@
from django.db import models
from common import to_lb
from common import remove_exponent, to_lb
class Bar(models.Model):
name = models.CharField(max_length=100)
weight_kg = models.DecimalField(max_digits=7, decimal_places=3)
weight_lb = models.DecimalField(max_digits=7, decimal_places=3)
def __str__(self):
return '{} ({}lb / {}kg)'.format(self.name, self.weight_kg, self.weight_lb)
@property
def weight_lb(self):
return to_lb(self.weight_kg)
return '{} ({}kg / {}lb)'.format(self.name, remove_exponent(self.weight_kg),
self.weight_lb)
class Lift(models.Model):
name = models.CharField(max_length=200)
@property
def display_name(self):
return self.name
def __str__(self):
return self.name

View File

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View File

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('inventory', '3000_initial_data'),
('lifting', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='liftingoptions',
name='default_bar',
field=models.ForeignKey(default=1, to='inventory.Bar'),
preserve_default=False,
),
]

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('lifting', '0002_liftingoptions_default_bar'),
]
operations = [
migrations.AlterField(
model_name='liftingoptions',
name='default_bar',
field=models.ForeignKey(default=1, to='inventory.Bar'),
),
]

View File

@ -1,7 +1,8 @@
from decimal import Decimal
from django.db import models
from django.contrib.auth.models import User
from django.contrib.postgres.fields import ArrayField
from inventory.models import Lift
from inventory.models import Lift, Bar
SET_TYPES = (
('warmup', 'Warmup'),
@ -18,9 +19,37 @@ class LiftingOptions(models.Model):
user = models.OneToOneField(User, related_name='lifting_options')
lifting_units = models.CharField(max_length=1, choices=UNITS, default='i')
default_bar = models.ForeignKey(Bar, default=1)
plate_pairs = ArrayField(models.DecimalField(max_digits=7, decimal_places=3),
default=['45','45','25','10','5','5','2.5','1.25'])
def plates_for_weight(self, weight):
side = []
w = Decimal(weight)
if self.lifting_units == 'i':
w -= self.default_bar.weight_lb
else:
w -= self.default_bar.weight_kg
initial_weight = w
available = sorted(self.plate_pairs, reverse=True)
while w and available:
plate = available.pop(0)
if plate * 2 <= w:
w -= plate * 2
side.append(plate)
if sum(side) * 2 != initial_weight:
raise ValueError('remaining weight {}'.format(initial_weight - sum(side) * 2))
return side
class LiftOptions(models.Model):
user = models.ForeignKey(User, related_name='lift_options')
lift = models.ForeignKey(Lift, related_name='options')
bar = models.ForeignKey(Bar, null=True)
extra_start_weight = models.DecimalField(max_digits=7, decimal_places=3, default=0)
increment = models.DecimalField(max_digits=5, decimal_places=3, default=5)
class Set(models.Model):
user = models.ForeignKey(User, related_name='sets')

View File

@ -1,10 +1,13 @@
from django import template
from django.template.defaultfilters import stringfilter
from common import to_lb
from common import to_lb, remove_exponent
register = template.Library()
register.filter('decimal', remove_exponent)
class MassNode(template.Node):
def __init__(self, weight):
self.weight = template.Variable(weight)

View File

@ -1,3 +1,4 @@
from decimal import Decimal as D
from django.test import TestCase
from django.contrib.auth.models import User
from lifting.models import LiftingOptions
@ -5,6 +6,55 @@ from lifting.models import LiftingOptions
class TestLiftingOptions(TestCase):
def setUp(self):
self.user = User.objects.create_user(username='test', email='test@example.com', password='test')
def test_signal(self):
u = User.objects.create_user(username='test', email='test@example.com', password='test')
assert LiftingOptions.objects.filter(user=u).count() == 1
assert LiftingOptions.objects.filter(user=self.user).count() == 1
def test_plates_for_weight(self):
opts = self.user.lifting_options
opts.plate_pairs = [D(45), D(45), D(25), D(10), D(5), D(5), D('2.5')]
opts.default_bar_id = 1
opts.lifting_units = 'i'
assert opts.plates_for_weight(45) == []
assert opts.plates_for_weight(50) == [D('2.5')]
assert opts.plates_for_weight(90) == [D(10), D(5), D(5), D('2.5')]
assert opts.plates_for_weight(320) == [D(45), D(45), D(25), D(10), D(5), D(5), D('2.5')]
def test_plates_for_weight_womens_bar(self):
opts = self.user.lifting_options
opts.plate_pairs = [D(45), D(45), D(25), D(10), D(5), D(5), D('2.5')]
opts.default_bar_id = 2
opts.lifting_units = 'i'
assert opts.plates_for_weight(35) == []
assert opts.plates_for_weight(40) == [D('2.5')]
assert opts.plates_for_weight(80) == [D(10), D(5), D(5), D('2.5')]
assert opts.plates_for_weight(310) == [D(45), D(45), D(25), D(10), D(5), D(5), D('2.5')]
def test_plates_for_weight_kg(self):
opts = self.user.lifting_options
opts.plate_pairs = [D(20), D(20), D(10), D(5), D('2.5')]
opts.default_bar_id = 1
opts.lifting_units = 'm'
assert opts.plates_for_weight(20) == []
assert opts.plates_for_weight(25) == [D('2.5')]
assert opts.plates_for_weight(55) == [D(10), D(5), D('2.5')]
assert opts.plates_for_weight(135) == [D(20), D(20), D(10), D(5), D('2.5')]
def test_plates_for_weight_error(self):
opts = self.user.lifting_options
opts.plate_pairs = [D(45), D(45), D(25), D(10), D(5), D(5), D('2.5')]
opts.default_bar_id = 1
opts.lifting_units = 'i'
# TODO: check amounts
with self.assertRaises(ValueError):
opts.plates_for_weight('47.5')
with self.assertRaises(ValueError):
opts.plates_for_weight(325)
with self.assertRaises(ValueError):
opts.plates_for_weight(30)

View File

@ -10,5 +10,5 @@ urlpatterns = [
url(r'^lifts/$', views.lift_list, name='lift-list'),
url(r'^lifts/(?P<lift_id>\d+)/$', views.by_lift, name='lift-detail'),
url(r'^edit/$', views.edit_profile, name='edit-profile'),
url(r'^options/$', views.edit_options, name='edit-options'),
]

View File

@ -1,17 +1,17 @@
import calendar
import datetime
import decimal
import os
import tempfile
import calendar
from collections import defaultdict
from collections import defaultdict, Counter
from django.shortcuts import render
from django import forms
from django.contrib.auth.decorators import login_required
from django.views.generic import dates
from django.db.models import Count, Max
from inventory.models import Lift, Bar
from .models import Set
from inventory.models import Lift
@login_required
@ -83,7 +83,25 @@ def by_lift(request, lift_id):
@login_required
def edit_profile(request):
form = request.user.profile
def edit_options(request):
lifting_options = request.user.lifting_options
return render(request, 'profiles/edit.html', {'form': form})
if request.method == 'POST':
print(request.POST)
plates = []
for weight, number in zip(request.POST.getlist('plate_weight'),
request.POST.getlist('plate_number')):
if weight and number:
plates += [decimal.Decimal(weight)] * int(number)
lifting_options.plate_pairs = plates
lifting_options.default_bar_id = int(request.POST.get('barbell'))
lifting_options.lifting_units = request.POST.get('lifting_units')
lifting_options.save()
bars = Bar.objects.all()
plates = sorted(Counter(lifting_options.plate_pairs).items())
return render(request, 'profiles/edit.html', {'lifting_options': lifting_options,
'bars': bars, 'plates': plates,
})

View File

@ -0,0 +1,15 @@
from django import template
from django.template.loader import render_to_string
register = template.Library()
@register.filter
def formfield(value, arg):
if ',' in arg:
size, units = arg.split(',')
else:
size = arg
units = None
return render_to_string('lifting/_form-group.html',
{'field': value, 'size': size, 'units': units})

View File

@ -0,0 +1,82 @@
class Plan(models.Model):
name = models.CharField(max_length=100)
tags = models.ManyToManyField(PlanTag, related_name='plans')
public = models.BooleanField(default=False)
owner = models.ForeignKey(User, related_name='plans', null=True)
cloned_from = models.ForeignKey('self', null=True)
objects = ByNameManager()
def __str__(self):
return '{0}'.format(self.name)
def get_absolute_url(self):
return reverse('lifting.views.plan', args=[str(self.id)])
def natural_key(self):
return (self.name,)
def get_days(self, user):
exercise_rules = {}
days = []
for day in self.days.all():
day_sets = []
for exercise in day.exercises.all():
for reps in exercise.get_sets():
rules = exercise_rules.setdefault(exercise.exercise,
exercise.exercise.rules.get(user=user))
day_sets.append(
Set(exercise=exercise.exercise,
weight=round_to(rules.work_weight*exercise.percent, rules.increment),
reps=reps,
type='planned')
)
if exercise.raise_weight:
rules.work_weight += rules.increment
days.append(day_sets)
return days
class PlanDay(models.Model):
plan = models.ForeignKey(Plan, related_name='days')
name = models.CharField(max_length=100)
order = models.PositiveIntegerField()
def __str__(self):
return '{0}: {1}'.format(self.plan, self.name)
class Meta:
ordering = ['order']
class PlanExercise(models.Model):
plan_day = models.ForeignKey(PlanDay, related_name='exercises')
exercise = models.ForeignKey(Exercise)
order = models.PositiveIntegerField()
sets = models.CharField(max_length=100)
percent = models.DecimalField(max_digits=4, decimal_places=3, default=1)
raise_weight = models.BooleanField(default=False)
def get_sets(self):
return [int(s) for s in self.sets.split(',')]
def get_set_display(self):
sets = []
last_reps = None
last_reps_num = 0
for s in self.get_sets():
if last_reps and s != last_reps:
sets.append('{0}x{1}'.format(last_reps_num, last_reps))
last_reps_num = 0
last_reps_num += 1
last_reps = s
sets.append('{0}x{1}'.format(last_reps_num, last_reps))
return ', '.join(sets)
def get_percent_display(self):
return '{0:%}'.format(self.percent)
class Meta:
ordering = ['order']

View File

@ -0,0 +1,31 @@
from decimal import Decimal as D
from .models import ExerciseRules, Set
from .utils import round_to
def warmup_ss(exercise, weight, user):
"""
Starting Strength Warmup
========================
(start)x5 x2
(40%)x5
(60%)x3
(80%)x2
"""
# get relevant rules
rules, _ = ExerciseRules.objects.get_or_create(user=user, exercise=exercise)
start = rules.start_weight
# empty bar sets
sets = [Set(exercise=exercise, weight=start, reps=5, type='warmup')]*2
if D('0.8')*weight < start:
return []
for reps, pct in ((5, D('0.4')), (3, D('0.6')), (2, D('0.8'))):
ww = round_to(weight * pct, D('5'))
if ww > start:
sets.append(Set(exercise=exercise, weight=ww, reps=reps, type='warmup'))
return sets

View File

@ -0,0 +1,147 @@
from decimal import Decimal as D
from django.test import TestCase
from django.contrib.auth.models import User
from .models import Exercise, UserSettings, ExerciseRules, Plan
from .plans import warmup_ss
from .utils import round_to
def _seteq(s1, exercise, weight, reps):
try:
assert s1.exercise == exercise
assert s1.weight == weight
assert s1.reps == reps
except AssertionError:
raise AssertionError('{0} != {1}x{2}'.format(s1, weight, reps))
class PlanTests(TestCase):
def setUp(self):
self.user = User.objects.create_user(username='user')
self.squat = Exercise.objects.create(name='squat')
self.bench = Exercise.objects.create(name='bench press')
ExerciseRules.objects.create(user=self.user, exercise=self.squat, work_weight=200)
ExerciseRules.objects.create(user=self.user, exercise=self.bench, work_weight=100)
self.tm = Plan.objects.create(name='Texas Method')
a1 = self.tm.days.create(name='A week - Volume day', order=1)
a1.exercises.create(exercise=self.squat, order=1, sets='5,5,5,5,5', percent=D('0.85'))
a1.exercises.create(exercise=self.bench, order=2, sets='5,5,5,5,5', percent=D('0.85'))
a2 = self.tm.days.create(name='A week - Recovery day', order=2)
a2.exercises.create(exercise=self.squat, order=1, sets='5,5', percent=D('0.8'))
# exaggerated raise_weight for tests
a3 = self.tm.days.create(name='A week - Record day', order=3)
a3.exercises.create(exercise=self.squat, order=1, sets='5', percent=D(1),
raise_weight=True)
a3.exercises.create(exercise=self.bench, order=2, sets='5', percent=D(1),
raise_weight=True)
b1 = self.tm.days.create(name='B week - Volume day', order=4)
b1.exercises.create(exercise=self.squat, order=1, sets='5,5,5,5,5', percent=D('0.85'))
b2 = self.tm.days.create(name='B week - Recovery day', order=5)
b2.exercises.create(exercise=self.squat, order=1, sets='5,5', percent=D('0.8'))
b2.exercises.create(exercise=self.bench, order=1, sets='5,5', percent=D('0.8'))
b3 = self.tm.days.create(name='B week - Record day', order=6)
b3.exercises.create(exercise=self.squat, order=2, sets='5', percent=D(1))
def test_get_days(self):
a1, a2, a3, b1, b2, b3 = self.tm.get_days(self.user)
_seteq(a1[0], self.squat, 170, 5)
_seteq(a1[1], self.squat, 170, 5)
_seteq(a1[2], self.squat, 170, 5)
_seteq(a1[3], self.squat, 170, 5)
_seteq(a1[4], self.squat, 170, 5)
_seteq(a1[5], self.bench, 85, 5)
_seteq(a1[6], self.bench, 85, 5)
_seteq(a1[7], self.bench, 85, 5)
_seteq(a1[8], self.bench, 85, 5)
_seteq(a1[9], self.bench, 85, 5)
_seteq(a2[0], self.squat, 160, 5)
_seteq(a2[1], self.squat, 160, 5)
_seteq(a3[0], self.squat, 200, 5)
_seteq(a3[1], self.bench, 100, 5)
# b record day raised by 5
_seteq(b3[0], self.squat, 205, 5)
class WarmupTests(TestCase):
def setUp(self):
self.exercise = Exercise.objects.create(name='bench press')
self.user = User.objects.create_user(username='user')
def test_round_to(self):
assert round_to(D('21'), D('2.5')) == D('20')
assert round_to(D('23'), D('2.5')) == D('22.5')
assert round_to(D('23'), D('5')) == D('20')
assert round_to(D('24.5'), D('2.5')) == D('22.5')
assert round_to(D('24.9'), D('5')) == D('25')
def test_warmup_ss(self):
# <=55: no warmup
assert warmup_ss(self.exercise, D('10'), self.user) == []
assert warmup_ss(self.exercise, D('55'), self.user) == []
# 60: just the bar
sets = warmup_ss(self.exercise, D('60'), self.user)
assert len(sets) == 2, sets
_seteq(sets[0], self.exercise, 45, 5)
_seteq(sets[1], self.exercise, 45, 5)
sets = warmup_ss(self.exercise, D('70'), self.user)
_seteq(sets[0], self.exercise, 45, 5)
_seteq(sets[1], self.exercise, 45, 5)
_seteq(sets[2], self.exercise, 55, 2)
sets = warmup_ss(self.exercise, D('95'), self.user)
_seteq(sets[0], self.exercise, 45, 5)
_seteq(sets[1], self.exercise, 45, 5)
_seteq(sets[2], self.exercise, 55, 3)
_seteq(sets[3], self.exercise, 75, 2)
sets = warmup_ss(self.exercise, D('135'), self.user)
_seteq(sets[0], self.exercise, 45, 5)
_seteq(sets[1], self.exercise, 45, 5)
_seteq(sets[2], self.exercise, 50, 5)
_seteq(sets[3], self.exercise, 80, 3)
_seteq(sets[4], self.exercise, 105, 2)
sets = warmup_ss(self.exercise, D('170'), self.user)
_seteq(sets[0], self.exercise, 45, 5)
_seteq(sets[1], self.exercise, 45, 5)
_seteq(sets[2], self.exercise, 65, 5)
_seteq(sets[3], self.exercise, 100, 3)
_seteq(sets[4], self.exercise, 135, 2)
sets = warmup_ss(self.exercise, D('250'), self.user)
_seteq(sets[0], self.exercise, 45, 5)
_seteq(sets[1], self.exercise, 45, 5)
_seteq(sets[2], self.exercise, 100, 5)
_seteq(sets[3], self.exercise, 150, 3)
_seteq(sets[4], self.exercise, 200, 2)
# slightly crazy jump
sets = warmup_ss(self.exercise, D('315'), self.user)
_seteq(sets[0], self.exercise, 45, 5)
_seteq(sets[1], self.exercise, 45, 5)
_seteq(sets[2], self.exercise, 125, 5)
_seteq(sets[3], self.exercise, 185, 3)
_seteq(sets[4], self.exercise, 250, 2)
# this is probably crazy & should be fixed
sets = warmup_ss(self.exercise, D('500'), self.user)
_seteq(sets[0], self.exercise, 45, 5)
_seteq(sets[1], self.exercise, 45, 5)
_seteq(sets[2], self.exercise, 200, 5)
_seteq(sets[3], self.exercise, 300, 3)
_seteq(sets[4], self.exercise, 400, 2)

View File

@ -0,0 +1,56 @@
from decimal import Decimal as D
from django.shortcuts import render, get_object_or_404
from django.views.decorators.http import require_http_methods, require_GET
from django.contrib.auth.decorators import login_required
from .models import UserSettings, ExerciseRules, Exercise, Plan
from .forms import UserSettingsForm, PlanForm
@require_http_methods(["GET", "POST"])
@login_required
def plan_edit(request, id):
""" edit details of a plan """
plan = get_object_or_404(Plan, pk=id)
exercises = Exercise.objects.all()
if request.method == 'GET':
pform = PlanForm(instance=plan)
return render(request, 'lifting/plan_edit.html',
{'pform': pform, 'plan': plan, 'exercises': exercises})
@require_http_methods(["GET", "POST"])
@login_required
def rules(request):
""" a view that allows a user to view/edit their list of rules """
gr, _ = UserSettings.objects.get_or_create(user=request.user)
ers = list(ExerciseRules.objects.filter(user=request.user))
exercises = Exercise.objects.exclude(id__in=[er.exercise_id for er in ers])
if request.method == 'GET':
grform = UserSettingsForm(instance=gr)
elif request.method == 'POST':
grform = UserSettingsForm(request.POST, instance=gr)
if grform.is_valid():
grform.save()
for exercise, start, inc, work in zip(request.POST.getlist('er.exercise'),
request.POST.getlist('er.start_weight'),
request.POST.getlist('er.increment'),
request.POST.getlist('er.work_weight')):
exercise = int(exercise)
start = D(start)
inc = D(inc)
work = D(work)
er, _ = ExerciseRules.objects.get_or_create(user=request.user,
exercise_id=int(exercise))
er.start_weight = start
er.increment = inc
er.work_weight = work
er.save()
return render(request, 'lifting/rules.html',
{'grform': grform, 'exercise_rules': ers, 'exercises': exercises, })
def er_row(request, eid):
return render(request, 'lifting/_er-row.html',
{'er': ExerciseRules(user=request.user, exercise=Exercise.objects.get(pk=eid))})

View File

@ -0,0 +1,24 @@
<tr>
<input type="hidden" name="er.exercise" value="{{er.exercise.id}}" />
<td class="col-md-3">
{{er.exercise}}
</td>
<td class="col-md-2">
<div class="input-group">
<input type="text" class="form-control" name="er.start_weight" value="{{er.start_weight}}" />
<span class="input-group-addon">lbs</span>
</div>
</td>
<td class="col-md-2">
<div class="input-group">
<input type="text" class="form-control" name="er.increment" value="{{er.increment}}" />
<span class="input-group-addon">lbs</span>
</div>
</td>
<td class="col-md-2">
<div class="input-group">
<input type="text" class="form-control" name="er.work_weight" value="{{er.work_weight}}" />
<span class="input-group-addon">lbs</span>
</div>
</td>
</tr>

View File

@ -0,0 +1,7 @@
<div class="form-group {% if field.errors %}has-error{% endif %}">
<label class="col-md-2 control-label" for="{{field.id_for_label}}">{{field.label}}: </label>
<div class="col-md-{{size}}{% if units %}input-group{% endif %}">
<input type="text" class="form-control" id="{{field.id_for_label}}" name="{{field.html_name}}" value="{{field.value}}" />
{% if units %}<span class="input-group-addon">{{units}}</span>{% endif %}
</div>
</div>

View File

@ -0,0 +1,34 @@
{% extends "lifting/base.html" %}
{% load lifting %}
{% block content %}
<input type="text" name="plan.name">
<div class="row">
{% for day in plan.days.all %}
<div class="col-md-4">
<input type="day.name">
{{day.name}}
<table class="table">
<thead>
<th>Exercise</th><th>Sets</th><th>Percent</th>
</thead>
<tbody>
{% for e in day.exercises.all %}
<tr>
<td>{{e.exercise}}</td>
<td>{{e.get_set_display}}</td>
<td>{{e.get_percent_display}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endfor %}
</div>
{% endblock %}
{% block script %}
<script>
</script>
{% endblock %}

View File

@ -0,0 +1,33 @@
{% extends "lifting/base.html" %}
{% load lifting %}
{% block content %}
<h2>{{plan}}</h2>
<div class="row">
{% for day in plan.days.all %}
<div class="col-md-4">
<h4>{{day.name}}</h4>
<table class="table">
<thead>
<th>Exercise</th><th>Sets</th><th>Percent</th>
</thead>
<tbody>
{% for e in day.exercises.all %}
<tr>
<td>{{e.exercise}}</td>
<td>{{e.get_set_display}}</td>
<td>{{e.get_percent_display}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endfor %}
</div>
{% endblock %}
{% block script %}
<script>
</script>
{% endblock %}

View File

@ -0,0 +1,54 @@
{% extends "lifting/base.html" %}
{% load lifting %}
{% block content %}
<form class="form-horizontal" method="POST">
{{pform.name|formfield:"3"}}
{{pform.tags|formfield:"5"}}
<hr>
<div class="row">
{% for day in plan.days.all %}
<div class="col-md-6">
<div class="form-group">
<label class="col-md-2 control-label" for="day.name">Day: </label>
<div class="col-md-9">
<input type="text" class="form-control" id="day.name" name="day.name" value="{{day.name}}" />
</div>
</div>
</div>
<div class="col-md-6">
<table class="table">
<thead>
<th>Exercise</th><th>Sets</th><th>Percent</th>
</thead>
<tbody>
{% for e in day.exercises.all %}
<tr>
<td>
<select id="new-exercise" class="form-control">
{% for exercise in exercises %}
<option value="{{exercise.id}}" {% if e.exercise_id == exercise.id %}selected{% endif %}>{{exercise}}</option>
{% endfor %}
</select>
</td>
<td>{{e.get_set_display}}</td>
<td>{{e.get_percent_display}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endfor %}
</div>
</form>
{% endblock %}
{% block script %}
<script>
</script>
{% endblock %}

View File

@ -0,0 +1,36 @@
{% extends "lifting/base.html" %}
{% load lifting %}
{% block content %}
<table class="table">
<thead>
<tr>
<th>Plan</th>
<th>Tags</th>
<th>Popularity</th>
<th>&nbsp;</th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody id="exercise-rules">
{% for plan in plans %}
<tr>
<td><a href="{{plan.get_absolute_url}}">{{plan}}</a></td>
<td>
{% for tag in plan.tags.all %}
<span style="background-color: #{{tag.color}};" class="label">{{tag.name}}</span>
{% endfor %}
</td>
<td>{{plan.popularity}}</td>
<td>clone</td>
<td>use plan</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock content %}
{% block script %}
<script>
</script>
{% endblock %}

View File

@ -0,0 +1,56 @@
{% extends "lifting/base.html" %}
{% load lifting %}
{% block content %}
<form class="form-horizontal" method="POST">
{% csrf_token %}
<h3>Global Settings</h3>
{{grform.bar|formfield:"2,lbs"}}
{{grform.plates|formfield:"3,lbs"}}
<hr>
<h3>Exercise Settings</h3>
<table class="table">
<thead>
<tr>
<th>Exercise</th>
<th>Start Weight</th>
<th>Increment</th>
<th>Working Weight</th>
</tr>
</thead>
<tbody id="exercise-rules">
{% for er in exercise_rules %}
{% include "lifting/_er-row.html" %}
{% endfor %}
</tbody>
</table>
<hr>
<div class="form-group">
<div class="col-md-2">
<button id="add-exercise" type="button" class="btn">Add Exercise: </button>
</div>
<div class="col-md-5">
<select id="new-exercise" class="form-control">
{% for exercise in exercises %}
<option value="{{exercise.id}}">{{exercise}}</option>
{% endfor %}
</select>
</div>
</div>
<button type="submit" class="btn btn-primary">Save Settings</button>
</form>
{% endblock content %}
{% block script %}
<script>
$(function() {
$('#add-exercise').click(function() {
var val = $('#new-exercise').val();
$.get('/_er-row/' + val + '/', function(data) {
$('#exercise-rules').append(data);
$('#new-exercise > option[value=' + val + ']').remove();
});
});
});
</script>
{% endblock %}

View File

@ -1,7 +1,11 @@
{% extends "base.html" %}
{% load lifting %}
{% block content %}
<form method="post">
{% csrf_token %}
<div class="row">
<div class="col-sm-6">
<section class="panel panel-default">
@ -37,22 +41,21 @@
<label class="col-sm-4 control-label">Lifting Units:</label>
<div class="col-sm-8">
<div class="radio">
<input type="radio" name="lifting_unit" value="i">lbs</input>
<input type="radio" name="lifting_units" value="i" {% if lifting_options.lifting_units == "i" %}checked{% endif %} >lb</input>
</div>
<div class="radio">
<input type="radio" name="lifting_unit" value="m">kg</input>
<input type="radio" name="lifting_units" value="m" {% if lifting_options.lifting_units == "m" %}checked{% endif %}>kg</input>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">Barbell:</label>
<div class="col-sm-8">
{% for bar in bars %}
<div class="radio">
<input type="radio" name="barbell" value="1">Men's Olympic (44lbs / 20kg) </input>
</div>
<div class="radio">
<input type="radio" name="barbell" value="2">Women's Olympic (33lbs / 15kg) </input>
<input type="radio" name="barbell" value="{{bar.id}}" {% if lifting_options.default_bar_id == bar.id %}checked{% endif %}>{{bar}}</input>
</div>
{% endfor %}
</div>
</div>
<div class="form-group">
@ -63,37 +66,28 @@
<tr><td>Weight</td><td># of Pairs</td></tr>
</thead>
<tbody>
{% for weight, n in plates %}
<tr>
<td><input type="text" class="form-control" name="plate_weight" value="45"></input></td>
<td><input type="text" class="form-control" name="plate_number" value="2"></input></td>
<td><input type="text" class="form-control" name="plate_weight" value="{{weight|decimal}}"></input></td>
<td><input type="text" class="form-control" name="plate_number" value="{{n}}"></input></td>
</tr>
{% endfor %}
<tr>
<td><input type="text" class="form-control" name="plate_weight" value="25"></input></td>
<td><input type="text" class="form-control" name="plate_number" value="1"></input></td>
</tr>
<tr>
<td><input type="text" class="form-control" name="plate_weight" value="10"></input></td>
<td><input type="text" class="form-control" name="plate_number" value="1"></input></td>
</tr>
<tr>
<td><input type="text" class="form-control" name="plate_weight" value="5"></input></td>
<td><input type="text" class="form-control" name="plate_number" value="2"></input></td>
</tr>
<tr>
<td><input type="text" class="form-control" name="plate_weight" value="2.5"></input></td>
<td><input type="text" class="form-control" name="plate_number" value="1"></input></td>
</tr>
<tr>
<td><input type="text" class="form-control" name="plate_weight" value="1.25"></input></td>
<td><input type="text" class="form-control" name="plate_number" value="1"></input></td>
<td><input type="text" class="form-control" name="plate_weight" value=""></input></td>
<td><input type="text" class="form-control" name="plate_number" value=""></input></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="form-group">
<div class="col-sm-12"><input type="submit" class="form-control" value="Save Changes"></input> </div>
</div>
</div>
</div>
</section>
</div>
</div>
</form>
{% endblock %}