a few more tests and removing old code
This commit is contained in:
@@ -312,12 +312,6 @@ def mapcolors(x):
|
||||
except KeyError:
|
||||
return mytypes.colors[-1]
|
||||
|
||||
def maptypes(x):
|
||||
try:
|
||||
return mytypes.workouttypes_ordered[x]
|
||||
except KeyError:
|
||||
return 'Other'
|
||||
|
||||
def interactive_workouttype_piechart(workouts):
|
||||
if len(workouts) == 0:
|
||||
return "","Not enough workouts to make a chart"
|
||||
@@ -2092,171 +2086,6 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
|
||||
|
||||
|
||||
|
||||
def fitnessmetric_chart(fitnessmetrics,user,workoutmode='rower',startdate=None,
|
||||
enddate=None):
|
||||
|
||||
power4min = [int(m.PowerFourMin) for m in fitnessmetrics]
|
||||
power2k = [int(m.PowerTwoK) for m in fitnessmetrics]
|
||||
power1hr = [int(m.PowerOneHour) for m in fitnessmetrics]
|
||||
dates = [m.date for m in fitnessmetrics]
|
||||
|
||||
|
||||
mode = [m.workoutmode for m in fitnessmetrics]
|
||||
|
||||
if len(power4min) == 0:
|
||||
return ['','']
|
||||
|
||||
df = pd.DataFrame(
|
||||
{'power4min':power4min,
|
||||
'power2k':power2k,
|
||||
'power1hr':power1hr,
|
||||
'date':dates,
|
||||
'dates':dates,
|
||||
'mode':mode
|
||||
})
|
||||
|
||||
|
||||
delta = df['power4min'].astype('int').diff()
|
||||
|
||||
mask = delta == 0
|
||||
|
||||
df.loc[mask,'power4min'] = np.nan
|
||||
df.dropna(inplace=True,axis=0,how='any')
|
||||
|
||||
|
||||
df = df[df['power2k']>0]
|
||||
try:
|
||||
df = df[df['mode']==workoutmode]
|
||||
except TypeError:
|
||||
df = pd.DataFrame()
|
||||
|
||||
if df.empty:
|
||||
return ["","no data"]
|
||||
|
||||
groups = df.groupby(by='date').max()
|
||||
|
||||
power4min = groups['power4min']
|
||||
date = groups['dates']
|
||||
power2k = groups['power2k']
|
||||
power1hr = groups['power1hr']
|
||||
|
||||
source = ColumnDataSource(
|
||||
data = dict(
|
||||
power4min = power4min,
|
||||
power2k = power2k,
|
||||
date = date,
|
||||
power1hr = power1hr,
|
||||
fdate=groups['dates'].map(lambda x: x.strftime('%Y-%m-%d'))
|
||||
)
|
||||
)
|
||||
|
||||
# fit
|
||||
|
||||
resampled = groups.set_index('dates')
|
||||
resampled.index = pd.to_datetime(resampled.index)
|
||||
resampled = resampled.resample('D').interpolate(
|
||||
method='linear',order=2)
|
||||
|
||||
power4min = resampled['power4min']
|
||||
date = resampled.index.values
|
||||
power2k = resampled['power2k']
|
||||
power1hr = resampled['power1hr']
|
||||
|
||||
source2 = ColumnDataSource(
|
||||
data = dict(
|
||||
power4min = power4min,
|
||||
power2k = power2k,
|
||||
date = date,
|
||||
power1hr = power1hr,
|
||||
fdate=resampled.index.map(lambda x: x.strftime('%d-%m-%Y')) )
|
||||
)
|
||||
|
||||
|
||||
|
||||
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
||||
|
||||
plot = Figure(tools=TOOLS,toolbar_location="above",
|
||||
toolbar_sticky=False,width=900,
|
||||
x_axis_type='datetime')
|
||||
|
||||
# add watermark
|
||||
watermarkurl = "/static/img/logo7.png"
|
||||
watermarksource = ColumnDataSource(dict(
|
||||
url = [watermarkurl],))
|
||||
|
||||
watermarkrange = Range1d(start=0,end=1)
|
||||
watermarkalpha = 0.6
|
||||
watermarkx = 0.99
|
||||
watermarky = 0.01
|
||||
watermarkw = 184
|
||||
watermarkh = 35
|
||||
watermarkanchor = 'bottom_right'
|
||||
plot.extra_y_ranges = {"watermark": watermarkrange}
|
||||
plot.extra_x_ranges = {"watermark": watermarkrange}
|
||||
|
||||
plot.image_url([watermarkurl],watermarkx,watermarky,
|
||||
watermarkw,watermarkh,
|
||||
global_alpha=watermarkalpha,
|
||||
w_units='screen',
|
||||
h_units='screen',
|
||||
anchor=watermarkanchor,
|
||||
dilate=True,
|
||||
x_range_name = "watermark",
|
||||
y_range_name = "watermark",
|
||||
)
|
||||
|
||||
plot.circle('date','power2k',source=source,fill_color='red',size=10,
|
||||
legend_label='2k power')
|
||||
|
||||
|
||||
plot.circle('date','power1hr',source=source,fill_color='blue',size=10,
|
||||
legend_label='1 hr power')
|
||||
|
||||
plot.circle('date','power4min',source=source,fill_color='green',size=10,
|
||||
legend_label='4 min power')
|
||||
|
||||
plot.line('date','power4min',source=source2,color='green')
|
||||
plot.line('date','power2k',source=source2,color='red')
|
||||
plot.line('date','power1hr',source=source2,color='blue')
|
||||
|
||||
plot.xaxis.axis_label = 'Date'
|
||||
plot.yaxis.axis_label = 'Power (W)'
|
||||
|
||||
plot.xaxis.formatter = DatetimeTickFormatter(
|
||||
days=["%d %B %Y"],
|
||||
months=["%d %B %Y"],
|
||||
years=["%d %B %Y"],
|
||||
)
|
||||
|
||||
plot.xaxis.major_label_orientation = pi/4
|
||||
plot.sizing_mode = 'stretch_both'
|
||||
|
||||
plot.y_range = Range1d(0,1.5*max(power4min))
|
||||
startdate = datetime.datetime.combine(startdate,datetime.datetime.min.time())
|
||||
enddate = datetime.datetime.combine(enddate,datetime.datetime.min.time())
|
||||
if not startdate:
|
||||
startdate = datetime.datetime.combine(min(date), datetime.datetime.min.time())
|
||||
|
||||
if not enddate:
|
||||
enddate = datetime.datetime.combine(max(date), datetime.datetime.min.time())
|
||||
|
||||
plot.x_range = Range1d(
|
||||
startdate,enddate,
|
||||
)
|
||||
plot.title.text = 'Power levels ('+workoutmode+') from workouts '+user.first_name
|
||||
|
||||
hover = plot.select(dict(type=HoverTool))
|
||||
|
||||
hover.tooltips = OrderedDict([
|
||||
('Power 4 minutes','@power4min'),
|
||||
('Power 2000 m','@power2k'),
|
||||
('Power 1 hour','@power1hr'),
|
||||
('Date','@fdate'),
|
||||
])
|
||||
|
||||
script,div = components(plot)
|
||||
|
||||
return [script,div]
|
||||
|
||||
def interactive_histoall(theworkouts,histoparam,includereststrokes,
|
||||
spmmin=0,spmmax=55,
|
||||
@@ -6678,255 +6507,6 @@ def interactive_multiple_compare_chart(ids,xparam,yparam,plottype='line',
|
||||
|
||||
|
||||
|
||||
def interactive_comparison_chart(id1=0,id2=0,xparam='distance',yparam='spm',
|
||||
promember=0,plottype='line'):
|
||||
|
||||
|
||||
|
||||
|
||||
columns = [xparam,yparam,
|
||||
'ftime','distance','fpace',
|
||||
'power','hr','spm',
|
||||
'time','pace','workoutstate']
|
||||
|
||||
# check if valid ID exists (workout exists)
|
||||
#rowdata1,row1 = dataprep.getrowdata_db(id=id1)
|
||||
#rowdata2,row2 = dataprep.getrowdata_db(id=id2)
|
||||
|
||||
rowdata1 = dataprep.getsmallrowdata_db(columns,ids=[id1])
|
||||
rowdata2 = dataprep.getsmallrowdata_db(columns,ids=[id2])
|
||||
for n in ['distance','power','hr','spm','time','pace','workoutstate']:
|
||||
try:
|
||||
rowdata1[n].fillna(value=0,inplace=True)
|
||||
except KeyError:
|
||||
pass
|
||||
try:
|
||||
rowdata2[n].fillna(value=0,inplace=True)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
rowdata1.dropna(axis=1,how='all',inplace=True)
|
||||
rowdata1.dropna(axis=0,how='any',inplace=True)
|
||||
rowdata2.dropna(axis=1,how='all',inplace=True)
|
||||
rowdata2.dropna(axis=0,how='any',inplace=True)
|
||||
|
||||
row1 = Workout.objects.get(id=id1)
|
||||
row2 = Workout.objects.get(id=id2)
|
||||
|
||||
if rowdata1.empty:
|
||||
return "","No Valid Data Available"
|
||||
# else:
|
||||
# rowdata1.sort_values(by='time',ascending=True,inplace=True)
|
||||
|
||||
if rowdata2.empty:
|
||||
return "","No Valid Data Available"
|
||||
# else:
|
||||
# rowdata2.sort_values(by='time',ascending=True,inplace=True)
|
||||
|
||||
try:
|
||||
x1 = rowdata1.loc[:,xparam]
|
||||
x2 = rowdata2.loc[:,xparam]
|
||||
|
||||
y1 = rowdata1.loc[:,yparam]
|
||||
y2 = rowdata2.loc[:,yparam]
|
||||
except KeyError:
|
||||
return "","No valid Data Available"
|
||||
|
||||
x_axis_type = 'linear'
|
||||
y_axis_type = 'linear'
|
||||
if xparam == 'time':
|
||||
x_axis_type = 'datetime'
|
||||
|
||||
if yparam == 'pace':
|
||||
y_axis_type = 'datetime'
|
||||
ymax = 1.0e3*90
|
||||
ymin = 1.0e3*180
|
||||
|
||||
if row1.workouttype == 'water':
|
||||
ymax = 1.0e3*90
|
||||
ymin = 1.0e3*210
|
||||
|
||||
ftime1 = rowdata1.loc[:,'ftime']
|
||||
ftime2 = rowdata2.loc[:,'ftime']
|
||||
|
||||
hr1 = rowdata1.loc[:,'hr']
|
||||
hr2 = rowdata2.loc[:,'hr']
|
||||
|
||||
|
||||
fpace1 = rowdata1.loc[:,'fpace']
|
||||
fpace2 = rowdata2.loc[:,'fpace']
|
||||
|
||||
distance1 = rowdata1.loc[:,'distance']
|
||||
distance2 = rowdata2.loc[:,'distance']
|
||||
|
||||
spm1 = rowdata1.loc[:,'spm']
|
||||
spm2 = rowdata2.loc[:,'spm']
|
||||
|
||||
if (promember==1):
|
||||
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
||||
else:
|
||||
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
||||
|
||||
|
||||
data1 = pd.DataFrame(
|
||||
dict(
|
||||
x1=x1,
|
||||
y1=y1,
|
||||
ftime1=ftime1,
|
||||
fpace1=fpace1,
|
||||
hr1 = hr1,
|
||||
spm1 = spm1,
|
||||
distance1=distance1,
|
||||
)
|
||||
).dropna()
|
||||
|
||||
data2 = pd.DataFrame(
|
||||
dict(
|
||||
x2=x2,
|
||||
y2=y2,
|
||||
ftime2=ftime2,
|
||||
fpace2=fpace2,
|
||||
hr2 = hr2,
|
||||
spm2 = spm2,
|
||||
distance2=distance2,
|
||||
)
|
||||
).dropna()
|
||||
|
||||
|
||||
|
||||
source1 = ColumnDataSource(
|
||||
data1
|
||||
)
|
||||
|
||||
source2 = ColumnDataSource(
|
||||
data2
|
||||
)
|
||||
|
||||
ymean1 = data1['y1'].mean()
|
||||
ymean2 = data2['y2'].mean()
|
||||
|
||||
# create interactive plot
|
||||
plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type,
|
||||
tools=TOOLS,
|
||||
plot_width=920,
|
||||
toolbar_sticky=False)
|
||||
|
||||
# add watermark
|
||||
watermarkurl = "/static/img/logo7.png"
|
||||
watermarksource = ColumnDataSource(dict(
|
||||
url = [watermarkurl],))
|
||||
|
||||
watermarkrange = Range1d(start=0,end=1)
|
||||
watermarkalpha = 0.6
|
||||
watermarkx = 0.99
|
||||
watermarky = 0.01
|
||||
watermarkw = 184
|
||||
watermarkh = 35
|
||||
watermarkanchor = 'bottom_right'
|
||||
plot.extra_y_ranges = {"watermark": watermarkrange}
|
||||
plot.extra_x_ranges = {"watermark": watermarkrange}
|
||||
plot.sizing_mode = 'stretch_both'
|
||||
|
||||
plot.image_url([watermarkurl],0.05,watermarky,
|
||||
watermarkw,watermarkh,
|
||||
global_alpha=watermarkalpha,
|
||||
w_units='screen',
|
||||
h_units='screen',
|
||||
anchor='bottom_left',
|
||||
dilate=True,
|
||||
x_range_name = "watermark",
|
||||
y_range_name = "watermark",
|
||||
)
|
||||
|
||||
TIPS = OrderedDict([
|
||||
('time','@ftime1'),
|
||||
('pace','@fpace1'),
|
||||
('hr','@hr1'),
|
||||
('spm','@spm1{1.1}'),
|
||||
('distance','@distance1{5}'),
|
||||
])
|
||||
TIPS2 = OrderedDict([
|
||||
('time','@ftime2'),
|
||||
('pace','@fpace2'),
|
||||
('hr','@hr2'),
|
||||
('spm','@spm2{1.1}'),
|
||||
('distance','@distance2{5}'),
|
||||
])
|
||||
|
||||
|
||||
|
||||
hover1 = plot.select(type=HoverTool)
|
||||
hover1.tooltips = TIPS
|
||||
hover2 = plot.select(type=HoverTool)
|
||||
hover2.tooltips = TIPS2
|
||||
|
||||
|
||||
if plottype=='line':
|
||||
l1 = plot.line('x1','y1',source=source1,
|
||||
color="blue",legend_label=row1.name,
|
||||
)
|
||||
l2 = plot.line('x2','y2',source=source2,
|
||||
color="red",legend_label=row2.name,
|
||||
)
|
||||
elif plottype=='scatter':
|
||||
l1 = plot.scatter('x1','y1',source=source1,legend_label=row1.name,
|
||||
fill_alpha=0.4,
|
||||
line_color=None)
|
||||
l2 = plot.scatter('x2','y2',source=source2,legend_label=row2.name,
|
||||
fill_alpha=0.4,
|
||||
line_color=None,color="red")
|
||||
|
||||
plot.add_tools(HoverTool(renderers=[l1],tooltips=TIPS))
|
||||
plot.add_tools(HoverTool(renderers=[l2],tooltips=TIPS2))
|
||||
plot.legend.location = "bottom_right"
|
||||
|
||||
plot.title.text = row1.name+' vs '+row2.name
|
||||
plot.title.text_font_size=value("1.2em")
|
||||
plot.xaxis.axis_label = axlabels[xparam]
|
||||
plot.yaxis.axis_label = axlabels[yparam]
|
||||
|
||||
ylabel1 = Label(x=100,y=90,x_units='screen',y_units='screen',
|
||||
text=axlabels[yparam]+": {ymean1:6.2f}".format(
|
||||
ymean1=ymean1
|
||||
),
|
||||
background_fill_alpha=.7,
|
||||
background_fill_color='white',
|
||||
text_color='blue'
|
||||
)
|
||||
ylabel2 = Label(x=100,y=110,x_units='screen',y_units='screen',
|
||||
text=axlabels[yparam]+": {ymean2:6.2f}".format(
|
||||
ymean2=ymean2
|
||||
),
|
||||
background_fill_alpha=.7,
|
||||
background_fill_color='white',
|
||||
text_color='red'
|
||||
)
|
||||
plot.add_layout(ylabel1)
|
||||
plot.add_layout(ylabel2)
|
||||
|
||||
if xparam == 'time':
|
||||
plot.xaxis[0].formatter = DatetimeTickFormatter(
|
||||
hours = ["%H"],
|
||||
minutes = ["%M"],
|
||||
seconds = ["%S"],
|
||||
days = ["0"],
|
||||
months = [""],
|
||||
years = [""]
|
||||
)
|
||||
|
||||
|
||||
if yparam == 'pace':
|
||||
plot.yaxis[0].formatter = DatetimeTickFormatter(
|
||||
seconds = ["%S"],
|
||||
minutes = ["%M"]
|
||||
)
|
||||
|
||||
plot.y_range = Range1d(ymin,ymax)
|
||||
|
||||
|
||||
script, div = components(plot)
|
||||
|
||||
return [script,div]
|
||||
|
||||
def interactive_otw_advanced_pace_chart(id=0,promember=0):
|
||||
# check if valid ID exists (workout exists)
|
||||
|
||||
@@ -1000,9 +1000,28 @@ class GoldMedalScores(TestCase):
|
||||
|
||||
self.c = Client()
|
||||
self.user_workouts = WorkoutFactory.create_batch(20, user=self.r)
|
||||
ws = Workout.objects.all().order_by('date')
|
||||
ws[0].rankingpiece = True
|
||||
ws[0].save()
|
||||
result = get_random_file(filename='rowers/tests/testdata/onwater2.csv')
|
||||
self.w1 = WorkoutFactory(user=self.r,
|
||||
csvfilename=result['filename'],
|
||||
starttime=result['starttime'],
|
||||
startdatetime=result['startdatetime'],
|
||||
duration=result['duration'],
|
||||
distance=result['totaldist'],
|
||||
workouttype = 'water',
|
||||
rankingpiece=True
|
||||
)
|
||||
|
||||
result = get_random_file(filename='rowers/tests/testdata/onwater2.csv')
|
||||
self.w2 = WorkoutFactory(user=self.r,
|
||||
csvfilename=result['filename'],
|
||||
starttime=result['starttime'],
|
||||
startdatetime=result['startdatetime'],
|
||||
duration=result['duration'],
|
||||
distance=result['totaldist'],
|
||||
workouttype = 'water',
|
||||
rankingpiece=True
|
||||
)
|
||||
|
||||
self.factory = RequestFactory()
|
||||
self.password = faker.word()
|
||||
self.u.set_password(self.password)
|
||||
@@ -1020,6 +1039,9 @@ class GoldMedalScores(TestCase):
|
||||
def test_workouts_goldmedalscores(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db):
|
||||
|
||||
ws = Workout.objects.filter(rankingpiece=True)
|
||||
self.assertEqual(ws.count(),2)
|
||||
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
|
||||
|
||||
@@ -71,7 +71,10 @@ class InteractivePlotTests(TestCase):
|
||||
self.assertFalse(len(script)==0)
|
||||
self.assertFalse(len(div)==0)
|
||||
|
||||
def test_interactive_chart(self):
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db', side_effect=mocked_getsmallrowdata_db)
|
||||
def test_interactive_chart(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db):
|
||||
workout = Workout.objects.filter(user=self.r,workouttype__in=mytypes.rowtypes)[0]
|
||||
id = workout.id
|
||||
|
||||
@@ -99,3 +102,14 @@ class InteractivePlotTests(TestCase):
|
||||
script, div = interactiveplots.interactive_chart_video(data)
|
||||
self.assertFalse(len(script)==0)
|
||||
self.assertFalse(len(div)==0)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db', side_effect=mocked_getsmallrowdata_db)
|
||||
def test_interactive_flexchart_stacked(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db):
|
||||
workout = Workout.objects.filter(user=self.r,workouttype__in=mytypes.rowtypes)[0]
|
||||
id = workout.id
|
||||
|
||||
script, div, js_res, css_res, comment = interactiveplots.interactive_flexchart_stacked(id,self.r)
|
||||
self.assertFalse(len(script)==0)
|
||||
self.assertFalse(len(div)==0)
|
||||
|
||||
@@ -205,9 +205,10 @@ class TestForceUnit(TestCase):
|
||||
average_N = int(row.df[' AverageDriveForce (N)'].mean())
|
||||
self.assertEqual(average_N,398)
|
||||
|
||||
|
||||
df = dataprep.getsmallrowdata_db(['averageforce'],ids=[w[0].id],doclean=False,
|
||||
compute=False)
|
||||
rowdata = dataprep.rdata('rowers/tests/testdata/PainsledForce.csv')
|
||||
df = dataprep.dataprep(rowdata.df)
|
||||
#df = dataprep.getsmallrowdata_db(['averageforce'],ids=[w[0].id],doclean=False,
|
||||
# compute=False)
|
||||
try:
|
||||
average_N = int(df['averageforce'].mean())
|
||||
if average_N != 0:
|
||||
|
||||
@@ -349,9 +349,9 @@ urlpatterns = [
|
||||
re_path(r'^record-progress/$',views.post_progress),
|
||||
re_path(r'^list-graphs/$',views.graphs_view,name='graphs_view'),
|
||||
re_path(r'^list-graphs/user/(?P<userid>\d+)/$',views.graphs_view,name='graphs_view'),
|
||||
re_path(r'^fitness-progress/$',views.fitnessmetric_view,name='fitnessmetric_view'),
|
||||
re_path(r'^fitness-progress/user/(?P<userid>\d+)/$',views.fitnessmetric_view,name='fitnessmetric_view'),
|
||||
re_path(r'^fitness-progress/user/(?P<userid>\d+)/(?P<mode>\w+.*)/$',views.fitnessmetric_view,name='fitnessmetric_view'),
|
||||
#re_path(r'^fitness-progress/$',views.fitnessmetric_view,name='fitnessmetric_view'),
|
||||
#re_path(r'^fitness-progress/user/(?P<userid>\d+)/$',views.fitnessmetric_view,name='fitnessmetric_view'),
|
||||
#re_path(r'^fitness-progress/user/(?P<userid>\d+)/(?P<mode>\w+.*)/$',views.fitnessmetric_view,name='fitnessmetric_view'),
|
||||
re_path(r'^createmarkerworkouts/user/(?P<userid>\d+)/$',views.create_marker_workouts_view,
|
||||
name='create_marker_workouts_view'),
|
||||
re_path(r'^createmarkerworkouts/$',views.create_marker_workouts_view,
|
||||
|
||||
@@ -1484,63 +1484,6 @@ def planrequired_view(request):
|
||||
|
||||
return HttpResponseRedirect(reverse('paidplans_view'))
|
||||
|
||||
@user_passes_test(isplanmember,login_url="/rowers/paidplans",
|
||||
message="This functionality requires a Coach or Self-Coach plan",
|
||||
redirect_field_name=None)
|
||||
@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True)
|
||||
def fitnessmetric_view(request,userid=0,mode='rower',
|
||||
startdate=timezone.now()-timezone.timedelta(days=365),
|
||||
enddate=timezone.now()):
|
||||
|
||||
|
||||
therower = getrequestrower(request,userid=userid)
|
||||
theuser = therower.user
|
||||
|
||||
|
||||
if request.method == 'POST':
|
||||
form = FitnessMetricForm(request.POST)
|
||||
if form.is_valid():
|
||||
startdate = form.cleaned_data['startdate']
|
||||
enddate = form.cleaned_data['enddate']
|
||||
mode = form.cleaned_data['mode']
|
||||
else:
|
||||
form = FitnessMetricForm()
|
||||
|
||||
fitnessmetrics = PowerTimeFitnessMetric.objects.filter(
|
||||
user=theuser,
|
||||
workoutmode=mode,
|
||||
date__gte=startdate,
|
||||
date__lte=enddate)
|
||||
|
||||
|
||||
script,thediv = fitnessmetric_chart(
|
||||
fitnessmetrics,theuser,
|
||||
workoutmode=mode,startdate=startdate,
|
||||
enddate=enddate,
|
||||
)
|
||||
|
||||
breadcrumbs = [
|
||||
{
|
||||
'url':'/rowers/analysis',
|
||||
'name':'Analysis'
|
||||
},
|
||||
{
|
||||
'url':reverse('fitnessmetric_view'),
|
||||
'name': 'Power Progress'
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
return render(request,'fitnessmetric.html',
|
||||
{
|
||||
'rower':therower,
|
||||
'active':'nav-analysis',
|
||||
'chartscript':script,
|
||||
'breadcrumbs':breadcrumbs,
|
||||
'the_div':thediv,
|
||||
'mode':mode,
|
||||
'form':form,
|
||||
})
|
||||
|
||||
@user_passes_test(ispromember, login_url="/rowers/paidplans",
|
||||
message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality",
|
||||
|
||||
Reference in New Issue
Block a user