Saturday, December 27, 2025

Develop a Calorie Counter

 Develop a Calorie Counter

Develop a Calorie Counter that can be used to estimate the number of calories a person needs to consume each day. This calculator can also provide some simple guidelines for gaining or losing weight. Users can also keep track of how many calories he/she needs and how much he/she consumes in a day. To calculate calories, we have two formulas: 

For a male 
BMR= 66.47+(13.75 x weight in kg) + (5.003 x height in cm) - (6.755 x age in years) 

For a female 
BMR=655.1+(9.563 x weight in kg)+(1.850 xheight in cm) - (4.676 x age in years) 

Job Specification information: 

1. Create a new Django project named Name_ID_CaloryCounter and a Calorie Counter app. 
2. Define your Calorie Counter models. 
3. Create views for Login (username/email and password) and Registration (username, email, password, confirm password) pages. 
4. Create a django-form to take input Name, Age, Gender, Height, Weight etc. 
5. Create a Django form to take input daily consumed calories (Item name, Calorie consumed) 
6. Create a dashboard where the user can view the required calories for her/him and the consumed calories daily. 
7. Define URL Patterns and configure project-level URLs. 
8. Implement the required Function and Logic in the view.py file. 

Job Specification information: 

a. Create a new Django project. (Naming Convention: Name_ID_CaloryCounter) 
b. Run migration to create the data tables. 
c. Create a super user. (username: admin, password: 1234) 
d. Register your models to the Django admin.


models.py
from django.db import models
from django.contrib.auth.models import User
from datetime import date
from django.utils import timezone

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    name = models.CharField(max_length=100, default='')
    age = models.IntegerField(default=25)
    GENDER_CHOICES = [
        ('M', 'Male'),
        ('F', 'Female'),
    ]
    gender = models.CharField(max_length=1, choices=GENDER_CHOICES, default='M')
    height = models.FloatField(help_text="Height in cm", default=170.0)
    weight = models.FloatField(help_text="Weight in kg", default=70.0)

    def __str__(self):
        return self.name

    def calculate_bmr(self):
        if self.gender == 'M':
            bmr = 66.47 + (13.75 * self.weight) + (5.003 * self.height) - (6.755 * self.age)
        else:
            bmr = 655.1 + (9.563 * self.weight) + (1.850 * self.height) - (4.676 * self.age)
        return round(bmr, 2)

class CalorieEntry(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    food_item = models.CharField(max_length=100, null=True)
    calories_consumed = models.FloatField()
    date = models.DateField(default=date.today)
    time = models.TimeField(default=timezone.now)

    def __str__(self):
        return f"{self.food_item} - {self.calories_consumed} cal"


forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from .models import UserProfile, CalorieEntry

class UserProfileForm(forms.ModelForm):
    class Meta:
        model = UserProfile
        fields = ['name', 'age', 'gender', 'height', 'weight']
        widgets = {
            'name': forms.TextInput(attrs={'class': 'form-control'}),
            'age': forms.NumberInput(attrs={'class': 'form-control'}),
            'gender': forms.Select(attrs={'class': 'form-select'}),
            'height': forms.NumberInput(attrs={'class': 'form-control'}),
            'weight': forms.NumberInput(attrs={'class': 'form-control'}),
        }

class CalorieEntryForm(forms.ModelForm):
    class Meta:
        model = CalorieEntry
        fields = ['food_item', 'calories_consumed', 'date', 'time']
        widgets = {
            'food_item': forms.TextInput(attrs={'class': 'form-control'}),
            'calories_consumed': forms.NumberInput(attrs={'class': 'form-control'}),
            'date': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
            'time': forms.TimeInput(attrs={'type': 'time', 'class': 'form-control'}),
        }

class CustomUserCreationForm(UserCreationForm):
    email = forms.EmailField(required=True, widget=forms.EmailInput(attrs={'class': 'form-control'}))

    class Meta:
        model = User
        fields = ("username", "email", "password1", "password2")
        widgets = {
            'username': forms.TextInput(attrs={'class': 'form-control'}),
            'password1': forms.PasswordInput(attrs={'class': 'form-control'}),
            'password2': forms.PasswordInput(attrs={'class': 'form-control'}),
        }

    def save(self, commit=True):
        user = super().save(commit=False)
        user.email = self.cleaned_data["email"]
        if commit:
            user.save()
        return user


admin.py
from django.contrib import admin
from .models import UserProfile, CalorieEntry

@admin.register(UserProfile)
class UserProfileAdmin(admin.ModelAdmin):
    list_display = ('name', 'user', 'age', 'gender', 'height', 'weight')

@admin.register(CalorieEntry)
class CalorieEntryAdmin(admin.ModelAdmin):
    list_display = ('user', 'food_item', 'calories_consumed', 'date', 'time')
    list_filter = ('date', 'user')


views.py
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth import login, authenticate
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from .forms import UserProfileForm, CalorieEntryForm, CustomUserCreationForm
from .models import UserProfile, CalorieEntry
from datetime import date

def home(request):
    if request.user.is_authenticated:
        return redirect('calorie_counter:dashboard')
    else:
        return redirect('calorie_counter:login')

def register(request):
    if request.method == 'POST':
        form = CustomUserCreationForm(request.POST)
        if form.is_valid():
            user = form.save()
            login(request, user)
            messages.success(request, 'Registration successful.')
            return redirect('calorie_counter:profile_form')
    else:
        form = CustomUserCreationForm()
    return render(request, 'registration/register.html', {'form': form})

def login_view(request):
    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(request, username=username, password=password)
        if user is not None:
            login(request, user)
            return redirect("calorie_counter:dashboard")
        else:
            messages.error(request, "Invalid credentials.")
            return redirect("calorie_counter:login")
    return render(request, 'calorie_counter/login.html')

@login_required
def profile_form(request):
    profile, created = UserProfile.objects.get_or_create(user=request.user)
    if request.method == 'POST':
        form = UserProfileForm(request.POST, instance=profile)
        if form.is_valid():
            form.save()
            messages.success(request, 'Profile updated successfully.')
            return redirect('calorie_counter:dashboard')
    else:
        form = UserProfileForm(instance=profile)
    return render(request, 'calorie_counter/profile_form.html', {'form': form})

@login_required
def dashboard(request):
    try:
        profile = UserProfile.objects.get(user=request.user)
        bmr = profile.calculate_bmr()
        today = date.today()
        entries_today = CalorieEntry.objects.filter(user=request.user, date=today)
        total_consumed = sum(entry.calories_consumed for entry in entries_today)
        remaining = bmr - total_consumed
        context = {
            'bmr': bmr,
            'total_consumed': total_consumed,
            'remaining': remaining,
            'entries': entries_today,
        }
    except UserProfile.DoesNotExist:
        messages.warning(request, 'Please complete your profile first.')
        return redirect('calorie_counter:profile_form')
    return render(request, 'calorie_counter/dashboard.html', context)

@login_required
def add_calorie_entry(request):
    if request.method == 'POST':
        form = CalorieEntryForm(request.POST)
        if form.is_valid():
            entry = form.save(commit=False)
            entry.user = request.user
            entry.save()
            messages.success(request, 'Calorie entry added.')
            return redirect('calorie_counter:dashboard')
    else:
        form = CalorieEntryForm()
    return render(
        request,
        "calorie_counter/add_entry.html",
        {"form": form, "title": "Add Calorie Entry", 'submit': 'Add',},
    )

@login_required
def update_calorie_entry(request, pk):
    entry = get_object_or_404(CalorieEntry, pk=pk, user=request.user)
    if request.method == 'POST':
        form = CalorieEntryForm(request.POST, instance=entry)
        if form.is_valid():
            form.save()
            messages.success(request, 'Calorie entry updated.')
            return redirect('calorie_counter:dashboard')
    else:
        form = CalorieEntryForm(instance=entry)
    return render(
        request,
        "calorie_counter/add_entry.html",
        {
            "form": form,
            "title": "Edit Calorie Entry",
            "submit": "Update"
        },
    )

@login_required
def delete_calorie_entry(request, pk):
    entry = get_object_or_404(CalorieEntry, pk=pk, user=request.user)
    if request.method == 'POST':
        entry.delete()
        messages.success(request, 'Calorie entry deleted.')
        return redirect('calorie_counter:dashboard')
    return render(request, 'calorie_counter/delete_entry.html', {'entry': entry})

def logout_view(request):
    from django.contrib.auth import logout
    logout(request)
    return redirect('calorie_counter:login')

@login_required
def logout(request):
    logout(request)
    return redirect("calorie_counter:login")


urls.py
from django.urls import path
from . import views

app_name = 'calorie_counter'

urlpatterns = [
    path("", views.home, name="home"),
    path("register/", views.register, name="register"),
    path("login/", views.login_view, name="login"),
    path("profile/", views.profile_form, name="profile_form"),
    path("dashboard/", views.dashboard, name="dashboard"),
    path("add-entry/", views.add_calorie_entry, name="add_entry"),
    path("update-entry/<int:pk>/", views.update_calorie_entry, name="update_entry"),
    path("delete-entry/<int:pk>/", views.delete_calorie_entry, name="delete_entry"),
]


projects/urls.py

from django.contrib import admin
from django.urls import path, include
from django.contrib.auth import views as auth_views
from calorie_counter import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('calorie_counter.urls')),
    path('accounts/login/', auth_views.LoginView.as_view(template_name='registration/login.html'), name='login'),
    path('accounts/logout/', views.logout_view, name='logout'),
]


project Templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}Calorie Counter{% endblock %}</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <style>
        .regilog {
            text-decoration: none;
            color: #0d6efd;
        }
        .regilog:hover {
            color: #04aa94ff;
        }
    </style>
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-dark bg-primary">
        <div class="container">
            <a class="navbar-brand" href="{% url 'calorie_counter:dashboard' %}">Calorie Counter</a>
            <div class="navbar-nav ms-auto">
                {% if user.is_authenticated %}
                    <a class="nav-link" href="{% url 'calorie_counter:dashboard' %}">Dashboard</a>
                    <a class="nav-link" href="{% url 'calorie_counter:profile_form' %}">Profile</a>
                    <a class="nav-link" href="{% url 'logout' %}">Logout</a>
                {% else %}
                    <a class="nav-link" href="{% url 'calorie_counter:login' %}">Login</a>
                    <a class="nav-link" href="{% url 'calorie_counter:register' %}">Register</a>
                {% endif %}
            </div>
        </div>
    </nav>
    <div class="container mt-4">
        {% if messages %}
            {% for message in messages %}
                <div class="alert alert-{{ message.tags }}">{{ message }}</div>
            {% endfor %}
        {% endif %}
        {% block content %}{% endblock %}
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>


register/register.html
{% extends 'base.html' %}

{% block title %}Register{% endblock %}

{% block content %}
<div class="row justify-content-center">
    <div class="col-md-6">
        <h2>Register</h2>
        <form method="post">
            {% csrf_token %}
            <div class="mb-3">
                <label for="id_username" class="form-label">Username</label>
                <input type="text" class="form-control" id="id_username" name="username" required>
                {% if form.username.errors %}
                    <div class="text-danger">{{ form.username.errors }}</div>
                {% endif %}
            </div>
            <div class="mb-3">
                <label for="id_email" class="form-label">Email</label>
                <input type="email" class="form-control" id="id_email" name="email" required>
                {% if form.email.errors %}
                    <div class="text-danger">{{ form.email.errors }}</div>
                {% endif %}
            </div>
            <div class="mb-3">
                <label for="id_password1" class="form-label">Password</label>
                <input type="password" class="form-control" id="id_password1" name="password1" required>
                {% if form.password1.errors %}
                    <div class="text-danger">{{ form.password1.errors }}</div>
                {% endif %}
            </div>
            <div class="mb-3">
                <label for="id_password2" class="form-label">Password confirmation</label>
                <input type="password" class="form-control" id="id_password2" name="password2" required>
                {% if form.password2.errors %}
                    <div class="text-danger">{{ form.password2.errors }}</div>
                {% endif %}
            </div>
            <button type="submit" class="btn btn-primary">Register</button>
        </form>
        <div class="text-center mt-3">
            <p>Already have an account? <a class="regilog" href="{% url 'calorie_counter:login' %}"><b>Login here</b></a></p>
        </div>
    </div>
</div>
{% endblock %}


app template/calorie_counter/login.html
{% extends 'base.html' %}

{% block title %}Login{% endblock %}

{% block content %}
<div class="row justify-content-center">
    <div class="col-md-6">
        <h2>Login</h2>
        <form method="post">
            {% csrf_token %}
            <div class="mb-3">
                <label for="username" class="form-label">Username</label>
                <input type="text" class="form-control" id="username" name="username" required>
            </div>
            <div class="mb-3">
                <label for="password" class="form-label">Password</label>
                <input type="password" class="form-control" id="password" name="password" required>
            </div>
            <button type="submit" class="btn btn-primary">Login</button>
        </form>
        <div class="text-center mt-3">
            <p>Don't have an account? <a class="regilog" href="{% url 'calorie_counter:register' %}"><b>Register here</b></a></p>
        </div>
    </div>
</div>
{% endblock %}


dashboard.html
{% extends 'base.html' %}

{% block title %}Dashboard{% endblock %}

{% block content %}
<div class="row">
    <div class="col-md-8">
        <h2>Dashboard</h2>
        <div class="card mb-4">
            <div class="card-body">
                <h5 class="card-title">Daily Calorie Summary</h5>
                <p><strong>BMR:</strong> {{ bmr }} calories</p>
                <p><strong>Total Consumed Today:</strong> {{ total_consumed }} calories</p>
                <p><strong>Remaining:</strong> {{ remaining }} calories</p>
            </div>
        </div>
        <a href="{% url 'calorie_counter:add_entry' %}" class="btn btn-primary mb-4">Add Calorie Entry</a>
        <h3>Today's Entries</h3>
        {% if entries %}
            <table class="table">
                <thead>
                    <tr>
                        <th>Food Item</th>
                        <th>Calories Consumed</th>
                        <th>Time</th>
                        <th>Actions</th>
                    </tr>
                </thead>
                <tbody>
                    {% for entry in entries %}
                        <tr>
                            <td>{{ entry.food_item }}</td>
                            <td>{{ entry.calories_consumed }}</td>
                            <td>{{ entry.time }}</td>
                            <td>
                                <a href="{% url 'calorie_counter:update_entry' entry.pk %}" class="btn btn-sm btn-primary">Edit</a>
                                <a href="{% url 'calorie_counter:delete_entry' entry.pk %}" class="btn btn-sm btn-danger">Delete</a>
                            </td>
                        </tr>
                    {% endfor %}
                </tbody>
            </table>
        {% else %}
            <p>No entries for today.</p>
        {% endif %}
    </div>
</div>
{% endblock %}


profile.html
{% extends 'base.html' %}

{% block title %}Profile{% endblock %}

{% block content %}
<div class="row justify-content-center">
    <div class="col-md-6">
        <h2>Update Profile</h2>
        <form method="post">
            {% csrf_token %}
            {{ form.as_p }}
            <button type="submit" class="btn btn-primary">Save</button>
        </form>
    </div>
</div>
{% endblock %}


add-entry.html
{% extends 'base.html' %}

{% block title %}Add Calorie Entry{% endblock %}

{% block content %}
<div class="row justify-content-center">
    <div class="col-md-6">
        <h2>{{title}}</h2>
        <form method="post">
            {% csrf_token %}
            {{ form.as_p }}
            <button type="submit" class="btn btn-primary">{{submit}}</button>
        </form>
    </div>
</div>
{% endblock %}


delete-entry.html
{% extends 'base.html' %}

{% block title %}Delete Calorie Entry{% endblock %}

{% block content %}
<div class="row justify-content-center">
    <div class="col-md-6">
        <h2>Delete Calorie Entry</h2>
        <p>Are you sure you want to delete the entry for "{{ entry.food_item }}" with {{ entry.calories_consumed }} calories?</p>
        <form method="post">
            {% csrf_token %}
            <button type="submit" class="btn btn-danger">Yes, Delete</button>
            <a href="{% url 'calorie_counter:dashboard' %}" class="btn btn-secondary">Cancel</a>
        </form>
    </div>
</div>
{% endblock %}



settings.html
"""
Django settings for Mahfuz_18_CaloryCounter project.

Generated by 'django-admin startproject' using Django 5.2.7.

For more information on this file, see
https://docs.djangoproject.com/en/5.2/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.2/ref/settings/
"""

from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-2r%kmai(^nsd02$=ae=uj2+$($^=12bk^!tucgj+5r#fx^p3rr'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

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

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'Mahfuz_18_CaloryCounter.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'Mahfuz_18_CaloryCounter.wsgi.application'


# Database
# https://docs.djangoproject.com/en/5.2/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}


# Password validation
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/5.2/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.2/howto/static-files/

STATIC_URL = 'static/'

# Default primary key field type
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
LOGIN_URL = 'calorie_counter:login'