Quick Body Weight Workout

fitcypher

Now we’ve added a page to show a list of available Workouts to choose from :

alt text

Each time the user performs an exercise they can click the exercise and it will add an entry for today for that exercise and display a total count of exercises performed per day for that exercise :

alt text

I found that with this approach of creating an entry per exercise rep performed the entries page quickly became cluttered with individual reps, so I’ve updated the Entries page to group the exercises by name and provide a count of total exercises :

alt text

Try out FitCypher here :

https://alexlaverty.pythonanywhere.com/

Or git clone the FitCypher github repo and run it locally :

https://github.com/alexlaverty/fitcypher


REST API

fitcypher

We will use Django Rest Framework as the API framework to interact with this model.

Using API’s allows to either add entries in bulk, allow users to export and import from other systems, allow for automation and scheduled data syncing.

To make the API friendly to use we’ll provide an API UI :

alt text

Rest API Authentication

For now we will just use basic authentication, username and password, however in the future we’ll implement some better authentication methods like token authentication.

FitCypher API Curl Commands

GET

Curl Command :

curl - X GET http: //127.0.0.1:8000/api/entries/ -u your_username:your_password

JSON Response :

    [{
        "id": 1,
        "user": {
            "id": 1,
            "username": "alex"
        },
        "date": "2025-02-02T07:51:00Z",
        "tracking": "Food",
        "string_value": "Apple",
        "numerical_value": null,
        "notes": "",
        "tags": "",
        "source": "FitCypher"
    }, {
        "id": 2,
        "user": {
            "id": 1,
            "username": "alex"
        },
        "date": "2025-02-02T07:52:00Z",
        "tracking": "Exercise",
        "string_value": "Push Ups",
        "numerical_value": "10.00",
        "notes": "",
        "tags": "",
        "source": "FitCypher"
    }]

If you install JQ you can also get pretty printed output via :

curl -s -X GET http://127.0.0.1:8000/api/entries/ -u your_username:your_password | jq
[
  {
    "id": 1,
    "user": {
      "id": 1,
      "username": "alex"
    },
    "date": "2025-02-02T07:51:00Z",
    "tracking": "Food",
    "string_value": "Apple",
    "numerical_value": null,
    "notes": "",
    "tags": "",
    "source": "FitCypher"
  },
  {
    "id": 2,
    "user": {
      "id": 1,
      "username": "alex"
    },
    "date": "2025-02-02T07:52:00Z",
    "tracking": "Exercise",
    "string_value": "Push Ups",
    "numerical_value": "10.00",
    "notes": "",
    "tags": "",
    "source": "FitCypher"
  },
  {
    "id": 3,
    "user": {
      "id": 1,
      "username": "alex"
    },
    "date": "2023-10-15T12:00:00Z",
    "tracking": "weight",
    "string_value": null,
    "numerical_value": "70.50",
    "notes": "After breakfast",
    "tags": "morning",
    "source": "fitcypher"
  }
]

POST

Add a new entry via the API

curl -X POST http://127.0.0.1:8000/api/entries/ \
-H "Content-Type: application/json" \
-u your_username:your_password \
-d '{
    "date": "2023-10-15T12:00:00Z",
    "tracking": "weight",
    "numerical_value": 70.5,
    "notes": "After breakfast",
    "tags": "morning",
    "source": "fitcypher"
}'

Add a new entry via the API to the PythonAnywhere hosted instance :

curl -X POST https://alexlaverty.pythonanywhere.com/api/entries/ \
-H "Content-Type: application/json" \
-u your_username:your_password \
-d '{
    "date": "2023-10-15T12:00:00Z",
    "tracking": "food",
    "string_value": "Banana",
    "numerical_value": "",
    "notes": "",
    "tags": "",
    "source": "fitcypher"
}'

Try out FitCypher here :

https://alexlaverty.pythonanywhere.com/

Or git clone the FitCypher github repo and run it locally :

https://github.com/alexlaverty/fitcypher


Django Model

fitcypher

Today I am working on the FitCypher database backend, to keep it simple the nutrition and health metrics will be posted into a common Entry model :

class Entry(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="entries")
    date = models.DateTimeField()
    tracking = models.CharField(max_length=255)
    string_value = models.CharField(max_length=255, null=True, blank=True)
    numerical_value = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    notes = models.TextField(null=True, blank=True)
    tags = models.CharField(max_length=255, null=True, blank=True)
    source = models.TextField(null=True, blank=True, default="fitcypher")

    def __str__(self):
        return f"{self.date.strftime('%Y-%m-%d')}, {self.user}, {self.string_value}"

This Entry model is a flexible and generic way to store various health and fitness metrics for users.

Below is an explanation of each field and its purpose:


1. user

   user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="entries")
  • Purpose: This field establishes a relationship between the Entry and the User model. It indicates which user the entry belongs to.
  • Details:
    • on_delete=models.CASCADE: If the user is deleted, all their associated entries will also be deleted.
    • related_name="entries": This allows you to access all entries for a specific user using user.entries.

2. date

   date = models.DateTimeField()
  • Purpose: This field stores the date and time when the entry was recorded.
  • Details:
    • It is essential for tracking when a specific health metric was logged (e.g., weight on a particular day, steps taken on a specific date).

3. tracking

   tracking = models.CharField(max_length=255)
  • Purpose: This field specifies what type of health or fitness metric is being tracked (e.g., “weight”, “steps”, “calories”, “heart_rate”).
  • Details:
    • It acts as a label or category for the entry, allowing you to differentiate between different types of metrics.

4. string_value

   string_value = models.CharField(max_length=255, null=True, blank=True)
  • Purpose: This field stores a textual value for the tracked metric, if applicable.
  • Details:
    • It is optional (null=True, blank=True) because not all metrics will have a textual value.
    • Example: If tracking="mood", string_value could be “happy” or “stressed”.

5. numerical_value

   numerical_value = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
  • Purpose: This field stores a numerical value for the tracked metric, if applicable.
  • Details:
    • It is optional (null=True, blank=True) because not all metrics will have a numerical value.
    • Example: If tracking="weight", numerical_value could be 70.5 (in kg).

6. notes

   notes = models.TextField(null=True, blank=True)
  • Purpose: This field allows users to add additional comments or details about the entry.
  • Details:
    • It is optional (null=True, blank=True).
    • Example: If tracking="workout", notes could describe the type of workout performed (e.g., “30 minutes of cardio and 20 minutes of strength training”).

7. tags

   tags = models.CharField(max_length=255, null=True, blank=True)
  • Purpose: This field allows users to add tags or keywords to categorize or filter entries.
  • Details:
    • It is optional (null=True, blank=True).
    • Example: Tags like “morning”, “evening”, “high-intensity”, or “low-carb” can help organize entries.

8. source

   source = models.TextField(null=True, blank=True, default="fitcypher")
  • Purpose: This field indicates the source of the entry (e.g., a specific app, device, or manual entry).
  • Details:
    • It has a default value of "fitcypher", which could be your app’s name.
    • Example: If the data is synced from a fitness tracker like Fitbit, source could be "Fitbit".

9. __str__ Method

   def __str__(self):
       return f"{self.date.strftime('%Y-%m-%d')}, {self.user}, {self.string_value}"
  • Purpose: This method provides a human-readable string representation of the Entry object.
  • Details:
    • It is useful for debugging, logging, or displaying the entry in the Django admin interface.
    • Example output: "2023-10-15, john_doe, 70.5".

Summary of Use Cases

  • Tracking Weight: tracking="weight", numerical_value=70.5, notes="After breakfast", tags="morning".
  • Tracking Mood: tracking="mood", string_value="happy", notes="Had a great workout".
  • Tracking Steps: tracking="steps", numerical_value=10000, source="Fitbit".

This model is highly flexible and can accommodate a wide range of health and fitness metrics, making it a great foundation for a simple health and fitness tracker.

We will use Django Rest Framework as the API framework to interact with this model.

To make the API friendly to use we’ll provide an API UI :

alt text

Try out FitCypher here :

https://alexlaverty.pythonanywhere.com/

Or git clone the FitCypher github repo and run it locally :

https://github.com/alexlaverty/fitcypher