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


Generating FitCypher web logos with AI

fitcypher

I need a logo for the FitCypher app and I am a hopeless artist so I’m using Meta AI image generation to come up with a logo, here’s a few I’ve generated

So far this is the one I’ve chosen to go with but I am open to suggestions :

Try out FitCypher here :

https://alexlaverty.pythonanywhere.com/

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

https://github.com/alexlaverty/fitcypher


New Django Project

fitcypher

Creating a new Django Project

Creating the FitCypher Django Project

I switch between linux and windows desktops so the commands will be whatever OS I’m on at the time.

Creating a new python virtual environment and activating it

D:\src\fitcypher>virtualenv env
D:\src\fitcypher>env\Scripts\activate.bat
# Install Django
pip install django

# Create a new project
django-admin startproject fitcypher

# Navigate to the project directory
cd fitcypher

# Create a new app
python manage.py startapp api

# Add the 'api' to INSTALLED_APPS in settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'api'
]

# Run initial migrations
python manage.py migrate

# Start the development server
python manage.py runserver

After that browse the local website :

http://127.0.0.1:8000/

and then hey presto we have lift off :

alt text

Deploying FitCypher to Render.com

Once you’ve built the site and pushed the code to github you need somewhere to deploy and host the website.

I’ve used Render.com before and it will monitor the github repo, and if there is a new commit it will redeploy the website with the latest code.

I’ve deployed before via docker container but I’ll give it a go trying to run the django website directly on render, we’ll see how it goes.

Going to follow the documentation here https://render.com/docs/deploy-django

pip install psycopg2-binary
pip install dj-database-url

On second thought I’m going to try out PythonAnywhere

When I tried Render free tier, first things I noticed were the website goes to sleep if it’s not receiving traffic and when it’s accessed the next time the website has to wake up which takes time and can even time out on the first attempt. Also the database is scheduled deletion every month which means having to setup the database again. It was pretty annoying.

Seems PythonAnywhere will not go to sleep and as long as you log in and click a button saying you’re still using the website it’ll extend for another 3 months, not sure what the go is with the database for free tier.

Hmmm so Render.com has a much nicer setup, you can pretty much auth to Github and click a repo and it’ll do a webhook on commit to trigger and deployment, where as PythonAnywhere is much more basic, and you basically get a virtual server and ssh console access to login, and you need to git clone your repo, manually git pull and then go into the UI and click reload to make the changes take effect, might have to look into more if there’s better ways of triggering deployment on git commit.

So the basic FitCypher django project is available here :

https://alexlaverty.pythonanywhere.com/

I also provisioned a MySQL database on PythonAnywhere, it also had PostGres DB but they required a premium account so I’ve gone with MySQL.

Try out FitCypher here :

https://alexlaverty.pythonanywhere.com/

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

https://github.com/alexlaverty/fitcypher