Files
workout/data query and formatting.ipynb
T

87 KiB

Goal is to display all workouts

* Query database

* Transform models into viewmodels

* Display data to user

In [45]:
import sqlite3
import json
from datetime import datetime
In [2]:
DATABASE = 'workout.db'

Define function to query database

In [3]:
def query_db(query, args=(), one=False):
    conn = sqlite3.connect(DATABASE)
    conn.row_factory = sqlite3.Row
    cur = conn.execute(query, args)
    rv = cur.fetchall()
    conn.commit()
    cur.close()
    return (rv[0] if rv else None) if one else rv

Query all workouts & topsets completed by Gabe(PersonId=1)

In [70]:
topsets = query_db("""
    SELECT 
        P.PersonId, 
        P.Name AS PersonName, 
        W.WorkoutId, 
        W.StartDate, 
        T.TopSetId, 
        E.ExerciseId, 
        E.Name AS ExerciseName, 
        T.Repetitions, 
        T.Weight
    FROM Person P
         LEFT JOIN Workout W ON P.PersonId=W.PersonId
         LEFT JOIN TopSet T ON W.WorkoutId=T.WorkoutId
         LEFT JOIN Exercise E ON T.ExerciseId=E.ExerciseId
    WHERE P.PersonId=?""", [1])

for topset in topsets:
    print(f'WorkoutId: {topset["WorkoutId"]}, PersonId: {topset["PersonId"]} Person:{topset["PersonName"]}, StartDate: {topset["StartDate"]}, TopSetId: {topset["TopSetId"]}, ExerciseId: {topset["ExerciseId"]}, Exercise: {topset["ExerciseName"]}, Repetitions: {topset["Repetitions"]}, Weight: {topset["Weight"]}kg')
WorkoutId: 35, PersonId: 1 Person:Gabe, StartDate: 2022-01-13, TopSetId: 61, ExerciseId: 2, Exercise: Bench, Repetitions: 8, Weight: 50kg
WorkoutId: 36, PersonId: 1 Person:Gabe, StartDate: 2022-01-18, TopSetId: 62, ExerciseId: 1, Exercise: Squat, Repetitions: 7, Weight: 55kg
WorkoutId: 36, PersonId: 1 Person:Gabe, StartDate: 2022-01-18, TopSetId: 63, ExerciseId: 4, Exercise: Hotep, Repetitions: 4, Weight: 25kg
WorkoutId: 37, PersonId: 1 Person:Gabe, StartDate: 2022-02-08, TopSetId: 64, ExerciseId: 2, Exercise: Bench, Repetitions: 5, Weight: 55kg
WorkoutId: 37, PersonId: 1 Person:Gabe, StartDate: 2022-02-08, TopSetId: 65, ExerciseId: 3, Exercise: Deadlift, Repetitions: 6, Weight: 95kg
WorkoutId: 38, PersonId: 1 Person:Gabe, StartDate: 2022-02-15, TopSetId: 66, ExerciseId: 1, Exercise: Squat, Repetitions: 3, Weight: 65kg
WorkoutId: 38, PersonId: 1 Person:Gabe, StartDate: 2022-02-15, TopSetId: 67, ExerciseId: 4, Exercise: Hotep, Repetitions: 6, Weight: 25kg
WorkoutId: 39, PersonId: 1 Person:Gabe, StartDate: 2022-02-17, TopSetId: 68, ExerciseId: 2, Exercise: Bench, Repetitions: 2, Weight: 60kg
WorkoutId: 39, PersonId: 1 Person:Gabe, StartDate: 2022-02-17, TopSetId: 69, ExerciseId: 3, Exercise: Deadlift, Repetitions: 8, Weight: 105kg
WorkoutId: 40, PersonId: 1 Person:Gabe, StartDate: 2022-03-01, TopSetId: 70, ExerciseId: 1, Exercise: Squat, Repetitions: 3, Weight: 75kg
WorkoutId: 40, PersonId: 1 Person:Gabe, StartDate: 2022-03-01, TopSetId: 71, ExerciseId: 4, Exercise: Hotep, Repetitions: 4, Weight: 30kg
WorkoutId: 41, PersonId: 1 Person:Gabe, StartDate: 2022-03-10, TopSetId: 72, ExerciseId: 2, Exercise: Bench, Repetitions: 11, Weight: 50kg
WorkoutId: 42, PersonId: 1 Person:Gabe, StartDate: 2022-03-15, TopSetId: 73, ExerciseId: 1, Exercise: Squat, Repetitions: 5, Weight: 75kg
WorkoutId: 42, PersonId: 1 Person:Gabe, StartDate: 2022-03-15, TopSetId: 74, ExerciseId: 4, Exercise: Hotep, Repetitions: 5, Weight: 30kg
WorkoutId: 43, PersonId: 1 Person:Gabe, StartDate: 2022-03-22, TopSetId: 75, ExerciseId: 2, Exercise: Bench, Repetitions: 4, Weight: 60kg
WorkoutId: 43, PersonId: 1 Person:Gabe, StartDate: 2022-03-22, TopSetId: 76, ExerciseId: 3, Exercise: Deadlift, Repetitions: 4, Weight: 110kg
WorkoutId: 44, PersonId: 1 Person:Gabe, StartDate: 2022-04-07, TopSetId: 77, ExerciseId: 1, Exercise: Squat, Repetitions: 6, Weight: 75kg
WorkoutId: 44, PersonId: 1 Person:Gabe, StartDate: 2022-04-07, TopSetId: 78, ExerciseId: 4, Exercise: Hotep, Repetitions: 2, Weight: 35kg
WorkoutId: 45, PersonId: 1 Person:Gabe, StartDate: 2022-04-21, TopSetId: 79, ExerciseId: 2, Exercise: Bench, Repetitions: 10, Weight: 45kg
WorkoutId: 45, PersonId: 1 Person:Gabe, StartDate: 2022-04-21, TopSetId: 80, ExerciseId: 3, Exercise: Deadlift, Repetitions: 10, Weight: 100kg
WorkoutId: 46, PersonId: 1 Person:Gabe, StartDate: 2022-04-26, TopSetId: 81, ExerciseId: 1, Exercise: Squat, Repetitions: 3, Weight: 80kg
WorkoutId: 47, PersonId: 1 Person:Gabe, StartDate: 2022-04-28, TopSetId: 82, ExerciseId: 2, Exercise: Bench, Repetitions: 2, Weight: 60kg
WorkoutId: 47, PersonId: 1 Person:Gabe, StartDate: 2022-04-28, TopSetId: 83, ExerciseId: 3, Exercise: Deadlift, Repetitions: 5, Weight: 100kg
WorkoutId: 48, PersonId: 1 Person:Gabe, StartDate: 2022-05-03, TopSetId: 84, ExerciseId: 2, Exercise: Bench, Repetitions: 4, Weight: 55kg
WorkoutId: 48, PersonId: 1 Person:Gabe, StartDate: 2022-05-03, TopSetId: 85, ExerciseId: 3, Exercise: Deadlift, Repetitions: 7, Weight: 95kg
WorkoutId: 49, PersonId: 1 Person:Gabe, StartDate: 2022-05-05, TopSetId: 86, ExerciseId: 2, Exercise: Bench, Repetitions: 4, Weight: 55kg
WorkoutId: 49, PersonId: 1 Person:Gabe, StartDate: 2022-05-05, TopSetId: 87, ExerciseId: 3, Exercise: Deadlift, Repetitions: 7, Weight: 110kg
WorkoutId: 50, PersonId: 1 Person:Gabe, StartDate: 2022-05-17, TopSetId: 88, ExerciseId: 1, Exercise: Squat, Repetitions: 3, Weight: 60kg
WorkoutId: 50, PersonId: 1 Person:Gabe, StartDate: 2022-05-17, TopSetId: 89, ExerciseId: 4, Exercise: Hotep, Repetitions: 4, Weight: 27kg
WorkoutId: 51, PersonId: 1 Person:Gabe, StartDate: 2022-05-19, TopSetId: 90, ExerciseId: 2, Exercise: Bench, Repetitions: 1, Weight: 65kg
WorkoutId: 51, PersonId: 1 Person:Gabe, StartDate: 2022-05-19, TopSetId: 91, ExerciseId: 3, Exercise: Deadlift, Repetitions: 4, Weight: 125kg
WorkoutId: 52, PersonId: 1 Person:Gabe, StartDate: 2022-06-07, TopSetId: 92, ExerciseId: 2, Exercise: Bench, Repetitions: 4, Weight: 55kg
WorkoutId: 52, PersonId: 1 Person:Gabe, StartDate: 2022-06-07, TopSetId: 93, ExerciseId: 3, Exercise: Deadlift, Repetitions: 5, Weight: 100kg
WorkoutId: 53, PersonId: 1 Person:Gabe, StartDate: 2022-06-14, TopSetId: 94, ExerciseId: 1, Exercise: Squat, Repetitions: 2, Weight: 75kg
WorkoutId: 53, PersonId: 1 Person:Gabe, StartDate: 2022-06-14, TopSetId: 95, ExerciseId: 4, Exercise: Hotep, Repetitions: 4, Weight: 31kg
WorkoutId: 54, PersonId: 1 Person:Gabe, StartDate: 2022-06-29, TopSetId: 96, ExerciseId: 2, Exercise: Bench, Repetitions: 11, Weight: 40kg
WorkoutId: 55, PersonId: 1 Person:Gabe, StartDate: 2022-07-07, TopSetId: 97, ExerciseId: 1, Exercise: Squat, Repetitions: 5, Weight: 65kg
WorkoutId: 55, PersonId: 1 Person:Gabe, StartDate: 2022-07-07, TopSetId: 98, ExerciseId: 4, Exercise: Hotep, Repetitions: 6, Weight: 30kg
WorkoutId: 56, PersonId: 1 Person:Gabe, StartDate: 2022-07-12, TopSetId: 99, ExerciseId: 2, Exercise: Bench, Repetitions: 4, Weight: 60kg
WorkoutId: 56, PersonId: 1 Person:Gabe, StartDate: 2022-07-12, TopSetId: 100, ExerciseId: 3, Exercise: Deadlift, Repetitions: 9, Weight: 100kg
WorkoutId: 57, PersonId: 1 Person:Gabe, StartDate: 2022-07-15, TopSetId: 101, ExerciseId: 1, Exercise: Squat, Repetitions: 6, Weight: 75kg
WorkoutId: 57, PersonId: 1 Person:Gabe, StartDate: 2022-07-15, TopSetId: 102, ExerciseId: 4, Exercise: Hotep, Repetitions: 3, Weight: 35kg

Transform entity to view model with the following schema

{   "PersonId": 1,
    "PersonName": "Gabe",  
    "Exercises": [{"ExerciseIs": 1, "ExerciseName": "Squat"}, {"ExerciseIs": 2, "ExerciseName": "Bench"}]  
    "Workouts": [  
        {  
            "WorkoutId": 1,
            "StartDate": "2022-06-29 00:00:00.000",  
            "TopSets": [  
                {  
                    "ExerciseId": 1,
                    "ExerciseName": "Squat",  
                    "Weight": 80,  
                    "Repetitions": 8  
                },  
                {  
                    "ExerciseId": 2,
                    "ExerciseName": "Bench",  
                    "Weight": 60,  
                    "Repetitions": 4  
                }  
            ]  
        },  
        {
            "WorkoutId": 2,
            "StartDate": "2022-07-01 00:00:00.000",  
            "TopSets": [  
                {  
                    "ExerciseId": 1,
                    "ExerciseName": "Squat",  
                    "Weight": 85,  
                    "Repetitions": 4  
                },  
                {  
                    "ExerciseId": 2,
                    "ExerciseName": "Bench",  
                    "Weight": 65,  
                    "Repetitions": 5  
                }  
            ]  
        }  
    ]  
} 

1. Extract name from rows

In [37]:
def get_name(topsets):
    return topsets[0]['PersonName']

get_name(topsets)
Out [37]:
'Gabe'

2. Group rows into workouts using WorkoutId column

In [15]:
def get_workouts(topsets):
    # Get all unique workout_ids (No duplicates)
    workout_ids = set([t['WorkoutId'] for t in topsets])

    # Group topsets into workouts
    workouts = []
    for workout_id in workout_ids:
        topsets_in_workout = [t for t in topsets if t['WorkoutId'] == workout_id]
        workouts.append({
            'WorkoutId': workout_id,
            'StartDate': topsets_in_workout[0]['StartDate'],
            'TopSets': [{"TopSetId": t['TopSetId'], "ExerciseId": t['ExerciseId'], "ExerciseName": t['ExerciseName'], "Weight": t['Weight'], "Repetitions": t['Repetitions'] } for t in topsets_in_workout]
        })
    return workouts
In [16]:
print(json.dumps(get_workouts(topsets), indent=2))
[
  {
    "WorkoutId": 35,
    "StartDate": "2022-01-13",
    "TopSets": [
      {
        "TopSetId": 61,
        "ExerciseId": 2,
        "ExerciseName": "Bench",
        "Weight": 50,
        "Repetitions": 8
      }
    ]
  },
  {
    "WorkoutId": 36,
    "StartDate": "2022-01-18",
    "TopSets": [
      {
        "TopSetId": 62,
        "ExerciseId": 1,
        "ExerciseName": "Squat",
        "Weight": 55,
        "Repetitions": 7
      },
      {
        "TopSetId": 63,
        "ExerciseId": 4,
        "ExerciseName": "Hotep",
        "Weight": 25,
        "Repetitions": 4
      }
    ]
  },
  {
    "WorkoutId": 37,
    "StartDate": "2022-02-08",
    "TopSets": [
      {
        "TopSetId": 64,
        "ExerciseId": 2,
        "ExerciseName": "Bench",
        "Weight": 55,
        "Repetitions": 5
      },
      {
        "TopSetId": 65,
        "ExerciseId": 3,
        "ExerciseName": "Deadlift",
        "Weight": 95,
        "Repetitions": 6
      }
    ]
  },
  {
    "WorkoutId": 38,
    "StartDate": "2022-02-15",
    "TopSets": [
      {
        "TopSetId": 66,
        "ExerciseId": 1,
        "ExerciseName": "Squat",
        "Weight": 65,
        "Repetitions": 3
      },
      {
        "TopSetId": 67,
        "ExerciseId": 4,
        "ExerciseName": "Hotep",
        "Weight": 25,
        "Repetitions": 6
      }
    ]
  },
  {
    "WorkoutId": 39,
    "StartDate": "2022-02-17",
    "TopSets": [
      {
        "TopSetId": 68,
        "ExerciseId": 2,
        "ExerciseName": "Bench",
        "Weight": 60,
        "Repetitions": 2
      },
      {
        "TopSetId": 69,
        "ExerciseId": 3,
        "ExerciseName": "Deadlift",
        "Weight": 105,
        "Repetitions": 8
      }
    ]
  },
  {
    "WorkoutId": 40,
    "StartDate": "2022-03-01",
    "TopSets": [
      {
        "TopSetId": 70,
        "ExerciseId": 1,
        "ExerciseName": "Squat",
        "Weight": 75,
        "Repetitions": 3
      },
      {
        "TopSetId": 71,
        "ExerciseId": 4,
        "ExerciseName": "Hotep",
        "Weight": 30,
        "Repetitions": 4
      }
    ]
  },
  {
    "WorkoutId": 41,
    "StartDate": "2022-03-10",
    "TopSets": [
      {
        "TopSetId": 72,
        "ExerciseId": 2,
        "ExerciseName": "Bench",
        "Weight": 50,
        "Repetitions": 11
      }
    ]
  },
  {
    "WorkoutId": 42,
    "StartDate": "2022-03-15",
    "TopSets": [
      {
        "TopSetId": 73,
        "ExerciseId": 1,
        "ExerciseName": "Squat",
        "Weight": 75,
        "Repetitions": 5
      },
      {
        "TopSetId": 74,
        "ExerciseId": 4,
        "ExerciseName": "Hotep",
        "Weight": 30,
        "Repetitions": 5
      }
    ]
  },
  {
    "WorkoutId": 43,
    "StartDate": "2022-03-22",
    "TopSets": [
      {
        "TopSetId": 75,
        "ExerciseId": 2,
        "ExerciseName": "Bench",
        "Weight": 60,
        "Repetitions": 4
      },
      {
        "TopSetId": 76,
        "ExerciseId": 3,
        "ExerciseName": "Deadlift",
        "Weight": 110,
        "Repetitions": 4
      }
    ]
  },
  {
    "WorkoutId": 44,
    "StartDate": "2022-04-07",
    "TopSets": [
      {
        "TopSetId": 77,
        "ExerciseId": 1,
        "ExerciseName": "Squat",
        "Weight": 75,
        "Repetitions": 6
      },
      {
        "TopSetId": 78,
        "ExerciseId": 4,
        "ExerciseName": "Hotep",
        "Weight": 35,
        "Repetitions": 2
      }
    ]
  },
  {
    "WorkoutId": 45,
    "StartDate": "2022-04-21",
    "TopSets": [
      {
        "TopSetId": 79,
        "ExerciseId": 2,
        "ExerciseName": "Bench",
        "Weight": 45,
        "Repetitions": 10
      },
      {
        "TopSetId": 80,
        "ExerciseId": 3,
        "ExerciseName": "Deadlift",
        "Weight": 100,
        "Repetitions": 10
      }
    ]
  },
  {
    "WorkoutId": 46,
    "StartDate": "2022-04-26",
    "TopSets": [
      {
        "TopSetId": 81,
        "ExerciseId": 1,
        "ExerciseName": "Squat",
        "Weight": 80,
        "Repetitions": 3
      }
    ]
  },
  {
    "WorkoutId": 47,
    "StartDate": "2022-04-28",
    "TopSets": [
      {
        "TopSetId": 82,
        "ExerciseId": 2,
        "ExerciseName": "Bench",
        "Weight": 60,
        "Repetitions": 2
      },
      {
        "TopSetId": 83,
        "ExerciseId": 3,
        "ExerciseName": "Deadlift",
        "Weight": 100,
        "Repetitions": 5
      }
    ]
  },
  {
    "WorkoutId": 48,
    "StartDate": "2022-05-03",
    "TopSets": [
      {
        "TopSetId": 84,
        "ExerciseId": 2,
        "ExerciseName": "Bench",
        "Weight": 55,
        "Repetitions": 4
      },
      {
        "TopSetId": 85,
        "ExerciseId": 3,
        "ExerciseName": "Deadlift",
        "Weight": 95,
        "Repetitions": 7
      }
    ]
  },
  {
    "WorkoutId": 49,
    "StartDate": "2022-05-05",
    "TopSets": [
      {
        "TopSetId": 86,
        "ExerciseId": 2,
        "ExerciseName": "Bench",
        "Weight": 55,
        "Repetitions": 4
      },
      {
        "TopSetId": 87,
        "ExerciseId": 3,
        "ExerciseName": "Deadlift",
        "Weight": 110,
        "Repetitions": 7
      }
    ]
  },
  {
    "WorkoutId": 50,
    "StartDate": "2022-05-17",
    "TopSets": [
      {
        "TopSetId": 88,
        "ExerciseId": 1,
        "ExerciseName": "Squat",
        "Weight": 60,
        "Repetitions": 3
      },
      {
        "TopSetId": 89,
        "ExerciseId": 4,
        "ExerciseName": "Hotep",
        "Weight": 27,
        "Repetitions": 4
      }
    ]
  },
  {
    "WorkoutId": 51,
    "StartDate": "2022-05-19",
    "TopSets": [
      {
        "TopSetId": 90,
        "ExerciseId": 2,
        "ExerciseName": "Bench",
        "Weight": 65,
        "Repetitions": 1
      },
      {
        "TopSetId": 91,
        "ExerciseId": 3,
        "ExerciseName": "Deadlift",
        "Weight": 125,
        "Repetitions": 4
      }
    ]
  },
  {
    "WorkoutId": 52,
    "StartDate": "2022-06-07",
    "TopSets": [
      {
        "TopSetId": 92,
        "ExerciseId": 2,
        "ExerciseName": "Bench",
        "Weight": 55,
        "Repetitions": 4
      },
      {
        "TopSetId": 93,
        "ExerciseId": 3,
        "ExerciseName": "Deadlift",
        "Weight": 100,
        "Repetitions": 5
      }
    ]
  },
  {
    "WorkoutId": 53,
    "StartDate": "2022-06-14",
    "TopSets": [
      {
        "TopSetId": 94,
        "ExerciseId": 1,
        "ExerciseName": "Squat",
        "Weight": 75,
        "Repetitions": 2
      },
      {
        "TopSetId": 95,
        "ExerciseId": 4,
        "ExerciseName": "Hotep",
        "Weight": 31,
        "Repetitions": 4
      }
    ]
  },
  {
    "WorkoutId": 54,
    "StartDate": "2022-06-29",
    "TopSets": [
      {
        "TopSetId": 96,
        "ExerciseId": 2,
        "ExerciseName": "Bench",
        "Weight": 40,
        "Repetitions": 11
      }
    ]
  },
  {
    "WorkoutId": 55,
    "StartDate": "2022-07-07",
    "TopSets": [
      {
        "TopSetId": 97,
        "ExerciseId": 1,
        "ExerciseName": "Squat",
        "Weight": 65,
        "Repetitions": 5
      },
      {
        "TopSetId": 98,
        "ExerciseId": 4,
        "ExerciseName": "Hotep",
        "Weight": 30,
        "Repetitions": 6
      }
    ]
  },
  {
    "WorkoutId": 56,
    "StartDate": "2022-07-12",
    "TopSets": [
      {
        "TopSetId": 99,
        "ExerciseId": 2,
        "ExerciseName": "Bench",
        "Weight": 60,
        "Repetitions": 4
      },
      {
        "TopSetId": 100,
        "ExerciseId": 3,
        "ExerciseName": "Deadlift",
        "Weight": 100,
        "Repetitions": 9
      }
    ]
  },
  {
    "WorkoutId": 57,
    "StartDate": "2022-07-15",
    "TopSets": [
      {
        "TopSetId": 101,
        "ExerciseId": 1,
        "ExerciseName": "Squat",
        "Weight": 75,
        "Repetitions": 6
      },
      {
        "TopSetId": 102,
        "ExerciseId": 4,
        "ExerciseName": "Hotep",
        "Weight": 35,
        "Repetitions": 3
      }
    ]
  }
]
In [17]:
def get_all_exercises_from_topsets(topsets):
    exercise_ids = set([t['ExerciseId'] for t in topsets])
    exercises = []
    for exercise_id in exercise_ids:
        exercises.append({
            'ExerciseId': exercise_id,
            'ExerciseName': next((t['ExerciseName'] for t in topsets if t['ExerciseId'] == exercise_id), 'Unknown')
        })
    return exercises

get_all_exercises_from_topsets(topsets)
Out [17]:
[{'ExerciseId': 1, 'ExerciseName': 'Squat'},
 {'ExerciseId': 2, 'ExerciseName': 'Bench'},
 {'ExerciseId': 3, 'ExerciseName': 'Deadlift'},
 {'ExerciseId': 4, 'ExerciseName': 'Hotep'}]

3. Compose functions together to acheive final model

In [18]:
def convert_to_view_model(topsets):
    return {
        'PersonId': next((t['PersonId'] for t in topsets), -1),
        'PersonName': next((t['PersonName'] for t in topsets), -1),
        'Exercises': get_all_exercises_from_topsets(topsets),
        'Workouts': get_workouts(topsets)
    }
In [19]:
print(json.dumps(convert_to_view_model(topsets), indent=2))
{
  "PersonId": 1,
  "PersonName": "Gabe",
  "Exercises": [
    {
      "ExerciseId": 1,
      "ExerciseName": "Squat"
    },
    {
      "ExerciseId": 2,
      "ExerciseName": "Bench"
    },
    {
      "ExerciseId": 3,
      "ExerciseName": "Deadlift"
    },
    {
      "ExerciseId": 4,
      "ExerciseName": "Hotep"
    }
  ],
  "Workouts": [
    {
      "WorkoutId": 35,
      "StartDate": "2022-01-13",
      "TopSets": [
        {
          "TopSetId": 61,
          "ExerciseId": 2,
          "ExerciseName": "Bench",
          "Weight": 50,
          "Repetitions": 8
        }
      ]
    },
    {
      "WorkoutId": 36,
      "StartDate": "2022-01-18",
      "TopSets": [
        {
          "TopSetId": 62,
          "ExerciseId": 1,
          "ExerciseName": "Squat",
          "Weight": 55,
          "Repetitions": 7
        },
        {
          "TopSetId": 63,
          "ExerciseId": 4,
          "ExerciseName": "Hotep",
          "Weight": 25,
          "Repetitions": 4
        }
      ]
    },
    {
      "WorkoutId": 37,
      "StartDate": "2022-02-08",
      "TopSets": [
        {
          "TopSetId": 64,
          "ExerciseId": 2,
          "ExerciseName": "Bench",
          "Weight": 55,
          "Repetitions": 5
        },
        {
          "TopSetId": 65,
          "ExerciseId": 3,
          "ExerciseName": "Deadlift",
          "Weight": 95,
          "Repetitions": 6
        }
      ]
    },
    {
      "WorkoutId": 38,
      "StartDate": "2022-02-15",
      "TopSets": [
        {
          "TopSetId": 66,
          "ExerciseId": 1,
          "ExerciseName": "Squat",
          "Weight": 65,
          "Repetitions": 3
        },
        {
          "TopSetId": 67,
          "ExerciseId": 4,
          "ExerciseName": "Hotep",
          "Weight": 25,
          "Repetitions": 6
        }
      ]
    },
    {
      "WorkoutId": 39,
      "StartDate": "2022-02-17",
      "TopSets": [
        {
          "TopSetId": 68,
          "ExerciseId": 2,
          "ExerciseName": "Bench",
          "Weight": 60,
          "Repetitions": 2
        },
        {
          "TopSetId": 69,
          "ExerciseId": 3,
          "ExerciseName": "Deadlift",
          "Weight": 105,
          "Repetitions": 8
        }
      ]
    },
    {
      "WorkoutId": 40,
      "StartDate": "2022-03-01",
      "TopSets": [
        {
          "TopSetId": 70,
          "ExerciseId": 1,
          "ExerciseName": "Squat",
          "Weight": 75,
          "Repetitions": 3
        },
        {
          "TopSetId": 71,
          "ExerciseId": 4,
          "ExerciseName": "Hotep",
          "Weight": 30,
          "Repetitions": 4
        }
      ]
    },
    {
      "WorkoutId": 41,
      "StartDate": "2022-03-10",
      "TopSets": [
        {
          "TopSetId": 72,
          "ExerciseId": 2,
          "ExerciseName": "Bench",
          "Weight": 50,
          "Repetitions": 11
        }
      ]
    },
    {
      "WorkoutId": 42,
      "StartDate": "2022-03-15",
      "TopSets": [
        {
          "TopSetId": 73,
          "ExerciseId": 1,
          "ExerciseName": "Squat",
          "Weight": 75,
          "Repetitions": 5
        },
        {
          "TopSetId": 74,
          "ExerciseId": 4,
          "ExerciseName": "Hotep",
          "Weight": 30,
          "Repetitions": 5
        }
      ]
    },
    {
      "WorkoutId": 43,
      "StartDate": "2022-03-22",
      "TopSets": [
        {
          "TopSetId": 75,
          "ExerciseId": 2,
          "ExerciseName": "Bench",
          "Weight": 60,
          "Repetitions": 4
        },
        {
          "TopSetId": 76,
          "ExerciseId": 3,
          "ExerciseName": "Deadlift",
          "Weight": 110,
          "Repetitions": 4
        }
      ]
    },
    {
      "WorkoutId": 44,
      "StartDate": "2022-04-07",
      "TopSets": [
        {
          "TopSetId": 77,
          "ExerciseId": 1,
          "ExerciseName": "Squat",
          "Weight": 75,
          "Repetitions": 6
        },
        {
          "TopSetId": 78,
          "ExerciseId": 4,
          "ExerciseName": "Hotep",
          "Weight": 35,
          "Repetitions": 2
        }
      ]
    },
    {
      "WorkoutId": 45,
      "StartDate": "2022-04-21",
      "TopSets": [
        {
          "TopSetId": 79,
          "ExerciseId": 2,
          "ExerciseName": "Bench",
          "Weight": 45,
          "Repetitions": 10
        },
        {
          "TopSetId": 80,
          "ExerciseId": 3,
          "ExerciseName": "Deadlift",
          "Weight": 100,
          "Repetitions": 10
        }
      ]
    },
    {
      "WorkoutId": 46,
      "StartDate": "2022-04-26",
      "TopSets": [
        {
          "TopSetId": 81,
          "ExerciseId": 1,
          "ExerciseName": "Squat",
          "Weight": 80,
          "Repetitions": 3
        }
      ]
    },
    {
      "WorkoutId": 47,
      "StartDate": "2022-04-28",
      "TopSets": [
        {
          "TopSetId": 82,
          "ExerciseId": 2,
          "ExerciseName": "Bench",
          "Weight": 60,
          "Repetitions": 2
        },
        {
          "TopSetId": 83,
          "ExerciseId": 3,
          "ExerciseName": "Deadlift",
          "Weight": 100,
          "Repetitions": 5
        }
      ]
    },
    {
      "WorkoutId": 48,
      "StartDate": "2022-05-03",
      "TopSets": [
        {
          "TopSetId": 84,
          "ExerciseId": 2,
          "ExerciseName": "Bench",
          "Weight": 55,
          "Repetitions": 4
        },
        {
          "TopSetId": 85,
          "ExerciseId": 3,
          "ExerciseName": "Deadlift",
          "Weight": 95,
          "Repetitions": 7
        }
      ]
    },
    {
      "WorkoutId": 49,
      "StartDate": "2022-05-05",
      "TopSets": [
        {
          "TopSetId": 86,
          "ExerciseId": 2,
          "ExerciseName": "Bench",
          "Weight": 55,
          "Repetitions": 4
        },
        {
          "TopSetId": 87,
          "ExerciseId": 3,
          "ExerciseName": "Deadlift",
          "Weight": 110,
          "Repetitions": 7
        }
      ]
    },
    {
      "WorkoutId": 50,
      "StartDate": "2022-05-17",
      "TopSets": [
        {
          "TopSetId": 88,
          "ExerciseId": 1,
          "ExerciseName": "Squat",
          "Weight": 60,
          "Repetitions": 3
        },
        {
          "TopSetId": 89,
          "ExerciseId": 4,
          "ExerciseName": "Hotep",
          "Weight": 27,
          "Repetitions": 4
        }
      ]
    },
    {
      "WorkoutId": 51,
      "StartDate": "2022-05-19",
      "TopSets": [
        {
          "TopSetId": 90,
          "ExerciseId": 2,
          "ExerciseName": "Bench",
          "Weight": 65,
          "Repetitions": 1
        },
        {
          "TopSetId": 91,
          "ExerciseId": 3,
          "ExerciseName": "Deadlift",
          "Weight": 125,
          "Repetitions": 4
        }
      ]
    },
    {
      "WorkoutId": 52,
      "StartDate": "2022-06-07",
      "TopSets": [
        {
          "TopSetId": 92,
          "ExerciseId": 2,
          "ExerciseName": "Bench",
          "Weight": 55,
          "Repetitions": 4
        },
        {
          "TopSetId": 93,
          "ExerciseId": 3,
          "ExerciseName": "Deadlift",
          "Weight": 100,
          "Repetitions": 5
        }
      ]
    },
    {
      "WorkoutId": 53,
      "StartDate": "2022-06-14",
      "TopSets": [
        {
          "TopSetId": 94,
          "ExerciseId": 1,
          "ExerciseName": "Squat",
          "Weight": 75,
          "Repetitions": 2
        },
        {
          "TopSetId": 95,
          "ExerciseId": 4,
          "ExerciseName": "Hotep",
          "Weight": 31,
          "Repetitions": 4
        }
      ]
    },
    {
      "WorkoutId": 54,
      "StartDate": "2022-06-29",
      "TopSets": [
        {
          "TopSetId": 96,
          "ExerciseId": 2,
          "ExerciseName": "Bench",
          "Weight": 40,
          "Repetitions": 11
        }
      ]
    },
    {
      "WorkoutId": 55,
      "StartDate": "2022-07-07",
      "TopSets": [
        {
          "TopSetId": 97,
          "ExerciseId": 1,
          "ExerciseName": "Squat",
          "Weight": 65,
          "Repetitions": 5
        },
        {
          "TopSetId": 98,
          "ExerciseId": 4,
          "ExerciseName": "Hotep",
          "Weight": 30,
          "Repetitions": 6
        }
      ]
    },
    {
      "WorkoutId": 56,
      "StartDate": "2022-07-12",
      "TopSets": [
        {
          "TopSetId": 99,
          "ExerciseId": 2,
          "ExerciseName": "Bench",
          "Weight": 60,
          "Repetitions": 4
        },
        {
          "TopSetId": 100,
          "ExerciseId": 3,
          "ExerciseName": "Deadlift",
          "Weight": 100,
          "Repetitions": 9
        }
      ]
    },
    {
      "WorkoutId": 57,
      "StartDate": "2022-07-15",
      "TopSets": [
        {
          "TopSetId": 101,
          "ExerciseId": 1,
          "ExerciseName": "Squat",
          "Weight": 75,
          "Repetitions": 6
        },
        {
          "TopSetId": 102,
          "ExerciseId": 4,
          "ExerciseName": "Hotep",
          "Weight": 35,
          "Repetitions": 3
        }
      ]
    }
  ]
}

Dashboard page

In [20]:
all_topsets =query_db("""
    SELECT 
        P.PersonId, 
        P.Name AS PersonName, 
        W.WorkoutId, 
        W.StartDate, 
        T.TopSetId, 
        E.ExerciseId, 
        E.Name AS ExerciseName, 
        T.Repetitions, 
        T.Weight
    FROM Person P
         LEFT JOIN Workout W ON P.PersonId=W.PersonId
         LEFT JOIN TopSet T ON W.WorkoutId=T.WorkoutId
         LEFT JOIN Exercise E ON T.ExerciseId=E.ExerciseId""")
In [23]:
def get_people(topsets):
    # Get all unique workout_ids (No duplicates)
    people_ids = set([t['PersonId'] for t in topsets])

    # Group topsets into workouts
    people = []
    for person_id in people_ids:
        workouts_for_person = [t for t in topsets if t['PersonId'] == person_id]
        people.append({
            'PersonId': person_id,
            'PersonName': workouts_for_person[0]['PersonName'],
            'Workouts': get_workouts(workouts_for_person)
        })
    return people
In [24]:
print(json.dumps(get_people(all_topsets), indent=2))
[
  {
    "PersonId": 1,
    "PersonName": "Gabe",
    "Workouts": [
      {
        "WorkoutId": 35,
        "StartDate": "2022-01-13",
        "TopSets": [
          {
            "TopSetId": 61,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 50,
            "Repetitions": 8
          }
        ]
      },
      {
        "WorkoutId": 36,
        "StartDate": "2022-01-18",
        "TopSets": [
          {
            "TopSetId": 62,
            "ExerciseId": 1,
            "ExerciseName": "Squat",
            "Weight": 55,
            "Repetitions": 7
          },
          {
            "TopSetId": 63,
            "ExerciseId": 4,
            "ExerciseName": "Hotep",
            "Weight": 25,
            "Repetitions": 4
          }
        ]
      },
      {
        "WorkoutId": 37,
        "StartDate": "2022-02-08",
        "TopSets": [
          {
            "TopSetId": 64,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 55,
            "Repetitions": 5
          },
          {
            "TopSetId": 65,
            "ExerciseId": 3,
            "ExerciseName": "Deadlift",
            "Weight": 95,
            "Repetitions": 6
          }
        ]
      },
      {
        "WorkoutId": 38,
        "StartDate": "2022-02-15",
        "TopSets": [
          {
            "TopSetId": 66,
            "ExerciseId": 1,
            "ExerciseName": "Squat",
            "Weight": 65,
            "Repetitions": 3
          },
          {
            "TopSetId": 67,
            "ExerciseId": 4,
            "ExerciseName": "Hotep",
            "Weight": 25,
            "Repetitions": 6
          }
        ]
      },
      {
        "WorkoutId": 39,
        "StartDate": "2022-02-17",
        "TopSets": [
          {
            "TopSetId": 68,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 60,
            "Repetitions": 2
          },
          {
            "TopSetId": 69,
            "ExerciseId": 3,
            "ExerciseName": "Deadlift",
            "Weight": 105,
            "Repetitions": 8
          }
        ]
      },
      {
        "WorkoutId": 40,
        "StartDate": "2022-03-01",
        "TopSets": [
          {
            "TopSetId": 70,
            "ExerciseId": 1,
            "ExerciseName": "Squat",
            "Weight": 75,
            "Repetitions": 3
          },
          {
            "TopSetId": 71,
            "ExerciseId": 4,
            "ExerciseName": "Hotep",
            "Weight": 30,
            "Repetitions": 4
          }
        ]
      },
      {
        "WorkoutId": 41,
        "StartDate": "2022-03-10",
        "TopSets": [
          {
            "TopSetId": 72,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 50,
            "Repetitions": 11
          }
        ]
      },
      {
        "WorkoutId": 42,
        "StartDate": "2022-03-15",
        "TopSets": [
          {
            "TopSetId": 73,
            "ExerciseId": 1,
            "ExerciseName": "Squat",
            "Weight": 75,
            "Repetitions": 5
          },
          {
            "TopSetId": 74,
            "ExerciseId": 4,
            "ExerciseName": "Hotep",
            "Weight": 30,
            "Repetitions": 5
          }
        ]
      },
      {
        "WorkoutId": 43,
        "StartDate": "2022-03-22",
        "TopSets": [
          {
            "TopSetId": 75,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 60,
            "Repetitions": 4
          },
          {
            "TopSetId": 76,
            "ExerciseId": 3,
            "ExerciseName": "Deadlift",
            "Weight": 110,
            "Repetitions": 4
          }
        ]
      },
      {
        "WorkoutId": 44,
        "StartDate": "2022-04-07",
        "TopSets": [
          {
            "TopSetId": 77,
            "ExerciseId": 1,
            "ExerciseName": "Squat",
            "Weight": 75,
            "Repetitions": 6
          },
          {
            "TopSetId": 78,
            "ExerciseId": 4,
            "ExerciseName": "Hotep",
            "Weight": 35,
            "Repetitions": 2
          }
        ]
      },
      {
        "WorkoutId": 45,
        "StartDate": "2022-04-21",
        "TopSets": [
          {
            "TopSetId": 79,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 45,
            "Repetitions": 10
          },
          {
            "TopSetId": 80,
            "ExerciseId": 3,
            "ExerciseName": "Deadlift",
            "Weight": 100,
            "Repetitions": 10
          }
        ]
      },
      {
        "WorkoutId": 46,
        "StartDate": "2022-04-26",
        "TopSets": [
          {
            "TopSetId": 81,
            "ExerciseId": 1,
            "ExerciseName": "Squat",
            "Weight": 80,
            "Repetitions": 3
          }
        ]
      },
      {
        "WorkoutId": 47,
        "StartDate": "2022-04-28",
        "TopSets": [
          {
            "TopSetId": 82,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 60,
            "Repetitions": 2
          },
          {
            "TopSetId": 83,
            "ExerciseId": 3,
            "ExerciseName": "Deadlift",
            "Weight": 100,
            "Repetitions": 5
          }
        ]
      },
      {
        "WorkoutId": 48,
        "StartDate": "2022-05-03",
        "TopSets": [
          {
            "TopSetId": 84,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 55,
            "Repetitions": 4
          },
          {
            "TopSetId": 85,
            "ExerciseId": 3,
            "ExerciseName": "Deadlift",
            "Weight": 95,
            "Repetitions": 7
          }
        ]
      },
      {
        "WorkoutId": 49,
        "StartDate": "2022-05-05",
        "TopSets": [
          {
            "TopSetId": 86,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 55,
            "Repetitions": 4
          },
          {
            "TopSetId": 87,
            "ExerciseId": 3,
            "ExerciseName": "Deadlift",
            "Weight": 110,
            "Repetitions": 7
          }
        ]
      },
      {
        "WorkoutId": 50,
        "StartDate": "2022-05-17",
        "TopSets": [
          {
            "TopSetId": 88,
            "ExerciseId": 1,
            "ExerciseName": "Squat",
            "Weight": 60,
            "Repetitions": 3
          },
          {
            "TopSetId": 89,
            "ExerciseId": 4,
            "ExerciseName": "Hotep",
            "Weight": 27,
            "Repetitions": 4
          }
        ]
      },
      {
        "WorkoutId": 51,
        "StartDate": "2022-05-19",
        "TopSets": [
          {
            "TopSetId": 90,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 65,
            "Repetitions": 1
          },
          {
            "TopSetId": 91,
            "ExerciseId": 3,
            "ExerciseName": "Deadlift",
            "Weight": 125,
            "Repetitions": 4
          }
        ]
      },
      {
        "WorkoutId": 52,
        "StartDate": "2022-06-07",
        "TopSets": [
          {
            "TopSetId": 92,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 55,
            "Repetitions": 4
          },
          {
            "TopSetId": 93,
            "ExerciseId": 3,
            "ExerciseName": "Deadlift",
            "Weight": 100,
            "Repetitions": 5
          }
        ]
      },
      {
        "WorkoutId": 53,
        "StartDate": "2022-06-14",
        "TopSets": [
          {
            "TopSetId": 94,
            "ExerciseId": 1,
            "ExerciseName": "Squat",
            "Weight": 75,
            "Repetitions": 2
          },
          {
            "TopSetId": 95,
            "ExerciseId": 4,
            "ExerciseName": "Hotep",
            "Weight": 31,
            "Repetitions": 4
          }
        ]
      },
      {
        "WorkoutId": 54,
        "StartDate": "2022-06-29",
        "TopSets": [
          {
            "TopSetId": 96,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 40,
            "Repetitions": 11
          }
        ]
      },
      {
        "WorkoutId": 55,
        "StartDate": "2022-07-07",
        "TopSets": [
          {
            "TopSetId": 97,
            "ExerciseId": 1,
            "ExerciseName": "Squat",
            "Weight": 65,
            "Repetitions": 5
          },
          {
            "TopSetId": 98,
            "ExerciseId": 4,
            "ExerciseName": "Hotep",
            "Weight": 30,
            "Repetitions": 6
          }
        ]
      },
      {
        "WorkoutId": 56,
        "StartDate": "2022-07-12",
        "TopSets": [
          {
            "TopSetId": 99,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 60,
            "Repetitions": 4
          },
          {
            "TopSetId": 100,
            "ExerciseId": 3,
            "ExerciseName": "Deadlift",
            "Weight": 100,
            "Repetitions": 9
          }
        ]
      },
      {
        "WorkoutId": 57,
        "StartDate": "2022-07-15",
        "TopSets": [
          {
            "TopSetId": 101,
            "ExerciseId": 1,
            "ExerciseName": "Squat",
            "Weight": 75,
            "Repetitions": 6
          },
          {
            "TopSetId": 102,
            "ExerciseId": 4,
            "ExerciseName": "Hotep",
            "Weight": 35,
            "Repetitions": 3
          }
        ]
      }
    ]
  },
  {
    "PersonId": 2,
    "PersonName": "Michael",
    "Workouts": [
      {
        "WorkoutId": 10,
        "StartDate": "2022-01-13",
        "TopSets": [
          {
            "TopSetId": 13,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 45,
            "Repetitions": 7
          },
          {
            "TopSetId": 14,
            "ExerciseId": 3,
            "ExerciseName": "Deadlift",
            "Weight": 115,
            "Repetitions": 5
          }
        ]
      },
      {
        "WorkoutId": 11,
        "StartDate": "2022-01-18",
        "TopSets": [
          {
            "TopSetId": 15,
            "ExerciseId": 1,
            "ExerciseName": "Squat",
            "Weight": 55,
            "Repetitions": 10
          },
          {
            "TopSetId": 16,
            "ExerciseId": 4,
            "ExerciseName": "Hotep",
            "Weight": 30,
            "Repetitions": 10
          }
        ]
      },
      {
        "WorkoutId": 12,
        "StartDate": "2022-01-20",
        "TopSets": [
          {
            "TopSetId": 17,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 50,
            "Repetitions": 3
          },
          {
            "TopSetId": 18,
            "ExerciseId": 3,
            "ExerciseName": "Deadlift",
            "Weight": 115,
            "Repetitions": 10
          }
        ]
      },
      {
        "WorkoutId": 13,
        "StartDate": "2022-01-25",
        "TopSets": [
          {
            "TopSetId": 19,
            "ExerciseId": 1,
            "ExerciseName": "Squat",
            "Weight": 6,
            "Repetitions": 65
          },
          {
            "TopSetId": 20,
            "ExerciseId": 4,
            "ExerciseName": "Hotep",
            "Weight": 35,
            "Repetitions": 7
          }
        ]
      },
      {
        "WorkoutId": 15,
        "StartDate": "2022-01-27",
        "TopSets": [
          {
            "TopSetId": 21,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 55,
            "Repetitions": 1
          },
          {
            "TopSetId": 22,
            "ExerciseId": 3,
            "ExerciseName": "Deadlift",
            "Weight": 125,
            "Repetitions": 5
          }
        ]
      },
      {
        "WorkoutId": 16,
        "StartDate": "2022-02-01",
        "TopSets": [
          {
            "TopSetId": 23,
            "ExerciseId": 1,
            "ExerciseName": "Squat",
            "Weight": 75,
            "Repetitions": 5
          },
          {
            "TopSetId": 24,
            "ExerciseId": 4,
            "ExerciseName": "Hotep",
            "Weight": 40,
            "Repetitions": 5
          }
        ]
      },
      {
        "WorkoutId": 17,
        "StartDate": "2022-02-03",
        "TopSets": [
          {
            "TopSetId": 25,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 55,
            "Repetitions": 2
          },
          {
            "TopSetId": 26,
            "ExerciseId": 3,
            "ExerciseName": "Deadlift",
            "Weight": 135,
            "Repetitions": 3
          }
        ]
      },
      {
        "WorkoutId": 18,
        "StartDate": "2022-02-08",
        "TopSets": [
          {
            "TopSetId": 27,
            "ExerciseId": 1,
            "ExerciseName": "Squat",
            "Weight": 80,
            "Repetitions": 2
          },
          {
            "TopSetId": 28,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 50,
            "Repetitions": 3
          }
        ]
      },
      {
        "WorkoutId": 19,
        "StartDate": "2022-02-15",
        "TopSets": [
          {
            "TopSetId": 29,
            "ExerciseId": 1,
            "ExerciseName": "Squat",
            "Weight": 80,
            "Repetitions": 5
          },
          {
            "TopSetId": 30,
            "ExerciseId": 4,
            "ExerciseName": "Hotep",
            "Weight": 45,
            "Repetitions": 3
          }
        ]
      },
      {
        "WorkoutId": 20,
        "StartDate": "2022-02-17",
        "TopSets": [
          {
            "TopSetId": 31,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 60,
            "Repetitions": 1
          },
          {
            "TopSetId": 32,
            "ExerciseId": 3,
            "ExerciseName": "Deadlift",
            "Weight": 150,
            "Repetitions": 2
          }
        ]
      },
      {
        "WorkoutId": 21,
        "StartDate": "2022-03-01",
        "TopSets": [
          {
            "TopSetId": 33,
            "ExerciseId": 1,
            "ExerciseName": "Squat",
            "Weight": 75,
            "Repetitions": 7
          },
          {
            "TopSetId": 34,
            "ExerciseId": 4,
            "ExerciseName": "Hotep",
            "Weight": 45,
            "Repetitions": 4
          }
        ]
      },
      {
        "WorkoutId": 22,
        "StartDate": "2022-03-10",
        "TopSets": [
          {
            "TopSetId": 35,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 45,
            "Repetitions": 10
          },
          {
            "TopSetId": 36,
            "ExerciseId": 3,
            "ExerciseName": "Deadlift",
            "Weight": 100,
            "Repetitions": 10
          }
        ]
      },
      {
        "WorkoutId": 23,
        "StartDate": "2022-03-15",
        "TopSets": [
          {
            "TopSetId": 37,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 55,
            "Repetitions": 2
          },
          {
            "TopSetId": 38,
            "ExerciseId": 3,
            "ExerciseName": "Deadlift",
            "Weight": 120,
            "Repetitions": 2
          }
        ]
      },
      {
        "WorkoutId": 24,
        "StartDate": "2022-03-22",
        "TopSets": [
          {
            "TopSetId": 39,
            "ExerciseId": 1,
            "ExerciseName": "Squat",
            "Weight": 60,
            "Repetitions": 5
          },
          {
            "TopSetId": 40,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 40,
            "Repetitions": 5
          }
        ]
      },
      {
        "WorkoutId": 25,
        "StartDate": "2022-04-12",
        "TopSets": [
          {
            "TopSetId": 41,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 55,
            "Repetitions": 1
          },
          {
            "TopSetId": 42,
            "ExerciseId": 3,
            "ExerciseName": "Deadlift",
            "Weight": 130,
            "Repetitions": 1
          }
        ]
      },
      {
        "WorkoutId": 26,
        "StartDate": "2022-04-21",
        "TopSets": [
          {
            "TopSetId": 43,
            "ExerciseId": 1,
            "ExerciseName": "Squat",
            "Weight": 60,
            "Repetitions": 4
          },
          {
            "TopSetId": 44,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 50,
            "Repetitions": 3
          }
        ]
      },
      {
        "WorkoutId": 27,
        "StartDate": "2022-04-26",
        "TopSets": [
          {
            "TopSetId": 45,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 55,
            "Repetitions": 2
          },
          {
            "TopSetId": 46,
            "ExerciseId": 3,
            "ExerciseName": "Deadlift",
            "Weight": 125,
            "Repetitions": 1
          }
        ]
      },
      {
        "WorkoutId": 28,
        "StartDate": "2022-04-28",
        "TopSets": [
          {
            "TopSetId": 47,
            "ExerciseId": 1,
            "ExerciseName": "Squat",
            "Weight": 80,
            "Repetitions": 2
          },
          {
            "TopSetId": 48,
            "ExerciseId": 4,
            "ExerciseName": "Hotep",
            "Weight": 42,
            "Repetitions": 2
          }
        ]
      },
      {
        "WorkoutId": 29,
        "StartDate": "2022-05-03",
        "TopSets": [
          {
            "TopSetId": 49,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 47,
            "Repetitions": 3
          },
          {
            "TopSetId": 50,
            "ExerciseId": 3,
            "ExerciseName": "Deadlift",
            "Weight": 130,
            "Repetitions": 2
          }
        ]
      },
      {
        "WorkoutId": 30,
        "StartDate": "2022-05-05",
        "TopSets": [
          {
            "TopSetId": 51,
            "ExerciseId": 1,
            "ExerciseName": "Squat",
            "Weight": 80,
            "Repetitions": 5
          },
          {
            "TopSetId": 52,
            "ExerciseId": 4,
            "ExerciseName": "Hotep",
            "Weight": 44,
            "Repetitions": 4
          }
        ]
      },
      {
        "WorkoutId": 31,
        "StartDate": "2022-05-17",
        "TopSets": [
          {
            "TopSetId": 53,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 55,
            "Repetitions": 3
          },
          {
            "TopSetId": 54,
            "ExerciseId": 3,
            "ExerciseName": "Deadlift",
            "Weight": 140,
            "Repetitions": 2
          }
        ]
      },
      {
        "WorkoutId": 32,
        "StartDate": "2022-05-19",
        "TopSets": [
          {
            "TopSetId": 55,
            "ExerciseId": 2,
            "ExerciseName": "Bench",
            "Weight": 55,
            "Repetitions": 2
          },
          {
            "TopSetId": 56,
            "ExerciseId": 3,
            "ExerciseName": "Deadlift",
            "Weight": 100,
            "Repetitions": 5
          }
        ]
      },
      {
        "WorkoutId": 33,
        "StartDate": "2022-06-07",
        "TopSets": [
          {
            "TopSetId": 57,
            "ExerciseId": 1,
            "ExerciseName": "Squat",
            "Weight": 85,
            "Repetitions": 3
          },
          {
            "TopSetId": 58,
            "ExerciseId": 4,
            "ExerciseName": "Hotep",
            "Weight": 45,
            "Repetitions": 5
          }
        ]
      },
      {
        "WorkoutId": 34,
        "StartDate": "2022-06-14",
        "TopSets": [
          {
            "TopSetId": 59,
            "ExerciseId": 3,
            "ExerciseName": "Deadlift",
            "Weight": 120,
            "Repetitions": 6
          },
          {
            "TopSetId": 60,
            "ExerciseId": 4,
            "ExerciseName": "Hotep",
            "Weight": 45,
            "Repetitions": 5
          }
        ]
      }
    ]
  }
]
In [26]:
gabe_topsts = [t for t in topsets if t['PersonId'] == 1]
In [63]:
gabe_exercises = get_all_exercises_from_topsets(gabe_topsts)
gabe_rep_maxes = []
for e in gabe_exercises:
    exercise_topsets = [t for t in gabe_topsts if t['ExerciseId'] == e['ExerciseId']]
    set_reps = set([t['Repetitions'] for t in exercise_topsets])

    topsets_for_exercise = []
    for rep in set_reps:
        reps = [t for t in exercise_topsets if t['Repetitions'] == rep]
        max_weight = max([t['Weight'] for t in reps])
        max_topset_for_rep = [t for t in reps if t['Weight'] == max_weight]
        topsets_for_exercise.append({
            'StartDate': max_topset_for_rep[0]['StartDate'],
            'Repetitions': rep,
            'Weight': max_weight
        })
    
    topsets_for_exercise.sort(key=lambda x: datetime.strptime(x['StartDate'],"%Y-%m-%d"))
    
    gabe_rep_maxes.append({
            'ExerciseId': e['ExerciseId'],
            'ExerciseName': e['ExerciseName'],
            'RepMaxes': topsets_for_exercise,
        })
In [65]:
def get_rep_maxes_for_person(person_topsets):
    person_exercises = get_all_exercises_from_topsets(person_topsets)

    rep_maxes_in_exercises = []
    for e in person_exercises:
        exercise_topsets = [
            t for t in person_topsets if t['ExerciseId'] == e['ExerciseId']]
        set_reps = set([t['Repetitions'] for t in exercise_topsets])

        topsets_for_exercise = []
        for rep in set_reps:
            reps = [t for t in exercise_topsets if t['Repetitions'] == rep]
            max_weight = max([t['Weight'] for t in reps])
            max_topset_for_rep = [t for t in reps if t['Weight'] == max_weight]
            topsets_for_exercise.append({
                'StartDate': max_topset_for_rep[0]['StartDate'],
                'Repetitions': rep,
                'Weight': max_weight
            })

        topsets_for_exercise.sort(
            key=lambda x: datetime.strptime(x['StartDate'], "%Y-%m-%d"))

        rep_maxes_in_exercises.append({
            'ExerciseId': e['ExerciseId'],
            'ExerciseName': e['ExerciseName'],
            'RepMaxes': topsets_for_exercise,
        })
    return rep_maxes_in_exercises
In [66]:
get_rep_maxes_for_person(gabe_topsts)
Out [66]:
[{'ExerciseId': 1,
  'ExerciseName': 'Squat',
  'RepMaxes': [{'StartDate': '2022-01-18', 'Repetitions': 7, 'Weight': 55},
   {'StartDate': '2022-03-15', 'Repetitions': 5, 'Weight': 75},
   {'StartDate': '2022-04-07', 'Repetitions': 6, 'Weight': 75},
   {'StartDate': '2022-04-26', 'Repetitions': 3, 'Weight': 80},
   {'StartDate': '2022-06-14', 'Repetitions': 2, 'Weight': 75}]},
 {'ExerciseId': 2,
  'ExerciseName': 'Bench',
  'RepMaxes': [{'StartDate': '2022-01-13', 'Repetitions': 8, 'Weight': 50},
   {'StartDate': '2022-02-08', 'Repetitions': 5, 'Weight': 55},
   {'StartDate': '2022-02-17', 'Repetitions': 2, 'Weight': 60},
   {'StartDate': '2022-03-10', 'Repetitions': 11, 'Weight': 50},
   {'StartDate': '2022-03-22', 'Repetitions': 4, 'Weight': 60},
   {'StartDate': '2022-04-21', 'Repetitions': 10, 'Weight': 45},
   {'StartDate': '2022-05-19', 'Repetitions': 1, 'Weight': 65}]},
 {'ExerciseId': 3,
  'ExerciseName': 'Deadlift',
  'RepMaxes': [{'StartDate': '2022-02-08', 'Repetitions': 6, 'Weight': 95},
   {'StartDate': '2022-02-17', 'Repetitions': 8, 'Weight': 105},
   {'StartDate': '2022-04-21', 'Repetitions': 10, 'Weight': 100},
   {'StartDate': '2022-04-28', 'Repetitions': 5, 'Weight': 100},
   {'StartDate': '2022-05-05', 'Repetitions': 7, 'Weight': 110},
   {'StartDate': '2022-05-19', 'Repetitions': 4, 'Weight': 125},
   {'StartDate': '2022-07-12', 'Repetitions': 9, 'Weight': 100}]},
 {'ExerciseId': 4,
  'ExerciseName': 'Hotep',
  'RepMaxes': [{'StartDate': '2022-03-15', 'Repetitions': 5, 'Weight': 30},
   {'StartDate': '2022-04-07', 'Repetitions': 2, 'Weight': 35},
   {'StartDate': '2022-06-14', 'Repetitions': 4, 'Weight': 31},
   {'StartDate': '2022-07-07', 'Repetitions': 6, 'Weight': 30},
   {'StartDate': '2022-07-15', 'Repetitions': 3, 'Weight': 35}]}]
In [67]:
def get_people_and_exercise_rep_maxes(topsets):
    # Get all unique workout_ids (No duplicates)
    people_ids = set([t['PersonId'] for t in topsets])

    # Group topsets into workouts
    people = []
    for person_id in people_ids:
        workouts_for_person = [t for t in topsets if t['PersonId'] == person_id]
        people.append({
            'PersonId': person_id,
            'PersonName': workouts_for_person[0]['PersonName'],
            'Exercises': get_rep_maxes_for_person(workouts_for_person)
        })
    return people
In [69]:
get_people_and_exercise_rep_maxes(all_topsets)
Out [69]:
[{'PersonId': 1,
  'PersonName': 'Gabe',
  'Exercises': [{'ExerciseId': 1,
    'ExerciseName': 'Squat',
    'RepMaxes': [{'StartDate': '2022-01-18', 'Repetitions': 7, 'Weight': 55},
     {'StartDate': '2022-03-15', 'Repetitions': 5, 'Weight': 75},
     {'StartDate': '2022-04-07', 'Repetitions': 6, 'Weight': 75},
     {'StartDate': '2022-04-26', 'Repetitions': 3, 'Weight': 80},
     {'StartDate': '2022-06-14', 'Repetitions': 2, 'Weight': 75}]},
   {'ExerciseId': 2,
    'ExerciseName': 'Bench',
    'RepMaxes': [{'StartDate': '2022-01-13', 'Repetitions': 8, 'Weight': 50},
     {'StartDate': '2022-02-08', 'Repetitions': 5, 'Weight': 55},
     {'StartDate': '2022-02-17', 'Repetitions': 2, 'Weight': 60},
     {'StartDate': '2022-03-10', 'Repetitions': 11, 'Weight': 50},
     {'StartDate': '2022-03-22', 'Repetitions': 4, 'Weight': 60},
     {'StartDate': '2022-04-21', 'Repetitions': 10, 'Weight': 45},
     {'StartDate': '2022-05-19', 'Repetitions': 1, 'Weight': 65}]},
   {'ExerciseId': 3,
    'ExerciseName': 'Deadlift',
    'RepMaxes': [{'StartDate': '2022-02-08', 'Repetitions': 6, 'Weight': 95},
     {'StartDate': '2022-02-17', 'Repetitions': 8, 'Weight': 105},
     {'StartDate': '2022-04-21', 'Repetitions': 10, 'Weight': 100},
     {'StartDate': '2022-04-28', 'Repetitions': 5, 'Weight': 100},
     {'StartDate': '2022-05-05', 'Repetitions': 7, 'Weight': 110},
     {'StartDate': '2022-05-19', 'Repetitions': 4, 'Weight': 125},
     {'StartDate': '2022-07-12', 'Repetitions': 9, 'Weight': 100}]},
   {'ExerciseId': 4,
    'ExerciseName': 'Hotep',
    'RepMaxes': [{'StartDate': '2022-03-15', 'Repetitions': 5, 'Weight': 30},
     {'StartDate': '2022-04-07', 'Repetitions': 2, 'Weight': 35},
     {'StartDate': '2022-06-14', 'Repetitions': 4, 'Weight': 31},
     {'StartDate': '2022-07-07', 'Repetitions': 6, 'Weight': 30},
     {'StartDate': '2022-07-15', 'Repetitions': 3, 'Weight': 35}]}]},
 {'PersonId': 2,
  'PersonName': 'Michael',
  'Exercises': [{'ExerciseId': 1,
    'ExerciseName': 'Squat',
    'RepMaxes': [{'StartDate': '2022-01-18', 'Repetitions': 10, 'Weight': 55},
     {'StartDate': '2022-01-25', 'Repetitions': 65, 'Weight': 6},
     {'StartDate': '2022-02-08', 'Repetitions': 2, 'Weight': 80},
     {'StartDate': '2022-02-15', 'Repetitions': 5, 'Weight': 80},
     {'StartDate': '2022-03-01', 'Repetitions': 7, 'Weight': 75},
     {'StartDate': '2022-04-21', 'Repetitions': 4, 'Weight': 60},
     {'StartDate': '2022-06-07', 'Repetitions': 3, 'Weight': 85}]},
   {'ExerciseId': 2,
    'ExerciseName': 'Bench',
    'RepMaxes': [{'StartDate': '2022-01-13', 'Repetitions': 7, 'Weight': 45},
     {'StartDate': '2022-02-03', 'Repetitions': 2, 'Weight': 55},
     {'StartDate': '2022-02-17', 'Repetitions': 1, 'Weight': 60},
     {'StartDate': '2022-03-10', 'Repetitions': 10, 'Weight': 45},
     {'StartDate': '2022-03-22', 'Repetitions': 5, 'Weight': 40},
     {'StartDate': '2022-05-17', 'Repetitions': 3, 'Weight': 55}]},
   {'ExerciseId': 3,
    'ExerciseName': 'Deadlift',
    'RepMaxes': [{'StartDate': '2022-01-20', 'Repetitions': 10, 'Weight': 115},
     {'StartDate': '2022-01-27', 'Repetitions': 5, 'Weight': 125},
     {'StartDate': '2022-02-03', 'Repetitions': 3, 'Weight': 135},
     {'StartDate': '2022-02-17', 'Repetitions': 2, 'Weight': 150},
     {'StartDate': '2022-04-12', 'Repetitions': 1, 'Weight': 130},
     {'StartDate': '2022-06-14', 'Repetitions': 6, 'Weight': 120}]},
   {'ExerciseId': 4,
    'ExerciseName': 'Hotep',
    'RepMaxes': [{'StartDate': '2022-01-18', 'Repetitions': 10, 'Weight': 30},
     {'StartDate': '2022-01-25', 'Repetitions': 7, 'Weight': 35},
     {'StartDate': '2022-02-15', 'Repetitions': 3, 'Weight': 45},
     {'StartDate': '2022-03-01', 'Repetitions': 4, 'Weight': 45},
     {'StartDate': '2022-04-28', 'Repetitions': 2, 'Weight': 42},
     {'StartDate': '2022-06-07', 'Repetitions': 5, 'Weight': 45}]}]}]