Private
Public Access
1
0

Merge branch 'develop' into feature/restapi

This commit is contained in:
Sander Roosendaal
2016-11-23 14:58:16 +01:00
21 changed files with 733 additions and 321 deletions

View File

@@ -8,6 +8,7 @@ from pandas import DataFrame,Series
import pandas as pd import pandas as pd
import numpy as np import numpy as np
import itertools
from django.conf import settings from django.conf import settings
from sqlalchemy import create_engine from sqlalchemy import create_engine
@@ -84,9 +85,33 @@ def rdata(file,rower=rrower()):
def getrowdata_db(id=0): def getrowdata_db(id=0):
data = read_df_sql(id) data = read_df_sql(id)
data['pace'] = data['pace']/1.0e6
data['ergpace'] = data['ergpace']/1.0e6
data['nowindpace'] = data['nowindpace']/1.0e6
data['time'] = data['time']/1.0e6
data['x_right'] = data['x_right']/1.0e6
if data.empty: if data.empty:
rowdata,row = getrowdata(id=id) rowdata,row = getrowdata(id=id)
data = dataprep(rowdata.df,id=id,bands=True,barchart=True,otwpower=True) if rowdata:
data = dataprep(rowdata.df,id=id,bands=True,barchart=True,otwpower=True)
else:
data = pd.DataFrame() # returning empty dataframe
else:
row = Workout.objects.get(id=id)
return data,row
def getsmallrowdata_db(xparam,yparam1,yparam2,ids=[]):
if yparam2 == 'None':
yparam2 = yparam1
prepmultipledata(ids)
data = read_cols_df_sql(ids,xparam,yparam1,yparam2)
if xparam == 'time':
data['time'] = data['time']/1.0e6
if yparam1 == 'pace':
data['pace'] = data['pace']/1.0e6
if yparam2 == 'pace':
data['pace'] = data['pace']/1.0e6
return data return data
@@ -110,7 +135,34 @@ def getrowdata(id=0):
return rowdata,row return rowdata,row
# temporary def prepmultipledata(ids):
query = sa.text('SELECT DISTINCT workoutid FROM strokedata')
with engine.connect() as conn, conn.begin():
res = conn.execute(query)
res = list(itertools.chain.from_iterable(res.fetchall()))
res = list(set(ids)-set(res))
for id in res:
rowdata,row = getrowdata(id=id)
if rowdata:
data = dataprep(rowdata.df,id=id,bands=True,barchart=True,otwpower=True)
return res
def read_cols_df_sql(ids,col1,col2,col3):
columns = list(set((col1,col2,col3,'distance','spm')))
cls = ''
for column in columns:
cls += column+', '
cls = cls[:-2]
query = sa.text('SELECT {columns} FROM strokedata WHERE workoutid IN {ids}'.format(
columns = cls,
ids = tuple(ids),
))
df = pd.read_sql_query(query,engine)
return df
def read_df_sql(id): def read_df_sql(id):
df = pd.read_sql_query(sa.text('SELECT * FROM strokedata WHERE workoutid={id}'.format( df = pd.read_sql_query(sa.text('SELECT * FROM strokedata WHERE workoutid={id}'.format(
id=id)), engine) id=id)), engine)
@@ -118,6 +170,37 @@ def read_df_sql(id):
def smalldataprep(therows,xparam,yparam1,yparam2):
df = pd.DataFrame()
if yparam2 == 'None':
yparam2 = 'power'
df[xparam] = []
df[yparam1] = []
df[yparam2] = []
df['distance'] = []
df['spm'] = []
for workout in therows:
f1 = workout.csvfilename
try:
rowdata = dataprep(rrdata(f1).df)
rowdata = pd.DataFrame({xparam: rowdata[xparam],
yparam1: rowdata[yparam1],
yparam2: rowdata[yparam2],
'distance': rowdata['distance'],
'spm': rowdata['spm'],
}
)
df = pd.concat([df,rowdata],ignore_index=True)
except IOError:
pass
return df
def dataprep(rowdatadf,id=0,bands=False,barchart=False,otwpower=False): def dataprep(rowdatadf,id=0,bands=False,barchart=False,otwpower=False):
rowdatadf.set_index([range(len(rowdatadf))],inplace=True) rowdatadf.set_index([range(len(rowdatadf))],inplace=True)
t = rowdatadf.ix[:,'TimeStamp (sec)'] t = rowdatadf.ix[:,'TimeStamp (sec)']
@@ -134,8 +217,11 @@ def dataprep(rowdatadf,id=0,bands=False,barchart=False,otwpower=False):
power = rowdatadf.ix[:,' Power (watts)'] power = rowdatadf.ix[:,' Power (watts)']
averageforce = rowdatadf.ix[:,' AverageDriveForce (lbs)'] averageforce = rowdatadf.ix[:,' AverageDriveForce (lbs)']
drivelength = rowdatadf.ix[:,' DriveLength (meters)'] drivelength = rowdatadf.ix[:,' DriveLength (meters)']
try:
workoutstate = rowdatadf.ix[:,' WorkoutState']
except KeyError:
workoutstate = 0*hr
peakforce = rowdatadf.ix[:,' PeakDriveForce (lbs)'] peakforce = rowdatadf.ix[:,' PeakDriveForce (lbs)']
forceratio = averageforce/peakforce forceratio = averageforce/peakforce
@@ -152,7 +238,10 @@ def dataprep(rowdatadf,id=0,bands=False,barchart=False,otwpower=False):
drivelength = savgol_filter(drivelength,windowsize,3) drivelength = savgol_filter(drivelength,windowsize,3)
forceratio = savgol_filter(forceratio,windowsize,3) forceratio = savgol_filter(forceratio,windowsize,3)
t2 = t.fillna(method='ffill').apply(lambda x: timedeltaconv(x)) try:
t2 = t.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
except TypeError:
t2 = 0*t
p2 = p.fillna(method='ffill').apply(lambda x: timedeltaconv(x)) p2 = p.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
@@ -179,6 +268,7 @@ def dataprep(rowdatadf,id=0,bands=False,barchart=False,otwpower=False):
fpace = nicepaceformat(p2), fpace = nicepaceformat(p2),
driveenergy=driveenergy, driveenergy=driveenergy,
power=power, power=power,
workoutstate=workoutstate,
averageforce=averageforce, averageforce=averageforce,
drivelength=drivelength, drivelength=drivelength,
peakforce=peakforce, peakforce=peakforce,

View File

@@ -5,9 +5,11 @@ from rowingdata import cumcpdata,histodata
from rowingdata import rowingdata as rrdata from rowingdata import rowingdata as rrdata
from django.utils import timezone
from bokeh.plotting import figure, ColumnDataSource, Figure,curdoc from bokeh.plotting import figure, ColumnDataSource, Figure,curdoc
from bokeh.models import CustomJS,Slider from bokeh.models import CustomJS,Slider
from bokeh.charts import Histogram from bokeh.charts import Histogram,HeatMap
from bokeh.resources import CDN,INLINE from bokeh.resources import CDN,INLINE
from bokeh.embed import components from bokeh.embed import components
from bokeh.layouts import layout,widgetbox from bokeh.layouts import layout,widgetbox
@@ -68,14 +70,13 @@ from rowers.dataprep import timedeltaconv
def interactive_histoall(theworkouts): def interactive_histoall(theworkouts):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
therows = [] ids = [w.id for w in theworkouts]
for workout in theworkouts: rowdata = dataprep.getsmallrowdata_db('power','power','power',ids=ids)
f1 = workout.csvfilename
rowdata = rdata(f1) histopwr = rowdata['power'].values
if rowdata != 0: if len(histopwr) == 0:
therows.append(rowdata) return "","CSV file not found","",""
histopwr = histodata(therows)
# throw out nans # throw out nans
histopwr = histopwr[~np.isinf(histopwr)] histopwr = histopwr[~np.isinf(histopwr)]
histopwr = histopwr[histopwr > 25] histopwr = histopwr[histopwr > 25]
@@ -494,18 +495,15 @@ def interactive_chart(id=0,promember=0):
else: else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
rowdata,row = dataprep.getrowdata(id=id)
if rowdata == 0: datadf,row = dataprep.getrowdata_db(id=id)
if datadf.empty:
return "","CSV Data File Not Found" return "","CSV Data File Not Found"
datadf = dataprep.dataprep(rowdata.df)
source = ColumnDataSource( source = ColumnDataSource(
datadf datadf
) )
plot = Figure(x_axis_type="datetime",y_axis_type="datetime", plot = Figure(x_axis_type="datetime",y_axis_type="datetime",
plot_width=400, plot_width=400,
plot_height=400, plot_height=400,
@@ -552,10 +550,10 @@ def interactive_chart(id=0,promember=0):
hover.mode = 'mouse' hover.mode = 'mouse'
plot.extra_y_ranges = {"hr": Range1d(start=100,end=200)} plot.extra_y_ranges = {"hrax": Range1d(start=100,end=200)}
plot.line('time','hr',source=source,color="red", plot.line('time','hr',source=source,color="red",
y_range_name="hr", legend="Heart Rate") y_range_name="hrax", legend="Heart Rate")
plot.add_layout(LinearAxis(y_range_name="hr",axis_label="HR"),'right') plot.add_layout(LinearAxis(y_range_name="hrax",axis_label="HR"),'right')
plot.legend.location = "bottom_right" plot.legend.location = "bottom_right"
@@ -563,23 +561,15 @@ def interactive_chart(id=0,promember=0):
return [script,div] return [script,div]
def interactive_cum_flex_chart(theworkouts,promember=0, def interactive_cum_flex_chart2(theworkouts,promember=0,
xparam='spm', xparam='spm',
yparam1='power', yparam1='power',
yparam2='hr', yparam2='spm'):
):
therows = []
for workout in theworkouts:
f1 = workout.csvfilename
rowdata = rdata(f1)
if rowdata != 0:
therows.append(rowdata.df)
datadf = pd.concat(therows)
# datadf = dataprep.smalldataprep(theworkouts,xparam,yparam1,yparam2)
ids = [w.id for w in theworkouts]
datadf = dataprep.getsmallrowdata_db(xparam,yparam1,yparam2,ids=ids)
axlabels = { axlabels = {
'time': 'Time', 'time': 'Time',
'distance': 'Distance (m)', 'distance': 'Distance (m)',
@@ -626,21 +616,11 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
} }
datadf = dataprep.dataprep(datadf)
if yparam1 != 'pace' and yparam1 != 'time': datadf = datadf[datadf[yparam1] > 0]
datadf = datadf[datadf[yparam1] > 0]
elif yparam1 == 'time':
datadf = datadf[datadf['timesecs'] > 0]
else:
datadf = datadf[datadf['pseconds']>0]
if xparam != 'time' and xparam != 'pace':
datadf = datadf[datadf[xparam] > 0] datadf = datadf[datadf[xparam] > 0]
elif xparam == 'time':
datadf = datadf[datadf['timesecs']>0]
else:
datadf = datadf[datadf['pseconds']>0]
if yparam2 != 'None': if yparam2 != 'None':
datadf = datadf[datadf[yparam2] > 0] datadf = datadf[datadf[yparam2] > 0]
@@ -651,9 +631,7 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
datadf['x1'] = datadf.ix[:,xparam] datadf['x1'] = datadf.ix[:,xparam]
tseconds = datadf.ix[:,'timesecs']
datadf['y1'] = datadf.ix[:,yparam1] datadf['y1'] = datadf.ix[:,yparam1]
if yparam2 != 'None': if yparam2 != 'None':
datadf['y2'] = datadf.ix[:,yparam2] datadf['y2'] = datadf.ix[:,yparam2]
@@ -661,12 +639,7 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
datadf['y2'] = datadf['y1'] datadf['y2'] = datadf['y1']
if xparam=='time': if xparam=='distance':
xaxmax = tseconds.max()
xaxmin = tseconds.min()
xaxmax = 1.0e3*xaxmax
xaxmin = 1.0e3*xaxmin
elif xparam=='distance':
xaxmax = datadf['x1'].max() xaxmax = datadf['x1'].max()
xaxmin = datadf['x1'].min() xaxmin = datadf['x1'].min()
else: else:
@@ -674,27 +647,16 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
xaxmin = yaxminima[xparam] xaxmin = yaxminima[xparam]
# average values # average values
if xparam != 'time': x1mean = datadf['x1'].mean()
x1mean = datadf['x1'].mean()
else:
x1mean = 0
y1mean = datadf['y1'].mean() y1mean = datadf['y1'].mean()
y2mean = datadf['y2'].mean() y2mean = datadf['y2'].mean()
if xparam != 'time':
xvals = pd.Series(xaxmin+np.arange(100)*(xaxmax-xaxmin)/100.) xvals = pd.Series(xaxmin+np.arange(100)*(xaxmax-xaxmin)/100.)
else:
xvals = pd.Series(np.arange(100))
x_axis_type = 'linear' x_axis_type = 'linear'
y_axis_type = 'linear' y_axis_type = 'linear'
if xparam == 'time':
x_axis_type = 'datetime'
if yparam1 == 'pace':
y_axis_type = 'datetime'
y1mean = datadf.ix[:,'pseconds'].mean()
datadf['xname'] = xparam datadf['xname'] = xparam
datadf['yname1'] = yparam1 datadf['yname1'] = yparam1
@@ -703,6 +665,7 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
else: else:
datadf['yname2'] = yparam1 datadf['yname2'] = yparam1
source = ColumnDataSource( source = ColumnDataSource(
datadf datadf
) )
@@ -713,9 +676,9 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
# Add hover to this comma-separated string and see what changes # Add hover to this comma-separated string and see what changes
if (promember==1): if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair'
else: else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'
plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type, plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type,
tools=TOOLS, tools=TOOLS,
@@ -735,9 +698,9 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
text_color='green', text_color='green',
) )
if (xparam != 'time') and (xparam != 'distance'):
plot.add_layout(x1means) plot.add_layout(x1means)
plot.add_layout(xlabel) plot.add_layout(xlabel)
plot.add_layout(y1means) plot.add_layout(y1means)
@@ -746,8 +709,8 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
background_fill_alpha=.7, background_fill_alpha=.7,
text_color='blue', text_color='blue',
) )
if yparam1 != 'time' and yparam1 != 'pace':
plot.add_layout(y1label) plot.add_layout(y1label)
y2label = y1label y2label = y1label
plot.circle('x1','y1',source=source2,fill_alpha=0.3,line_color=None, plot.circle('x1','y1',source=source2,fill_alpha=0.3,line_color=None,
@@ -761,29 +724,9 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
yrange1 = Range1d(start=yaxminima[yparam1],end=yaxmaxima[yparam1]) yrange1 = Range1d(start=yaxminima[yparam1],end=yaxmaxima[yparam1])
plot.y_range = yrange1 plot.y_range = yrange1
if (xparam != 'time') and (xparam != 'distance'): xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam])
xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam]) plot.x_range = xrange1
plot.x_range = xrange1
if xparam == 'time':
xrange1 = Range1d(start=xaxmin,end=xaxmax)
plot.x_range = xrange1
plot.xaxis[0].formatter = DatetimeTickFormatter(
hours = ["%H"],
minutes = ["%M"],
seconds = ["%S"],
days = ["0"],
months = [""],
years = [""]
)
if yparam1 == 'pace':
plot.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
if yparam2 != 'None': if yparam2 != 'None':
yrange2 = Range1d(start=yaxminima[yparam2],end=yaxmaxima[yparam2]) yrange2 = Range1d(start=yaxminima[yparam2],end=yaxmaxima[yparam2])
@@ -809,18 +752,6 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
if yparam2 != 'pace' and yparam2 != 'time': if yparam2 != 'pace' and yparam2 != 'time':
plot.add_layout(y2label) plot.add_layout(y2label)
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Time','@ftime'),
('Pace','@fpace'),
('HR','@hr{int}'),
('SPM','@spm{1.1}'),
('Power','@power{int}'),
])
hover.mode = 'mouse'
callback = CustomJS(args = dict(source=source,source2=source2, callback = CustomJS(args = dict(source=source,source2=source2,
x1means=x1means, x1means=x1means,
@@ -835,11 +766,7 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
var y1 = data['y1'] var y1 = data['y1']
var y2 = data['y2'] var y2 = data['y2']
var spm1 = data['spm'] var spm1 = data['spm']
var time1 = data['time']
var pace1 = data['pace']
var hr1 = data['hr']
var distance1 = data['distance'] var distance1 = data['distance']
var power1 = data['power']
var xname = data['xname'][0] var xname = data['xname'][0]
var yname1 = data['yname1'][0] var yname1 = data['yname1'][0]
var yname2 = data['yname2'][0] var yname2 = data['yname2'][0]
@@ -856,11 +783,7 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
data2['y1'] = [] data2['y1'] = []
data2['y2'] = [] data2['y2'] = []
data2['spm'] = [] data2['spm'] = []
data2['time'] = []
data2['pace'] = []
data2['hr'] = []
data2['distance'] = [] data2['distance'] = []
data2['power'] = []
data2['x1mean'] = [] data2['x1mean'] = []
data2['y1mean'] = [] data2['y1mean'] = []
data2['y2mean'] = [] data2['y2mean'] = []
@@ -875,11 +798,7 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
data2['y1'].push(y1[i]) data2['y1'].push(y1[i])
data2['y2'].push(y2[i]) data2['y2'].push(y2[i])
data2['spm'].push(spm1[i]) data2['spm'].push(spm1[i])
data2['time'].push(time1[i])
data2['pace'].push(pace1[i])
data2['hr'].push(hr1[i])
data2['distance'].push(distance1[i]) data2['distance'].push(distance1[i])
data2['power'].push(power1[i])
xm += x1[i] xm += x1[i]
ym1 += y1[i] ym1 += y1[i]
@@ -944,6 +863,7 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
def interactive_flex_chart2(id=0,promember=0, def interactive_flex_chart2(id=0,promember=0,
xparam='time', xparam='time',
yparam1='pace', yparam1='pace',
@@ -994,8 +914,8 @@ def interactive_flex_chart2(id=0,promember=0,
'drivespeed':4, 'drivespeed':4,
} }
rowdata,row = dataprep.getrowdata(id=id) rowdata,row = dataprep.getrowdata_db(id=id)
if rowdata == 0: if rowdata.empty:
return "","CSV Data File Not Found" return "","CSV Data File Not Found"
workoutstateswork = [1,4,5,8,9,6,7] workoutstateswork = [1,4,5,8,9,6,7]
@@ -1004,16 +924,10 @@ def interactive_flex_chart2(id=0,promember=0,
if workstrokesonly: if workstrokesonly:
try: try:
rowdata.df = rowdata.df[~rowdata.df[' WorkoutState'].isin(workoutstatesrest)] rowdata = rowdata[~rowdata['workoutstate'].isin(workoutstatesrest)]
except KeyError: except KeyError:
pass pass
rowdata = dataprep.dataprep(rowdata.df)
# get user
# u = User.objects.get(id=row.user.id)
rowdata['x1'] = rowdata.ix[:,xparam] rowdata['x1'] = rowdata.ix[:,xparam]
rowdata['y1'] = rowdata.ix[:,yparam1] rowdata['y1'] = rowdata.ix[:,yparam1]
@@ -1336,15 +1250,10 @@ def interactive_flex_chart2(id=0,promember=0,
def interactive_bar_chart(id=0,promember=0): def interactive_bar_chart(id=0,promember=0):
# check if valid ID exists (workout exists) # check if valid ID exists (workout exists)
rowdata,row = dataprep.getrowdata(id=id) rowdata,row = dataprep.getrowdata_db(id=id)
if rowdata == 0: if rowdata.empty:
return "","CSV Data File Not Found" return "","CSV Data File Not Found"
rowdata = dataprep.dataprep(rowdata.df,bands=True,barchart=True)
# Add hover to this comma-separated string and see what changes # Add hover to this comma-separated string and see what changes
if (promember==1): if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
@@ -1355,8 +1264,6 @@ def interactive_bar_chart(id=0,promember=0):
rowdata rowdata
) )
plot = Figure(x_axis_type="datetime",y_axis_type="datetime", plot = Figure(x_axis_type="datetime",y_axis_type="datetime",
toolbar_sticky=False, toolbar_sticky=False,
plot_width=920, plot_width=920,
@@ -1453,19 +1360,14 @@ def interactive_comparison_chart(id1=0,id2=0,xparam='distance',yparam='spm',
# check if valid ID exists (workout exists) # check if valid ID exists (workout exists)
rowdata1,row1 = dataprep.getrowdata(id=id1) rowdata1,row1 = dataprep.getrowdata_db(id=id1)
rowdata2,row2 = dataprep.getrowdata(id=id2) rowdata2,row2 = dataprep.getrowdata_db(id=id2)
if rowdata1 == 0: if rowdata1.empty:
return "","CSV Data File Not Found" return "","CSV Data File Not Found"
if rowdata2 == 0: if rowdata2.empty:
return "","CSV Data File Not Found" return "","CSV Data File Not Found"
rowdata1 = dataprep.dataprep(rowdata1.df)
rowdata2 = dataprep.dataprep(rowdata2.df)
x1 = rowdata1.ix[:,xparam] x1 = rowdata1.ix[:,xparam]
x2 = rowdata2.ix[:,xparam] x2 = rowdata2.ix[:,xparam]
@@ -1601,12 +1503,10 @@ def interactive_comparison_chart(id1=0,id2=0,xparam='distance',yparam='spm',
def interactive_otw_advanced_pace_chart(id=0,promember=0): def interactive_otw_advanced_pace_chart(id=0,promember=0):
# check if valid ID exists (workout exists) # check if valid ID exists (workout exists)
rowdata,row = dataprep.getrowdata(id=id) rowdata,row = dataprep.getrowdata_db(id=id)
if rowdata == 0: if rowdata.empty:
return "","CSV Data File Not Found" return "","CSV Data File Not Found"
rowdata = dataprep.dataprep(rowdata.df,otwpower=True)
# Add hover to this comma-separated string and see what changes # Add hover to this comma-separated string and see what changes
if (promember==1): if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'

View File

@@ -9,8 +9,31 @@ from django.forms.widgets import SplitDateTimeWidget
from datetimewidget.widgets import DateTimeWidget from datetimewidget.widgets import DateTimeWidget
import os import os
# Create your models here. from django.conf import settings
from sqlalchemy import create_engine
import sqlalchemy as sa
from sqlite3 import OperationalError
user = settings.DATABASES['default']['USER']
password = settings.DATABASES['default']['PASSWORD']
database_name = settings.DATABASES['default']['NAME']
host = settings.DATABASES['default']['HOST']
port = settings.DATABASES['default']['PORT']
database_url = 'mysql://{user}:{password}@{host}:{port}/{database_name}'.format(
user=user,
password=password,
database_name=database_name,
host=host,
port=port,
)
if settings.DEBUG:
database_url = 'sqlite:///db.sqlite3'
engine = create_engine(database_url, echo=False)
# Create your models here.
class Team(models.Model): class Team(models.Model):
name = models.CharField(max_length=150) name = models.CharField(max_length=150)
notes = models.CharField(blank=True,max_length=200) notes = models.CharField(blank=True,max_length=200)
@@ -120,6 +143,17 @@ def auto_delete_file_on_delete(sender, instance, **kwargs):
if os.path.isfile(instance.csvfilename): if os.path.isfile(instance.csvfilename):
os.remove(instance.csvfilename) os.remove(instance.csvfilename)
@receiver(models.signals.post_delete,sender=Workout)
def auto_delete_strokedata_on_delete(sender, instance, **kwargs):
if instance.id:
query = sa.text('DELETE FROM strokedata WHERE workoutid={id};'.format(
id=instance.id,
))
with engine.connect() as conn, conn.begin():
try:
result = conn.execute(query)
except:
print "Database Locked"
class StrokeData(models.Model): class StrokeData(models.Model):
class Meta: class Meta:
@@ -130,6 +164,7 @@ class StrokeData(models.Model):
timesecs = models.FloatField(null=True) timesecs = models.FloatField(null=True)
hr = models.IntegerField(null=True) hr = models.IntegerField(null=True)
pace = models.TimeField(null=True) pace = models.TimeField(null=True)
workoutstate = models.IntegerField(null=True,default=1)
pseconds = models.FloatField(null=True) pseconds = models.FloatField(null=True)
spm = models.FloatField(null=True) spm = models.FloatField(null=True)
cumdist = models.FloatField(null=True) cumdist = models.FloatField(null=True)

View File

@@ -7,115 +7,132 @@
{% block content %} {% block content %}
<div id="workouts" class="grid_6 alpha"> <div id="workouts" class="grid_6 alpha">
{% if form.errors %} {% if form.errors %}
<p style="color: red;"> <p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below. Please correct the error{{ form.errors|pluralize }} below.
</p> </p>
{% endif %} {% endif %}
<h1>Advanced Workout Editor</h1> <h1>Advanced Workout Editor</h1>
{% if user.rower.rowerplan == 'basic' %} {% if user.rower.rowerplan == 'basic' %}
<p>This is a preview of the page with advanced functionality for Pro users. See <a href="/rowers/promembership">the page about Pro membership</a> for more information and to sign up for Pro Membership</a> <p>This is a preview of the page with advanced functionality for Pro users.
{% endif %} See
<div class="grid_2 alpha"> <a href="/rowers/promembership">the page about Pro membership</a> for more information and to sign up for Pro Membership</a>
<p> {% endif %}
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/edit">Edit Workout</a> <div class="grid_2 alpha">
</p> <p>
</div> <a class="button gray small" href="/rowers/workout/{{ workout.id }}/edit">Edit Workout</a>
<div class="grid_2 suffix_2 omega"> </p>
<p> </div>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/export">Export</a> <div class="grid_2 suffix_2 omega">
</p> <p>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/export">Export</a>
</p>
</div> </div>
<div class="grid_6 alpha"> <div class="grid_6 alpha">
<table width=100%> <table width=100%>
<tr> <tr>
<th>Date:</th><td>{{ workout.date }}</td> <th>Date:</th><td>{{ workout.date }}</td>
</tr><tr> </tr><tr>
<th>Time:</th><td>{{ workout.starttime }}</td> <th>Time:</th><td>{{ workout.starttime }}</td>
</tr><tr> </tr><tr>
<th>Distance:</th><td>{{ workout.distance }}m</td> <th>Distance:</th><td>{{ workout.distance }}m</td>
</tr><tr> </tr><tr>
<th>Duration:</th><td>{{ workout.duration |durationprint:"%H:%M:%S.%f" }}</td> <th>Duration:</th><td>{{ workout.duration |durationprint:"%H:%M:%S.%f" }}</td>
</tr> </tr>
<th>Public link to this workout</th> <th>Public link to this workout</th>
<td> <td>
<a href="/rowers/workout/{{ workout.id }}">http://rowsandall.com/rowers/workout/{{ workout.id }}</a> <a href="/rowers/workout/{{ workout.id }}">https://rowsandall.com/rowers/workout/{{ workout.id }}</a>
<td> <td>
</table> </table>
</div> </div>
<div class="grid_6 alpha"> <div class="grid_6 alpha">
<div class="grid_2 alpha"> <div class="grid_2 alpha">
{% if user.rower.rowerplan == 'pro' %} {% if user.rower.rowerplan == 'pro' %}
<a class="button blue small" href="/rowers/workout/compare/{{ workout.id }}">Compare Workouts</a> <a class="button blue small" href="/rowers/workout/compare/{{ workout.id }}">Compare Workouts</a>
{% else %} {% else %}
<a class="button blue small" href="/rowers/promembership/">Compare Workouts</a> <a class="button blue small" href="/rowers/promembership/">Compare Workouts</a>
{% endif %} {% endif %}
<p> <p>
Compare this workout to other workouts. Plot HR, SPM, or pace vs time or distance for the two workouts. Compare this workout to other workouts. Plot HR, SPM, or pace vs time or distance for the two workouts.
</p> </p>
</div> </div>
<div class="grid_2"> <div class="grid_2">
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/flexchart"> <a class="button blue small" href="/rowers/workout/{{ workout.id }}/flexchart">
Flexible Interactive Plot Flexible Interactive Plot
</a> </a>
<p> <p>
Flexible Interactive plot. Pick your own X and Y axis parameters. Flexible Interactive plot. Pick your own X and Y axis parameters.
</p> </p>
</div> </div>
<div class="grid_2 omega tooltip"> <div class="grid_2 omega tooltip">
<p> <p>
{% if user.rower.rowerplan == 'pro' %} {% if user.rower.rowerplan == 'pro' %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/editintervals">Edit Intervals</a> <a class="button blue small" href="/rowers/workout/{{ workout.id }}/editintervals">Edit Intervals</a>
{% else %} {% else %}
<a class="button blue small" href="/rowers/promembership">Edit Intervals</a> <a class="button blue small" href="/rowers/promembership">Edit Intervals</a>
{% endif %} {% endif %}
</p> </p>
<span class="tooltiptext">Enter or change the interval and summary data for your workout</span> <span class="tooltiptext">Enter or change the interval and summary data for your workout</span>
<p> <p>
Enter or change the interval and summary data for your workout Enter or change the interval and summary data for your workout
</p> </p>
</div> </div>
</div> </div>
<div class="grid_6 alpha"> <div class="grid_6 alpha">
<div class="grid_2 alpha"> <div class="grid_2 alpha">
<p> <p>
{% if user.rower.rowerplan == 'pro' %} {% if user.rower.rowerplan == 'pro' %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/adddistanceplot2">Dist Metrics Plot</a> <a class="button blue small" href="/rowers/workout/{{ workout.id }}/adddistanceplot2">Dist Metrics Plot</a>
{% else %} {% else %}
<a class="button blue small" href="/rowers/promembership">Dist Metrics Plot</a> <a class="button blue small" href="/rowers/promembership">Dist Metrics Plot</a>
{% endif %} {% endif %}
</p> </p>
<p> <p>
Various advanced stroke metrics plotted versus distance. Various advanced stroke metrics plotted versus distance.
</p> </p>
</div> </div>
<div class="grid_2"> <div class="grid_2">
<p> <p>
{% if user.rower.rowerplan == 'pro' %} {% if user.rower.rowerplan == 'pro' %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/addtimeplot2">Time Metrics Plot</a> <a class="button blue small" href="/rowers/workout/{{ workout.id }}/addtimeplot2">Time Metrics Plot</a>
{% else %} {% else %}
<a class="button blue small" href="/rowers/promembership">Time Metrics Plot</a> <a class="button blue small" href="/rowers/promembership">Time Metrics Plot</a>
{% endif %} {% endif %}
</p> </p>
<p> <p>
Various advanced stroke metrics plotted versus time. Various advanced stroke metrics plotted versus time.
</p> </p>
</div> </div>
<div class="grid_2 omega"> <div class="grid_2 omega">
<p> <p>
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/interactiveplot">Big Interactive Plot</a> <a class="button blue small" href="/rowers/workout/{{ workout.id }}/interactiveplot">Big Interactive Plot</a>
</p> </p>
<p> <p>
See (and save) the big interactive plot See (and save) the big interactive plot
</p> </p>
</div> </div>
</div>
<div class="grid_6 alpha">
<div class="grid_2 suffix_4 alpha">
<p>
{% if user.rower.rowerplan == 'pro' %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/histo">Power Histogram</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Dist Metrics Plot</a>
{% endif %}
</p>
<p>
Plot the Power Histogram of this workout
</p>
</div>
</div> </div>
</div> </div>
@@ -155,4 +172,4 @@ Enter or change the interval and summary data for your workout
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@@ -42,7 +42,7 @@
</tr> </tr>
<th>Public link to this workout</th> <th>Public link to this workout</th>
<td> <td>
<a href="/rowers/workout/{{ workout.id }}">http://rowsandall.com/rowers/workout/{{ workout.id }}</a> <a href="/rowers/workout/{{ workout.id }}">https://rowsandall.com/rowers/workout/{{ workout.id }}</a>
<td> <td>
</table> </table>
</div> </div>

View File

@@ -6,8 +6,7 @@
{% block content %} {% block content %}
<div id="workouts" class="grid_4 alpha"> <div id="workouts" class="grid_4 alpha">
<div class="grid_4 alpha">
<h1>Workout {{ id }}</h1> <h1>Workout {{ id }}</h1>
<table width=100%> <table width=100%>
<tr> <tr>
@@ -30,6 +29,35 @@
<th>Weight Category:</th><td>{{ workout.weightcategory }}</td> <th>Weight Category:</th><td>{{ workout.weightcategory }}</td>
</tr> </tr>
</table> </table>
</div>
<div class="grid_4 alpha">
<p>
<form id="searchform" action=""
method="get" accept-charset="utf-8">
<button class="button blue small" type="submit">
Search
</button>
<input class="searchfield" id="searchbox" name="q" type="text" placeholder="Search">
</form>
</p>
</div>
Select start and end date for a date range:
<div class="grid_4 alpha">
<p>
<form enctype="multipart/form-data" action="/rowers/workout/compare/{{ id }}/" method="post">
<table>
{{ dateform.as_table }}
</table>
{% csrf_token %}
</div>
<div class="grid_2 suffix_2 omega">
<input name='daterange' class="button green" type="submit" value="Submit"> </form>
</p>
</div>
</div> </div>
<div id="comparison" class="grid_8 omega"> <div id="comparison" class="grid_8 omega">
@@ -73,5 +101,21 @@
{% else %} {% else %}
<p> No workouts found </p> <p> No workouts found </p>
{% endif %} {% endif %}
<div class="grid_2 prefix_5 suffix_1 omega">
<span class="button gray small">
{% if workouts.has_previous %}
<a class="wh" href="/rowers/workout/compare/{{ id }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}?page={{ workouts.previous_page_number }}">&lt;</a>
{% endif %}
<span>
Page {{ workouts.number }} of {{ workouts.paginator.num_pages }}.
</span>
{% if workouts.has_next %}
<a class="wh" href="/rowers/workout/compare/{{ id }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}?page={{ workouts.next_page_number }}">&gt;</a>
{% endif %}
</span>
</div>
</div> </div>
{% endblock %} {% endblock %}

View File

@@ -39,18 +39,16 @@
<div class="grid_2 alpha dropdown"> <div class="grid_2 alpha dropdown">
<button class="grid_2 alpha button blue small dropbtn">X-axis</button> <button class="grid_2 alpha button blue small dropbtn">X-axis</button>
<div class="dropdown-content"> <div class="dropdown-content">
<a class="button blue small alpha" href="/rowers/flexall/time/{{ yparam1 }}/{{ yparam2 }}">Time</a>
<a class="button blue small alpha" href="/rowers/flexall/distance/{{ yparam1 }}/{{ yparam2 }}">Distance</a>
{% if promember %} {% if promember %}
<a class="button blue small alpha" href="/rowers/flexall/power/{{ yparam1 }}/{{ yparam2 }}">Power</a> <a class="button blue small alpha" href="/rowers/flexall/power/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Power</a>
<a class="button blue small alpha" href="/rowers/flexall/hr/{{ yparam1 }}/{{ yparam2 }}">HR</a> <a class="button blue small alpha" href="/rowers/flexall/hr/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">HR</a>
<a class="button blue small alpha" href="/rowers/flexall/spm/{{ yparam1 }}/{{ yparam2 }}">SPM</a> <a class="button blue small alpha" href="/rowers/flexall/spm/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">SPM</a>
<a class="button blue small alpha" href="/rowers/flexall/peakforce/{{ yparam1 }}/{{ yparam2 }}">Peak Force</a> <a class="button blue small alpha" href="/rowers/flexall/peakforce/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Peak Force</a>
<a class="button blue small alpha" href="/rowers/flexall/averageforce/{{ yparam1 }}/{{ yparam2 }}">Average Force</a> <a class="button blue small alpha" href="/rowers/flexall/averageforce/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Average Force</a>
<a class="button blue small alpha" href="/rowers/flexall/forceratio/{{ yparam1 }}/{{ yparam2 }}">Average/Peak Force Ratio</a> <a class="button blue small alpha" href="/rowers/flexall/forceratio/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Average/Peak Force Ratio</a>
<a class="button blue small alpha" href="/rowers/flexall/drivelength/{{ yparam1 }}/{{ yparam2 }}">Drive Length</a> <a class="button blue small alpha" href="/rowers/flexall/drivelength/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Drive Length</a>
<a class="button blue small alpha" href="/rowers/flexall/driveenergy/{{ yparam1 }}/{{ yparam2 }}">Work per Stroke</a> <a class="button blue small alpha" href="/rowers/flexall/driveenergy/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Work per Stroke</a>
<a class="button blue small alpha" href="/rowers/flexall/drivespeed/{{ yparam1 }}/{{ yparam2 }}">Drive Speed</a> <a class="button blue small alpha" href="/rowers/flexall/drivespeed/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Drive Speed</a>
{% else %} {% else %}
<a class="button rosy small" href="/rowers/promembership">Power (Pro)</a> <a class="button rosy small" href="/rowers/promembership">Power (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">HR (Pro)</a> <a class="button rosy small" href="/rowers/promembership">HR (Pro)</a>
@@ -69,17 +67,16 @@
<div class="grid_2 dropdown"> <div class="grid_2 dropdown">
<button class="grid_2 alpha button blue small dropbtn">Left</button> <button class="grid_2 alpha button blue small dropbtn">Left</button>
<div class="dropdown-content"> <div class="dropdown-content">
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/pace/{{ yparam2 }}">Pace</a> <a class="button blue small" href="/rowers/flexall/{{ xparam }}/hr/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">HR</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/hr/{{ yparam2 }}">HR</a> <a class="button blue small" href="/rowers/flexall/{{ xparam }}/spm/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">SPM</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/spm/{{ yparam2 }}">SPM</a> <a class="button blue small" href="/rowers/flexall/{{ xparam }}/power/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Power</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/power/{{ yparam2 }}">Power</a>
{% if promember %} {% if promember %}
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/peakforce/{{ yparam2 }}">Peak Force</a> <a class="button blue small" href="/rowers/flexall/{{ xparam }}/peakforce/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Peak Force</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/averageforce/{{ yparam2 }}">Average Force</a> <a class="button blue small" href="/rowers/flexall/{{ xparam }}/averageforce/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Average Force</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/forceratio/{{ yparam2 }}">Average/Peak Force Ratio</a> <a class="button blue small" href="/rowers/flexall/{{ xparam }}/forceratio/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Average/Peak Force Ratio</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/drivelength/{{ yparam2 }}">Drive Length</a> <a class="button blue small" href="/rowers/flexall/{{ xparam }}/drivelength/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Drive Length</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/driveenergy/{{ yparam2 }}">Work per Stroke</a> <a class="button blue small" href="/rowers/flexall/{{ xparam }}/driveenergy/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Work per Stroke</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/drivespeed/{{ yparam2 }}">Drive Speed</a> <a class="button blue small" href="/rowers/flexall/{{ xparam }}/drivespeed/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Drive Speed</a>
{% else %} {% else %}
<a class="button rosy small" href="/rowers/promembership">Peak Force (Pro)</a> <a class="button rosy small" href="/rowers/promembership">Peak Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Average Force (Pro)</a> <a class="button rosy small" href="/rowers/promembership">Average Force (Pro)</a>
@@ -95,16 +92,16 @@
<div class="grid_2 dropdown omega"> <div class="grid_2 dropdown omega">
<button class="grid_2 alpha button blue small dropbtn">Right</button> <button class="grid_2 alpha button blue small dropbtn">Right</button>
<div class="dropdown-content"> <div class="dropdown-content">
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/hr">HR</a> <a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/hr/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">HR</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/spm">SPM</a> <a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/spm/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">SPM</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/power">Power</a> <a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/power/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Power</a>
{% if promember %} {% if promember %}
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/peakforce">Peak Force</a> <a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/peakforce/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Peak Force</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/averageforce">Average Force</a> <a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/averageforce/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Average Force</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/forceratio">Average/Peak Force Ratio</a> <a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/forceratio/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Average/Peak Force Ratio</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/drivelength">Drive Length</a> <a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/drivelength/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Drive Length</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/driveenergy">Work per Stroke</a> <a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/driveenergy/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Work per Stroke</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/drivespeed">Drive Speed</a> <a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/drivespeed/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Drive Speed</a>
{% else %} {% else %}
<a class="button rosy small" href="/rowers/promembership">Peak Force (Pro)</a> <a class="button rosy small" href="/rowers/promembership">Peak Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Average Force (Pro)</a> <a class="button rosy small" href="/rowers/promembership">Average Force (Pro)</a>
@@ -114,7 +111,7 @@
<a class="button rosy small" href="/rowers/promembership">Drive Speed (Pro)</a> <a class="button rosy small" href="/rowers/promembership">Drive Speed (Pro)</a>
{% endif %} {% endif %}
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/None">None</a> <a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/None/{{startdate|date:"Y-m-d"}}/{{ enddate|date:"Y-m-d"}}">None</a>
</div> </div>
</div> </div>

View File

@@ -46,7 +46,7 @@
between {{ startdate|date }} and {{ enddate|date }}</p> between {{ startdate|date }} and {{ enddate|date }}</p>
<p>Direct link for other Pro users: <p>Direct link for other Pro users:
<a href="/rowers/{{ id }}/histo/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}">http://rowsandall.com/rowers/{{ id }}/histo/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}</a> <a href="/rowers/{{ id }}/histo/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}">https://rowsandall.com/rowers/{{ id }}/histo/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}</a>
</p> </p>
</div> </div>
<div id="form" class="grid_6 omega"> <div id="form" class="grid_6 omega">
@@ -82,4 +82,4 @@
</div> </div>
{% endblock %} {% endblock %}

View File

@@ -0,0 +1,66 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}View Workout {% endblock %}
{% block content %}
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ interactiveplot |safe }}
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, false, false);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="navigation" class="grid_12 alpha">
{% if user.is_authenticated and mayedit %}
<div class="grid_2 alpha">
<p>
<a class="button gray small" href="/rowers/workout/{{ id }}/edit">Edit Workout</a>
</p>
</div>
<div class="grid_2 suffix_8 omega">
<p>
<a class="button gray small" href="/rowers/workout/{{ id }}/advanced">Advanced Edit</a>
</p>
</div>
{% endif %}
</div>
<div id="title" class="grid_12 alpha">
<h1>Indoor Rower Power Histogram</h1>
</div>
<div id="graph" class="grid_12 alpha">
{{ the_div|safe }}
</div>
{% endblock %}

View File

@@ -42,7 +42,7 @@
<p>Summary of the past 12 months for {{ theuser.first_name }} {{ theuser.last_name }}</p> <p>Summary of the past 12 months for {{ theuser.first_name }} {{ theuser.last_name }}</p>
<p>Direct link for other Pro users: <p>Direct link for other Pro users:
<a href="/rowers/{{ id }}/histo-all">http://rowsandall.com/rowers/{{ id }}/histo-all</a> <a href="/rowers/{{ id }}/histo-all">https://rowsandall.com/rowers/{{ id }}/histo-all</a>
</p> </p>
<div class="grid_12 alpha"> <div class="grid_12 alpha">

View File

@@ -6,6 +6,14 @@
{% block content %} {% block content %}
<h1>Recent Graphs</h1> <h1>Recent Graphs</h1>
<form id="searchform" action="."
method="get" accept-charset="utf-8">
<button class="button blue small" type="submit">
Search
</button>
<input class="searchfield" id="searchbox" name="q" type="text" placeholder="Search">
</form>
{% if graphs1 %} {% if graphs1 %}
<div class="grid_1 alpha"> <div class="grid_1 alpha">
<p>&nbsp;</p> <p>&nbsp;</p>

View File

@@ -5,8 +5,27 @@
{% block title %}Workouts{% endblock %} {% block title %}Workouts{% endblock %}
{% block content %} {% block content %}
<div class="grid_12">
Select start and end date for a date range:
<div class="grid_4 alpha">
<form enctype="multipart/form-data" action="/rowers/list-workouts/" method="post">
<table>
{{ dateform.as_table }}
</table>
{% csrf_token %}
</div>
<div class="grid_2 suffix_6 omega">
<input name='daterange' class="button green" type="submit" value="Submit"> </form>
</div>
</div>
<h1>My Workouts</h1> <h1>My Workouts</h1>
{% if workouts %}
{% if workouts %}
<table width="70%" class="listtable"> <table width="70%" class="listtable">
<thead> <thead>
<tr> <tr>
@@ -49,4 +68,35 @@
{% else %} {% else %}
<p> No workouts found </p> <p> No workouts found </p>
{% endif %} {% endif %}
</div>
<div class="grid_6 alpha">
<form id="searchform" action="/rowers/list-workouts/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}"
method="get" accept-charset="utf-8">
<div class="grid_3 prefix_1 alpha">
<input class="searchfield" id="searchbox" name="q" type="text" placeholder="Search">
</div>
<div class="grid_1 suffix_1 omega">
<button class="button blue small" type="submit">
Search
</button>
</div>
</form>
</div>
<div class="grid_2 prefix_3 omega">
<span class="button gray small">
{% if workouts.has_previous %}
<a class="wh" href="?page={{ workouts.previous_page_number }}">&lt;</a>
{% endif %}
<span>
Page {{ workouts.number }} of {{ workouts.paginator.num_pages }}.
</span>
{% if workouts.has_next %}
<a class="wh" href="?page={{ workouts.next_page_number }}">&gt;</a>
{% endif %}
</span>
{% endblock %} {% endblock %}

View File

@@ -48,7 +48,7 @@
</tr> </tr>
<th>Public link to this workout</th> <th>Public link to this workout</th>
<td> <td>
<a href="/rowers/workout/{{ workout.id }}">http://rowsandall.com/rowers/workout/{{ workout.id }}</a> <a href="/rowers/workout/{{ workout.id }}">https://rowsandall.com/rowers/workout/{{ workout.id }}</a>
<td> <td>
</table> </table>
</div> </div>

View File

@@ -43,7 +43,7 @@
between {{ startdate|date }} and {{ enddate|date }}</p> between {{ startdate|date }} and {{ enddate|date }}</p>
<p>Direct link for other users: <p>Direct link for other users:
<a href="/rowers/{{ id }}/ote-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}">http://rowsandall.com/rowers/{{ id }}/ote-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}</a> <a href="/rowers/{{ id }}/ote-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}">https://rowsandall.com/rowers/{{ id }}/ote-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}</a>
</p> </p>
<p>The table gives the best efforts achieved on the official Concept2 ranking pieces in the selected date range.</p> <p>The table gives the best efforts achieved on the official Concept2 ranking pieces in the selected date range.</p>

View File

@@ -48,12 +48,12 @@
</tr><tr> </tr><tr>
<th>Public link to this workout</th> <th>Public link to this workout</th>
<td> <td>
<a href="/rowers/workout/{{ workout.id }}">http://rowsandall.com/rowers/workout/{{ workout.id }}</a> <a href="/rowers/workout/{{ workout.id }}">https://rowsandall.com/rowers/workout/{{ workout.id }}</a>
<td> <td>
</tr><tr> </tr><tr>
<th>Public link to interactive chart</th> <th>Public link to interactive chart</th>
<td> <td>
<a href="/rowers/workout/{{ workout.id }}/interactiveplot">http://rowsandall.com/rowers/workout/{{ workout.id }}/interactiveplot</a> <a href="/rowers/workout/{{ workout.id }}/interactiveplot">https://rowsandall.com/rowers/workout/{{ workout.id }}/interactiveplot</a>
<td> <td>
</tr> </tr>
</table> </table>

View File

@@ -48,12 +48,12 @@
</tr><tr> </tr><tr>
<th>Public link to this workout</th> <th>Public link to this workout</th>
<td> <td>
<a href="/rowers/workout/{{ workout.id }}">http://rowsandall.com/rowers/workout/{{ workout.id }}</a> <a href="/rowers/workout/{{ workout.id }}">https://rowsandall.com/rowers/workout/{{ workout.id }}</a>
<td> <td>
</tr><tr> </tr><tr>
<th>Public link to interactive chart</th> <th>Public link to interactive chart</th>
<td> <td>
<a href="/rowers/workout/{{ workout.id }}/interactiveplot">http://rowsandall.com/rowers/workout/{{ workout.id }}/interactiveplot</a> <a href="/rowers/workout/{{ workout.id }}/interactiveplot">https://rowsandall.com/rowers/workout/{{ workout.id }}/interactiveplot</a>
<td> <td>
</tr> </tr>
</table> </table>
@@ -189,6 +189,9 @@
{{ workout.summary }} {{ workout.summary }}
</pre> </pre>
</p> </p>
<div class="grid_2 alpha">
<a class="button green small" href="recalcsummary">Update Summary</a>
</div>
</div> </div>

View File

@@ -139,4 +139,4 @@
</div> </div>
{% endblock %} {% endblock %}

View File

@@ -425,6 +425,9 @@ class ViewTest(TestCase):
response = self.c.get('/rowers/workout/1/interactiveplot', form_data, follow=True) response = self.c.get('/rowers/workout/1/interactiveplot', form_data, follow=True)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
response = self.c.get('/rowers/workout/1/histo', form_data, follow=True)
self.assertEqual(response.status_code, 200)
w = Workout.objects.get(id=1) w = Workout.objects.get(id=1)

View File

@@ -49,6 +49,7 @@ urlpatterns = [
url(r'^list-workouts/c/(?P<message>\w+.*)/$',views.workouts_view), url(r'^list-workouts/c/(?P<message>\w+.*)/$',views.workouts_view),
url(r'^list-workouts/s/(?P<successmessage>\w+.*)/$',views.workouts_view), url(r'^list-workouts/s/(?P<successmessage>\w+.*)/$',views.workouts_view),
url(r'^list-workouts/c/(?P<message>\w+.*)/s/(?P<successmessage>\w+.*)$',views.workouts_view), url(r'^list-workouts/c/(?P<message>\w+.*)/s/(?P<successmessage>\w+.*)$',views.workouts_view),
url(r'^list-workouts/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.workouts_view),
url(r'^list-workouts/$',views.workouts_view), url(r'^list-workouts/$',views.workouts_view),
url(r'^list-graphs/$',views.graphs_view), url(r'^list-graphs/$',views.graphs_view),
url(r'^dashboard/c/(?P<message>\w+.*)/$',views.dashboard_view), url(r'^dashboard/c/(?P<message>\w+.*)/$',views.dashboard_view),
@@ -62,6 +63,7 @@ urlpatterns = [
url(r'^ote-bests/$',views.rankings_view), url(r'^ote-bests/$',views.rankings_view),
url(r'^(?P<theuser>\d+)/ote-bests/$',views.rankings_view), url(r'^(?P<theuser>\d+)/ote-bests/$',views.rankings_view),
url(r'^flexall/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.cum_flex),
url(r'^flexall/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)$',views.cum_flex), url(r'^flexall/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)$',views.cum_flex),
url(r'^flexall/$',views.cum_flex), url(r'^flexall/$',views.cum_flex),
@@ -77,6 +79,7 @@ urlpatterns = [
url(r'^graph/(\d+)/delete$',views.graph_delete_view), url(r'^graph/(\d+)/delete$',views.graph_delete_view),
url(r'^workout/upload/$',views.workout_upload_view), url(r'^workout/upload/$',views.workout_upload_view),
url(r'^workout/upload/(.+.*)$',views.workout_upload_view), url(r'^workout/upload/(.+.*)$',views.workout_upload_view),
url(r'^workout/(?P<id>\d+)/histo$',views.workout_histo_view),
url(r'^workout/(?P<id>\d+)/export/c/(?P<message>\w+.*)/s/(?P<successmessage>\w+.*)$',views.workout_export_view), url(r'^workout/(?P<id>\d+)/export/c/(?P<message>\w+.*)/s/(?P<successmessage>\w+.*)$',views.workout_export_view),
url(r'^workout/(?P<id>\d+)/export/c/(?P<message>\w+.*)$',views.workout_export_view), url(r'^workout/(?P<id>\d+)/export/c/(?P<message>\w+.*)$',views.workout_export_view),
url(r'^workout/(?P<id>\d+)/export/s/(?P<successmessage>\w+.*)$',views.workout_export_view), url(r'^workout/(?P<id>\d+)/export/s/(?P<successmessage>\w+.*)$',views.workout_export_view),
@@ -85,6 +88,7 @@ urlpatterns = [
url(r'^workout/(\d+)/emailcsv$',views.workout_csvemail_view), url(r'^workout/(\d+)/emailcsv$',views.workout_csvemail_view),
url(r'^workout/compare/(\d+)/$',views.workout_comparison_list), url(r'^workout/compare/(\d+)/$',views.workout_comparison_list),
url(r'^workout/compare2/(?P<id1>\d+)/(?P<id2>\d+)/(?P<xparam>\w+.*)/(?P<yparam>\w+.*)/$',views.workout_comparison_view), url(r'^workout/compare2/(?P<id1>\d+)/(?P<id2>\d+)/(?P<xparam>\w+.*)/(?P<yparam>\w+.*)/$',views.workout_comparison_view),
url(r'^workout/compare/(?P<id>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\w+.*)$',views.workout_comparison_list),
url(r'^workout/(?P<id>\d+)/export/c/(?P<message>\w+.*)/s/(?P<successmessage>\w+.*)$',views.workout_edit_view), url(r'^workout/(?P<id>\d+)/export/c/(?P<message>\w+.*)/s/(?P<successmessage>\w+.*)$',views.workout_edit_view),
url(r'^workout/(?P<id>\d+)/edit/c/(?P<message>.+.*)$',views.workout_edit_view), url(r'^workout/(?P<id>\d+)/edit/c/(?P<message>.+.*)$',views.workout_edit_view),
url(r'^workout/(?P<id>\d+)/edit/s/(?P<successmessage>.+.*)$',views.workout_edit_view), url(r'^workout/(?P<id>\d+)/edit/s/(?P<successmessage>.+.*)$',views.workout_edit_view),
@@ -131,6 +135,7 @@ urlpatterns = [
url(r'^workout/(\d+)/c2upload/$',views.list_c2_upload_view), url(r'^workout/(\d+)/c2upload/$',views.list_c2_upload_view),
url(r'^workout/(\d+)/c2uploadw/$',views.workout_c2_upload_view), url(r'^workout/(\d+)/c2uploadw/$',views.workout_c2_upload_view),
url(r'^workout/(\d+)/stravauploadw/$',views.workout_strava_upload_view), url(r'^workout/(\d+)/stravauploadw/$',views.workout_strava_upload_view),
url(r'^workout/(\d+)/recalcsummary/$',views.workout_recalcsummary_view),
url(r'^workout/(\d+)/sporttracksuploadw/$',views.workout_sporttracks_upload_view), url(r'^workout/(\d+)/sporttracksuploadw/$',views.workout_sporttracks_upload_view),
url(r'^me/edit/$',views.rower_edit_view), url(r'^me/edit/$',views.rower_edit_view),
url(r'^me/edit/(.+.*)/$',views.rower_edit_view), url(r'^me/edit/(.+.*)/$',views.rower_edit_view),

View File

@@ -1,11 +1,14 @@
import time import time
import operator
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from django.db.models import Q
from django.shortcuts import render from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect from django.http import HttpResponse, HttpResponseRedirect
from django.contrib.auth import authenticate, login, logout from django.contrib.auth import authenticate, login, logout
from rowers.forms import LoginForm,DocumentsForm,UploadOptionsForm from rowers.forms import LoginForm,DocumentsForm,UploadOptionsForm
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.template import RequestContext from django.template import RequestContext
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.conf import settings from django.conf import settings
from django.utils.datastructures import MultiValueDictKeyError from django.utils.datastructures import MultiValueDictKeyError
from django.utils import timezone,translation from django.utils import timezone,translation
@@ -1322,9 +1325,10 @@ def cum_flex(request,theuser=0,
u = '' u = ''
if allergworkouts: if allergworkouts:
res = interactive_cum_flex_chart(allergworkouts,xparam=xparam, res = interactive_cum_flex_chart2(allergworkouts,xparam=xparam,
yparam1=yparam1,yparam2=yparam2, yparam1=yparam1,
promember=promember) yparam2=yparam2,
promember=promember)
script = res[0] script = res[0]
div = res[1] div = res[1]
js_resources = res[2] js_resources = res[2]
@@ -1352,6 +1356,36 @@ def cum_flex(request,theuser=0,
'promember':promember, 'promember':promember,
}) })
@login_required()
def workout_histo_view(request,id=0):
row = Workout.objects.get(id=id)
promember=0
mayedit=0
if not request.user.is_anonymous():
r = Rower.objects.get(user=request.user)
result = request.user.is_authenticated() and r.rowerplan=='pro'
if result:
promember=1
if request.user == row.user.user:
mayedit=1
if not promember:
return HttpResponseRedirect("/rowers/about/")
res = interactive_histoall([row])
script = res[0]
div = res[1]
return render(request,
'histo_single.html',
{'interactiveplot':script,
'the_div':div,
'id':id,
'mayedit':mayedit,
})
@login_required() @login_required()
def histo(request,theuser=0, def histo(request,theuser=0,
@@ -1582,8 +1616,8 @@ def rankings_view(request,theuser=0,
for rankingduration in rankingdurations: for rankingduration in rankingdurations:
workouts = Workout.objects.filter(user=r,duration=rankingduration, workouts = Workout.objects.filter(user=r,duration=rankingduration,
workouttype='rower', workouttype='rower',
startdatetime__gte=startdate, startdatetime__gte=startdate,
startdatetime__lte=enddate).order_by('-distance') startdatetime__lte=enddate).order_by('-distance')
if workouts: if workouts:
thedistances.append(workouts[0].distance) thedistances.append(workouts[0].distance)
@@ -1754,29 +1788,156 @@ def rankings_view(request,theuser=0,
}) })
@login_required() @login_required()
def workouts_view(request,message='',successmessage=''): def workout_recalcsummary_view(request,id=0):
row = Workout.objects.get(id=id)
if (checkworkoutuser(request.user,row)==False):
message = "You are not allowed to edit this workout"
url = reverse(workouts_view,args=[str(message)])
return HttpResponseRedirect(url)
filename = row.csvfilename
rowdata = rdata(filename)
row.summary = rowdata.allstats()
row.save()
successmessage = "Summary Updated"
url = reverse(workout_edit_view,
kwargs = {
'id':str(id),
'successmessage':str(successmessage),
})
return HttpResponseRedirect(url)
@login_required()
def workouts_view(request,message='',successmessage='',
startdatestring="",enddatestring="",
startdate=timezone.now()-datetime.timedelta(days=365),
enddate=timezone.now()):
try: try:
r = Rower.objects.get(user=request.user) r = Rower.objects.get(user=request.user)
# res = mailprocessing.safeprocessattachments() # res = mailprocessing.safeprocessattachments()
#if len(res)>0 and np.cumsum(np.array(res)).max()>0: #if len(res)>0 and np.cumsum(np.array(res)).max()>0:
# successmessage = 'New Workouts have been created from email' # successmessage = 'New Workouts have been created from email'
workouts = Workout.objects.filter(user=r).order_by("-date", "-starttime") if request.method == 'POST':
dateform = DateRangeForm(request.POST)
if dateform.is_valid():
startdate = dateform.cleaned_data['startdate']
enddate = dateform.cleaned_data['enddate']
else:
dateform = DateRangeForm(initial={
'startdate':startdate,
'enddate':enddate,
})
startdate = datetime.datetime.combine(startdate,datetime.time())
enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59))
if startdatestring:
startdate = iso8601.parse_date(startdatestring)
if enddatestring:
enddate = iso8601.parse_date(enddatestring)
if enddate < startdate:
s = enddate
enddate = startdate
startdate = s
workouts = Workout.objects.filter(user=r,
startdatetime__gte=startdate,
startdatetime__lte=enddate).order_by("-date", "-starttime")
query = request.GET.get('q')
if query:
query_list = query.split()
workouts = workouts.filter(
reduce(operator.and_,
(Q(name__icontains=q) for q in query_list)) |
reduce(operator.and_,
(Q(notes__icontains=q) for q in query_list))
)
paginator = Paginator(workouts,20) # show 25 workouts per page
page = request.GET.get('page')
try:
workouts = paginator.page(page)
except PageNotAnInteger:
workouts = paginator.page(1)
except EmptyPage:
workouts = paginator.page(paginator.num_pages)
return render(request, 'list_workouts.html', return render(request, 'list_workouts.html',
{'workouts': workouts, {'workouts': workouts,
'message': message, 'message': message,
'successmessage':successmessage, 'successmessage':successmessage,
'dateform':dateform,
'startdate':startdate,
'enddate':enddate,
}) })
except Rower.DoesNotExist: except Rower.DoesNotExist:
return HttpResponse("User has no rower instance") return HttpResponse("User has no rower instance")
@user_passes_test(promember,login_url="/login") @user_passes_test(promember,login_url="/login")
def workout_comparison_list(request,id=0,message='',successmessage=''): def workout_comparison_list(request,id=0,message='',successmessage='',
startdatestring="",enddatestring="",
startdate=timezone.now()-datetime.timedelta(days=365),
enddate=timezone.now()):
try: try:
r = Rower.objects.get(user=request.user) r = Rower.objects.get(user=request.user)
u = User.objects.get(id=r.user.id) u = User.objects.get(id=r.user.id)
workouts = Workout.objects.filter(user=r).order_by("-date", "-starttime").exclude(id=id) if request.method == 'POST':
dateform = DateRangeForm(request.POST)
if dateform.is_valid():
startdate = dateform.cleaned_data['startdate']
enddate = dateform.cleaned_data['enddate']
else:
dateform = DateRangeForm(initial={
'startdate':startdate,
'enddate':enddate,
})
if startdatestring:
startdate = iso8601.parse_date(startdatestring)
if enddatestring:
enddate = iso8601.parse_date(enddatestring)
startdate = datetime.datetime.combine(startdate,datetime.time())
enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59))
if enddate < startdate:
s = enddate
enddate = startdate
startdate = s
workouts = Workout.objects.filter(user=r,
startdatetime__gte=startdate,
startdatetime__lte=enddate).order_by("-date", "-starttime").exclude(id=id)
query = request.GET.get('q')
if query:
query_list = query.split()
workouts = workouts.filter(
reduce(operator.and_,
(Q(name__icontains=q) for q in query_list)) |
reduce(operator.and_,
(Q(notes__icontains=q) for q in query_list))
)
paginator = Paginator(workouts,15) # show 25 workouts per page
page = request.GET.get('page')
try:
workouts = paginator.page(page)
except PageNotAnInteger:
workouts = paginator.page(1)
except EmptyPage:
workouts = paginator.page(paginator.num_pages)
row = Workout.objects.get(id=id) row = Workout.objects.get(id=id)
return render(request, 'comparison_list.html', return render(request, 'comparison_list.html',
@@ -1787,6 +1948,9 @@ def workout_comparison_list(request,id=0,message='',successmessage=''):
'first_name':u.first_name, 'first_name':u.first_name,
'message': message, 'message': message,
'successmessage':successmessage, 'successmessage':successmessage,
'dateform':dateform,
'startdate':startdate,
'enddate':enddate,
}) })
except Rower.DoesNotExist: except Rower.DoesNotExist:
return HttpResponse("User has no rower instance") return HttpResponse("User has no rower instance")
@@ -2712,11 +2876,14 @@ def workout_edit_view(request,id=0,message="",successmessage=""):
rowdata = rdata(f1) rowdata = rdata(f1)
hascoordinates = 1 hascoordinates = 1
try: if rowdata != 0:
latitude = rowdata.df[' latitude'] try:
except KeyError: latitude = rowdata.df[' latitude']
hascoordinates = 0 except KeyError,AttributeError:
hascoordinates = 0
else:
hascoordinates = 0
if hascoordinates: if hascoordinates:
res = googlemap_chart(rowdata.df[' latitude'], res = googlemap_chart(rowdata.df[' latitude'],
rowdata.df[' longitude'], rowdata.df[' longitude'],
@@ -3932,6 +4099,16 @@ def graphs_view(request):
try: try:
r = Rower.objects.get(user=request.user) r = Rower.objects.get(user=request.user)
workouts = Workout.objects.filter(user=r).order_by("-date", "-starttime") workouts = Workout.objects.filter(user=r).order_by("-date", "-starttime")
query = request.GET.get('q')
if query:
query_list = query.split()
workouts = workouts.filter(
reduce(operator.and_,
(Q(name__icontains=q) for q in query_list)) |
reduce(operator.and_,
(Q(notes__icontains=q) for q in query_list))
)
g = GraphImage.objects.filter(workout__in=workouts).order_by("-creationdatetime") g = GraphImage.objects.filter(workout__in=workouts).order_by("-creationdatetime")
if (len(g)<=5): if (len(g)<=5):
return render(request, 'list_graphs.html', return render(request, 'list_graphs.html',

View File

@@ -17,14 +17,19 @@ a {
text-decoration: none; text-decoration: none;
} }
a:visited { color:#000; } a:visited { color:#000; }
a:link { color: #000; } a:link { color: #000; }
a:hover { a:hover {
text-decoration: underline; text-decoration: underline;
} }
h1 { h1 {
/* font-family: Georgia, serif; */ /* font-family: Georgia, serif; */
font-weight: normal; font-weight: normal;
@@ -471,4 +476,16 @@ a.button {
.flexplot { .flexplot {
position: relative; position: relative;
z-index: 10; z-index: 10;
} }
a.wh:link {
color: #e9e9e9;
}
a.wh:visited {
color: #e9e9e9;
}
a.wh:hover {
color: #e9e9e9;
}