├── tip_prediction
├── db.sqlite3
├── ml_app
│ ├── __init__.py
│ ├── migrations
│ │ ├── __init__.py
│ │ └── __pycache__
│ │ │ └── __init__.cpython-313.pyc
│ ├── models.py
│ ├── tests.py
│ ├── admin.py
│ ├── __pycache__
│ │ ├── apps.cpython-313.pyc
│ │ ├── urls.cpython-313.pyc
│ │ ├── admin.cpython-313.pyc
│ │ ├── forms.cpython-313.pyc
│ │ ├── models.cpython-313.pyc
│ │ ├── views.cpython-313.pyc
│ │ └── __init__.cpython-313.pyc
│ ├── apps.py
│ ├── urls.py
│ ├── forms.py
│ ├── views.py
│ └── templates
│ │ └── ml_app
│ │ ├── base.html
│ │ ├── index.html
│ │ ├── home.html
│ │ └── predict_tip.html
├── tip_prediction
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── urls.cpython-313.pyc
│ │ ├── wsgi.cpython-313.pyc
│ │ ├── __init__.cpython-313.pyc
│ │ └── settings.cpython-313.pyc
│ ├── asgi.py
│ ├── wsgi.py
│ ├── urls.py
│ └── settings.py
└── manage.py
├── .gitignore
├── ml_project
├── models
│ └── xgb_model.pkl
└── data
│ └── tips.csv
├── requirements.txt
├── readme.md
└── deployment.md
/tip_prediction/db.sqlite3:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tip_prediction/ml_app/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tip_prediction/tip_prediction/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tip_prediction/ml_app/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tip_prediction/ml_app/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | # Create your models here.
4 |
--------------------------------------------------------------------------------
/tip_prediction/ml_app/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/tip_prediction/ml_app/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | # Register your models here.
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # ignore virtual environment
2 | .venv/
3 |
4 | .venv/*
5 |
6 | /*.sh
7 | /deployment_my_ip.md
8 |
9 | */*.pyc
--------------------------------------------------------------------------------
/ml_project/models/xgb_model.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AammarTufail/tip_prediction_django_app/main/ml_project/models/xgb_model.pkl
--------------------------------------------------------------------------------
/tip_prediction/ml_app/__pycache__/apps.cpython-313.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AammarTufail/tip_prediction_django_app/main/tip_prediction/ml_app/__pycache__/apps.cpython-313.pyc
--------------------------------------------------------------------------------
/tip_prediction/ml_app/__pycache__/urls.cpython-313.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AammarTufail/tip_prediction_django_app/main/tip_prediction/ml_app/__pycache__/urls.cpython-313.pyc
--------------------------------------------------------------------------------
/tip_prediction/ml_app/__pycache__/admin.cpython-313.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AammarTufail/tip_prediction_django_app/main/tip_prediction/ml_app/__pycache__/admin.cpython-313.pyc
--------------------------------------------------------------------------------
/tip_prediction/ml_app/__pycache__/forms.cpython-313.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AammarTufail/tip_prediction_django_app/main/tip_prediction/ml_app/__pycache__/forms.cpython-313.pyc
--------------------------------------------------------------------------------
/tip_prediction/ml_app/__pycache__/models.cpython-313.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AammarTufail/tip_prediction_django_app/main/tip_prediction/ml_app/__pycache__/models.cpython-313.pyc
--------------------------------------------------------------------------------
/tip_prediction/ml_app/__pycache__/views.cpython-313.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AammarTufail/tip_prediction_django_app/main/tip_prediction/ml_app/__pycache__/views.cpython-313.pyc
--------------------------------------------------------------------------------
/tip_prediction/ml_app/__pycache__/__init__.cpython-313.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AammarTufail/tip_prediction_django_app/main/tip_prediction/ml_app/__pycache__/__init__.cpython-313.pyc
--------------------------------------------------------------------------------
/tip_prediction/ml_app/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class MlAppConfig(AppConfig):
5 | default_auto_field = 'django.db.models.BigAutoField'
6 | name = 'ml_app'
7 |
--------------------------------------------------------------------------------
/tip_prediction/tip_prediction/__pycache__/urls.cpython-313.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AammarTufail/tip_prediction_django_app/main/tip_prediction/tip_prediction/__pycache__/urls.cpython-313.pyc
--------------------------------------------------------------------------------
/tip_prediction/tip_prediction/__pycache__/wsgi.cpython-313.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AammarTufail/tip_prediction_django_app/main/tip_prediction/tip_prediction/__pycache__/wsgi.cpython-313.pyc
--------------------------------------------------------------------------------
/tip_prediction/tip_prediction/__pycache__/__init__.cpython-313.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AammarTufail/tip_prediction_django_app/main/tip_prediction/tip_prediction/__pycache__/__init__.cpython-313.pyc
--------------------------------------------------------------------------------
/tip_prediction/tip_prediction/__pycache__/settings.cpython-313.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AammarTufail/tip_prediction_django_app/main/tip_prediction/tip_prediction/__pycache__/settings.cpython-313.pyc
--------------------------------------------------------------------------------
/tip_prediction/ml_app/migrations/__pycache__/__init__.cpython-313.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AammarTufail/tip_prediction_django_app/main/tip_prediction/ml_app/migrations/__pycache__/__init__.cpython-313.pyc
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | asgiref==3.9.1
2 | Django==5.2.5
3 | numpy==2.3.2
4 | pandas==2.3.2
5 | matplotlib==3.10.6
6 | seaborn==0.13.2
7 | plotly==6.3.0
8 | scikit-learn==1.7.1
9 | joblib==1.5.2
10 | ipykernel==6.30.1
11 | xgboost==3.0.4
--------------------------------------------------------------------------------
/tip_prediction/ml_app/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 | from . import views
3 |
4 | app_name = 'ml_app'
5 |
6 | urlpatterns = [
7 | path('', views.index, name='index'),
8 | path('predict/', views.predict_tip, name='predict_tip'),
9 | ]
10 |
--------------------------------------------------------------------------------
/tip_prediction/tip_prediction/asgi.py:
--------------------------------------------------------------------------------
1 | """
2 | ASGI config for tip_prediction project.
3 |
4 | It exposes the ASGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/5.2/howto/deployment/asgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.asgi import get_asgi_application
13 |
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tip_prediction.settings')
15 |
16 | application = get_asgi_application()
17 |
--------------------------------------------------------------------------------
/tip_prediction/tip_prediction/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for tip_prediction project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/5.2/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tip_prediction.settings')
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/tip_prediction/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """Django's command-line utility for administrative tasks."""
3 | import os
4 | import sys
5 |
6 |
7 | def main():
8 | """Run administrative tasks."""
9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tip_prediction.settings')
10 | try:
11 | from django.core.management import execute_from_command_line
12 | except ImportError as exc:
13 | raise ImportError(
14 | "Couldn't import Django. Are you sure it's installed and "
15 | "available on your PYTHONPATH environment variable? Did you "
16 | "forget to activate a virtual environment?"
17 | ) from exc
18 | execute_from_command_line(sys.argv)
19 |
20 |
21 | if __name__ == '__main__':
22 | main()
23 |
--------------------------------------------------------------------------------
/tip_prediction/tip_prediction/urls.py:
--------------------------------------------------------------------------------
1 | """
2 | URL configuration for tip_prediction project.
3 |
4 | The `urlpatterns` list routes URLs to views. For more information please see:
5 | https://docs.djangoproject.com/en/5.2/topics/http/urls/
6 | Examples:
7 | Function views
8 | 1. Add an import: from my_app import views
9 | 2. Add a URL to urlpatterns: path('', views.home, name='home')
10 | Class-based views
11 | 1. Add an import: from other_app.views import Home
12 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
13 | Including another URLconf
14 | 1. Import the include() function: from django.urls import include, path
15 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
16 | """
17 | from django.contrib import admin
18 | from django.urls import include, path
19 |
20 | urlpatterns = [
21 | path('admin/', admin.site.urls),
22 | # add home page
23 | path('', include('ml_app.urls')),
24 | ]
25 |
--------------------------------------------------------------------------------
/tip_prediction/ml_app/forms.py:
--------------------------------------------------------------------------------
1 | from django import forms
2 |
3 | class TipPredictionForm(forms.Form):
4 | SEX_CHOICES = [
5 | ('Female', 'Female'),
6 | ('Male', 'Male'),
7 | ]
8 |
9 | SMOKER_CHOICES = [
10 | ('No', 'No'),
11 | ('Yes', 'Yes'),
12 | ]
13 |
14 | DAY_CHOICES = [
15 | ('Fri', 'Friday'),
16 | ('Sat', 'Saturday'),
17 | ('Sun', 'Sunday'),
18 | ('Thur', 'Thursday'),
19 | ]
20 |
21 | TIME_CHOICES = [
22 | ('Dinner', 'Dinner'),
23 | ('Lunch', 'Lunch'),
24 | ]
25 |
26 | total_bill = forms.FloatField(
27 | label='Total Bill ($)',
28 | min_value=0,
29 | widget=forms.NumberInput(attrs={
30 | 'class': 'form-control',
31 | 'placeholder': 'Enter total bill amount',
32 | 'step': '0.01'
33 | })
34 | )
35 |
36 | sex = forms.ChoiceField(
37 | label='Gender',
38 | choices=SEX_CHOICES,
39 | widget=forms.Select(attrs={'class': 'form-control'})
40 | )
41 |
42 | smoker = forms.ChoiceField(
43 | label='Smoker',
44 | choices=SMOKER_CHOICES,
45 | widget=forms.Select(attrs={'class': 'form-control'})
46 | )
47 |
48 | day = forms.ChoiceField(
49 | label='Day of Week',
50 | choices=DAY_CHOICES,
51 | widget=forms.Select(attrs={'class': 'form-control'})
52 | )
53 |
54 | time = forms.ChoiceField(
55 | label='Time',
56 | choices=TIME_CHOICES,
57 | widget=forms.Select(attrs={'class': 'form-control'})
58 | )
59 |
60 | size = forms.IntegerField(
61 | label='Party Size',
62 | min_value=1,
63 | max_value=10,
64 | widget=forms.NumberInput(attrs={
65 | 'class': 'form-control',
66 | 'placeholder': 'Number of people'
67 | })
68 | )
69 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Python ML model deployment with Django
2 |
3 | This repository demonstrates how to deploy a machine learning model using Django, a high-level Python web framework. The project includes a simple web interface that allows users to input data and receive predictions from the ML model.
4 |
5 | ## Project we created in this repo
6 | > The project we created in this repo is deployed at [Tip Prediction Django App](https://django.codanics.com/)
7 |
8 |
9 | ## Important
10 | Create a readme.md file of your project, before starting.
11 |
12 | ## 1. Create python env
13 |
14 | We will use python env to create the env.
15 |
16 | ```bash
17 | # create a virtual environment
18 | python -m venv .venv
19 | # activate the virtual environment for linux mac
20 | source .venv/bin/activate
21 | # for windows
22 | # .venv\Scripts\activate
23 | # for windows and git bash
24 | source .venv/Scripts/activate
25 | ```
26 |
27 | ## 2. Install python libraries
28 |
29 | ```bash
30 | # web development framework
31 | pip install django
32 | # machine learning libraries
33 | pip install numpy pandas matplotlib seaborn plotly scikit-learn xgboost
34 | # jupyter notebook support
35 | pip install ipykernel
36 | ```
37 |
38 | ## 3. Train your machine learning model
39 |
40 | 1. Find the data
41 | 2. Preprocess the data
42 | 3. Train the model
43 | 4. Evaluate the model
44 | 5. Save the model
45 |
46 | I have saved the model as `xgb_model.pkl` in the `models` directory.
47 | > You can see the procedure of ML training a model and saving it in this [Jupyter notebook](./ml_project/01_ml.ipynb).
48 |
49 | ## 4. Create a Django project
50 |
51 | ```bash
52 | django-admin startproject tip_prediction
53 | cd tip_prediction
54 | ```
55 |
56 | ## 5. Create a Django app
57 |
58 | ```bash
59 | python manage.py startapp ml_app
60 | ```
61 |
62 | ## 6. Update settings.py
63 |
64 | Add the new app to the `INSTALLED_APPS` list in `tip_prediction/settings.py`:
65 |
66 | ```python
67 | INSTALLED_APPS = [
68 | ...
69 | 'ml_app',
70 | ]
71 | ```
72 |
73 | ## 7. Create a form for user input
74 |
75 | In `ml_app/forms.py`, create a form to accept user input:
76 |
77 | ```python
78 | from django import forms
79 |
80 | class PredictionForm(forms.Form):
81 | feature1 = forms.FloatField(label='Feature 1')
82 | feature2 = forms.FloatField(label='Feature 2')
83 | feature3 = forms.FloatField(label='Feature 3')
84 | feature4 = forms.FloatField(label='Feature 4')
85 | feature5 = forms.FloatField(label='Feature 5')
86 | feature6 = forms.FloatField(label='Feature 6')
87 | ```
88 |
89 |
--------------------------------------------------------------------------------
/tip_prediction/ml_app/views.py:
--------------------------------------------------------------------------------
1 | from django.shortcuts import render
2 | from django.contrib import messages
3 | from .forms import TipPredictionForm
4 | import joblib
5 | import numpy as np
6 | import os
7 | from django.conf import settings
8 |
9 | # Load the trained model
10 | model_path = os.path.join(settings.BASE_DIR.parent, 'ml_project', 'models', 'xgb_model.pkl')
11 |
12 | def load_model():
13 | try:
14 | model = joblib.load(model_path)
15 | return model
16 | except Exception as e:
17 | print(f"Error loading model: {e}")
18 | return None
19 |
20 | def encode_features(sex, smoker, day, time):
21 | """
22 | Encode categorical features according to the training process
23 | Based on the notebook, the encoding was:
24 | sex: Female=0, Male=1
25 | smoker: No=0, Yes=1
26 | day: Fri=0, Sat=1, Sun=2, Thur=3
27 | time: Dinner=0, Lunch=1
28 | """
29 |
30 | # Encode sex
31 | sex_encoded = 1 if sex == 'Male' else 0
32 |
33 | # Encode smoker
34 | smoker_encoded = 1 if smoker == 'Yes' else 0
35 |
36 | # Encode day
37 | day_mapping = {'Fri': 0, 'Sat': 1, 'Sun': 2, 'Thur': 3}
38 | day_encoded = day_mapping.get(day, 0)
39 |
40 | # Encode time
41 | time_encoded = 1 if time == 'Lunch' else 0
42 |
43 | return sex_encoded, smoker_encoded, day_encoded, time_encoded
44 |
45 | def index(request):
46 | """Main landing page"""
47 | return render(request, 'ml_app/index.html')
48 |
49 | def predict_tip(request):
50 | """Tip prediction page"""
51 | prediction = None
52 |
53 | if request.method == 'POST':
54 | form = TipPredictionForm(request.POST)
55 | if form.is_valid():
56 | # Get form data
57 | total_bill = form.cleaned_data['total_bill']
58 | sex = form.cleaned_data['sex']
59 | smoker = form.cleaned_data['smoker']
60 | day = form.cleaned_data['day']
61 | time = form.cleaned_data['time']
62 | size = form.cleaned_data['size']
63 |
64 | # Encode categorical features
65 | sex_encoded, smoker_encoded, day_encoded, time_encoded = encode_features(
66 | sex, smoker, day, time
67 | )
68 |
69 | # Prepare features for prediction
70 | features = np.array([[total_bill, sex_encoded, smoker_encoded, day_encoded, time_encoded, size]])
71 |
72 | # Load model and make prediction
73 | model = load_model()
74 | if model:
75 | try:
76 | prediction = model.predict(features)[0]
77 | prediction = round(prediction, 2)
78 | messages.success(request, f'Prediction successful! Expected tip: ${prediction}')
79 | except Exception as e:
80 | messages.error(request, f'Error making prediction: {str(e)}')
81 | else:
82 | messages.error(request, 'Error: Could not load the ML model.')
83 | else:
84 | form = TipPredictionForm()
85 |
86 | context = {
87 | 'form': form,
88 | 'prediction': prediction,
89 | }
90 |
91 | return render(request, 'ml_app/predict_tip.html', context)
92 |
--------------------------------------------------------------------------------
/tip_prediction/tip_prediction/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for tip_prediction project.
3 |
4 | Generated by 'django-admin startproject' using Django 5.2.5.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/5.2/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/5.2/ref/settings/
11 | """
12 |
13 | from pathlib import Path
14 |
15 | # Build paths inside the project like this: BASE_DIR / 'subdir'.
16 | BASE_DIR = Path(__file__).resolve().parent.parent
17 |
18 |
19 | # Quick-start development settings - unsuitable for production
20 | # See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
21 |
22 | # SECURITY WARNING: keep the secret key used in production secret!
23 | SECRET_KEY = 'django-insecure-qy$t7l*@ban%l54%r4lx$&qf#vyb*t4bx+48(o0zv=ex7+ag5&'
24 |
25 | # SECURITY WARNING: don't run with debug turned on in production!
26 | DEBUG = True
27 |
28 | ALLOWED_HOSTS = []
29 |
30 |
31 | # Application definition
32 |
33 | INSTALLED_APPS = [
34 | 'django.contrib.admin',
35 | 'django.contrib.auth',
36 | 'django.contrib.contenttypes',
37 | 'django.contrib.sessions',
38 | 'django.contrib.messages',
39 | 'django.contrib.staticfiles',
40 | 'ml_app',
41 | ]
42 |
43 | MIDDLEWARE = [
44 | 'django.middleware.security.SecurityMiddleware',
45 | 'django.contrib.sessions.middleware.SessionMiddleware',
46 | 'django.middleware.common.CommonMiddleware',
47 | 'django.middleware.csrf.CsrfViewMiddleware',
48 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
49 | 'django.contrib.messages.middleware.MessageMiddleware',
50 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
51 | ]
52 |
53 | ROOT_URLCONF = 'tip_prediction.urls'
54 |
55 | TEMPLATES = [
56 | {
57 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
58 | 'DIRS': [],
59 | 'APP_DIRS': True,
60 | 'OPTIONS': {
61 | 'context_processors': [
62 | 'django.template.context_processors.request',
63 | 'django.contrib.auth.context_processors.auth',
64 | 'django.contrib.messages.context_processors.messages',
65 | ],
66 | },
67 | },
68 | ]
69 |
70 | WSGI_APPLICATION = 'tip_prediction.wsgi.application'
71 |
72 |
73 | # Database
74 | # https://docs.djangoproject.com/en/5.2/ref/settings/#databases
75 |
76 | DATABASES = {
77 | 'default': {
78 | 'ENGINE': 'django.db.backends.sqlite3',
79 | 'NAME': BASE_DIR / 'db.sqlite3',
80 | }
81 | }
82 |
83 |
84 | # Password validation
85 | # https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
86 |
87 | AUTH_PASSWORD_VALIDATORS = [
88 | {
89 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
90 | },
91 | {
92 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
93 | },
94 | {
95 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
96 | },
97 | {
98 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
99 | },
100 | ]
101 |
102 |
103 | # Internationalization
104 | # https://docs.djangoproject.com/en/5.2/topics/i18n/
105 |
106 | LANGUAGE_CODE = 'en-us'
107 |
108 | TIME_ZONE = 'UTC'
109 |
110 | USE_I18N = True
111 |
112 | USE_TZ = True
113 |
114 |
115 | # Static files (CSS, JavaScript, Images)
116 | # https://docs.djangoproject.com/en/5.2/howto/static-files/
117 |
118 | STATIC_URL = 'static/'
119 |
120 | # Default primary key field type
121 | # https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field
122 |
123 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
124 |
--------------------------------------------------------------------------------
/tip_prediction/ml_app/templates/ml_app/base.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {% block title %}Restaurant Analytics Platform{% endblock %}
7 |
8 |
9 |
10 |
154 | {% block extra_css %}{% endblock %}
155 |
156 |
157 |
158 |
159 |
185 |
186 |
187 |
188 |
189 | {% block content %}
190 | {% endblock %}
191 |
192 |
193 |
194 |
206 |
207 |
208 | {% block extra_js %}{% endblock %}
209 |
210 |
211 |
--------------------------------------------------------------------------------
/ml_project/data/tips.csv:
--------------------------------------------------------------------------------
1 | total_bill,tip,sex,smoker,day,time,size
2 | 16.99,1.01,Female,No,Sun,Dinner,2
3 | 10.34,1.66,Male,No,Sun,Dinner,3
4 | 21.01,3.5,Male,No,Sun,Dinner,3
5 | 23.68,3.31,Male,No,Sun,Dinner,2
6 | 24.59,3.61,Female,No,Sun,Dinner,4
7 | 25.29,4.71,Male,No,Sun,Dinner,4
8 | 8.77,2.0,Male,No,Sun,Dinner,2
9 | 26.88,3.12,Male,No,Sun,Dinner,4
10 | 15.04,1.96,Male,No,Sun,Dinner,2
11 | 14.78,3.23,Male,No,Sun,Dinner,2
12 | 10.27,1.71,Male,No,Sun,Dinner,2
13 | 35.26,5.0,Female,No,Sun,Dinner,4
14 | 15.42,1.57,Male,No,Sun,Dinner,2
15 | 18.43,3.0,Male,No,Sun,Dinner,4
16 | 14.83,3.02,Female,No,Sun,Dinner,2
17 | 21.58,3.92,Male,No,Sun,Dinner,2
18 | 10.33,1.67,Female,No,Sun,Dinner,3
19 | 16.29,3.71,Male,No,Sun,Dinner,3
20 | 16.97,3.5,Female,No,Sun,Dinner,3
21 | 20.65,3.35,Male,No,Sat,Dinner,3
22 | 17.92,4.08,Male,No,Sat,Dinner,2
23 | 20.29,2.75,Female,No,Sat,Dinner,2
24 | 15.77,2.23,Female,No,Sat,Dinner,2
25 | 39.42,7.58,Male,No,Sat,Dinner,4
26 | 19.82,3.18,Male,No,Sat,Dinner,2
27 | 17.81,2.34,Male,No,Sat,Dinner,4
28 | 13.37,2.0,Male,No,Sat,Dinner,2
29 | 12.69,2.0,Male,No,Sat,Dinner,2
30 | 21.7,4.3,Male,No,Sat,Dinner,2
31 | 19.65,3.0,Female,No,Sat,Dinner,2
32 | 9.55,1.45,Male,No,Sat,Dinner,2
33 | 18.35,2.5,Male,No,Sat,Dinner,4
34 | 15.06,3.0,Female,No,Sat,Dinner,2
35 | 20.69,2.45,Female,No,Sat,Dinner,4
36 | 17.78,3.27,Male,No,Sat,Dinner,2
37 | 24.06,3.6,Male,No,Sat,Dinner,3
38 | 16.31,2.0,Male,No,Sat,Dinner,3
39 | 16.93,3.07,Female,No,Sat,Dinner,3
40 | 18.69,2.31,Male,No,Sat,Dinner,3
41 | 31.27,5.0,Male,No,Sat,Dinner,3
42 | 16.04,2.24,Male,No,Sat,Dinner,3
43 | 17.46,2.54,Male,No,Sun,Dinner,2
44 | 13.94,3.06,Male,No,Sun,Dinner,2
45 | 9.68,1.32,Male,No,Sun,Dinner,2
46 | 30.4,5.6,Male,No,Sun,Dinner,4
47 | 18.29,3.0,Male,No,Sun,Dinner,2
48 | 22.23,5.0,Male,No,Sun,Dinner,2
49 | 32.4,6.0,Male,No,Sun,Dinner,4
50 | 28.55,2.05,Male,No,Sun,Dinner,3
51 | 18.04,3.0,Male,No,Sun,Dinner,2
52 | 12.54,2.5,Male,No,Sun,Dinner,2
53 | 10.29,2.6,Female,No,Sun,Dinner,2
54 | 34.81,5.2,Female,No,Sun,Dinner,4
55 | 9.94,1.56,Male,No,Sun,Dinner,2
56 | 25.56,4.34,Male,No,Sun,Dinner,4
57 | 19.49,3.51,Male,No,Sun,Dinner,2
58 | 38.01,3.0,Male,Yes,Sat,Dinner,4
59 | 26.41,1.5,Female,No,Sat,Dinner,2
60 | 11.24,1.76,Male,Yes,Sat,Dinner,2
61 | 48.27,6.73,Male,No,Sat,Dinner,4
62 | 20.29,3.21,Male,Yes,Sat,Dinner,2
63 | 13.81,2.0,Male,Yes,Sat,Dinner,2
64 | 11.02,1.98,Male,Yes,Sat,Dinner,2
65 | 18.29,3.76,Male,Yes,Sat,Dinner,4
66 | 17.59,2.64,Male,No,Sat,Dinner,3
67 | 20.08,3.15,Male,No,Sat,Dinner,3
68 | 16.45,2.47,Female,No,Sat,Dinner,2
69 | 3.07,1.0,Female,Yes,Sat,Dinner,1
70 | 20.23,2.01,Male,No,Sat,Dinner,2
71 | 15.01,2.09,Male,Yes,Sat,Dinner,2
72 | 12.02,1.97,Male,No,Sat,Dinner,2
73 | 17.07,3.0,Female,No,Sat,Dinner,3
74 | 26.86,3.14,Female,Yes,Sat,Dinner,2
75 | 25.28,5.0,Female,Yes,Sat,Dinner,2
76 | 14.73,2.2,Female,No,Sat,Dinner,2
77 | 10.51,1.25,Male,No,Sat,Dinner,2
78 | 17.92,3.08,Male,Yes,Sat,Dinner,2
79 | 27.2,4.0,Male,No,Thur,Lunch,4
80 | 22.76,3.0,Male,No,Thur,Lunch,2
81 | 17.29,2.71,Male,No,Thur,Lunch,2
82 | 19.44,3.0,Male,Yes,Thur,Lunch,2
83 | 16.66,3.4,Male,No,Thur,Lunch,2
84 | 10.07,1.83,Female,No,Thur,Lunch,1
85 | 32.68,5.0,Male,Yes,Thur,Lunch,2
86 | 15.98,2.03,Male,No,Thur,Lunch,2
87 | 34.83,5.17,Female,No,Thur,Lunch,4
88 | 13.03,2.0,Male,No,Thur,Lunch,2
89 | 18.28,4.0,Male,No,Thur,Lunch,2
90 | 24.71,5.85,Male,No,Thur,Lunch,2
91 | 21.16,3.0,Male,No,Thur,Lunch,2
92 | 28.97,3.0,Male,Yes,Fri,Dinner,2
93 | 22.49,3.5,Male,No,Fri,Dinner,2
94 | 5.75,1.0,Female,Yes,Fri,Dinner,2
95 | 16.32,4.3,Female,Yes,Fri,Dinner,2
96 | 22.75,3.25,Female,No,Fri,Dinner,2
97 | 40.17,4.73,Male,Yes,Fri,Dinner,4
98 | 27.28,4.0,Male,Yes,Fri,Dinner,2
99 | 12.03,1.5,Male,Yes,Fri,Dinner,2
100 | 21.01,3.0,Male,Yes,Fri,Dinner,2
101 | 12.46,1.5,Male,No,Fri,Dinner,2
102 | 11.35,2.5,Female,Yes,Fri,Dinner,2
103 | 15.38,3.0,Female,Yes,Fri,Dinner,2
104 | 44.3,2.5,Female,Yes,Sat,Dinner,3
105 | 22.42,3.48,Female,Yes,Sat,Dinner,2
106 | 20.92,4.08,Female,No,Sat,Dinner,2
107 | 15.36,1.64,Male,Yes,Sat,Dinner,2
108 | 20.49,4.06,Male,Yes,Sat,Dinner,2
109 | 25.21,4.29,Male,Yes,Sat,Dinner,2
110 | 18.24,3.76,Male,No,Sat,Dinner,2
111 | 14.31,4.0,Female,Yes,Sat,Dinner,2
112 | 14.0,3.0,Male,No,Sat,Dinner,2
113 | 7.25,1.0,Female,No,Sat,Dinner,1
114 | 38.07,4.0,Male,No,Sun,Dinner,3
115 | 23.95,2.55,Male,No,Sun,Dinner,2
116 | 25.71,4.0,Female,No,Sun,Dinner,3
117 | 17.31,3.5,Female,No,Sun,Dinner,2
118 | 29.93,5.07,Male,No,Sun,Dinner,4
119 | 10.65,1.5,Female,No,Thur,Lunch,2
120 | 12.43,1.8,Female,No,Thur,Lunch,2
121 | 24.08,2.92,Female,No,Thur,Lunch,4
122 | 11.69,2.31,Male,No,Thur,Lunch,2
123 | 13.42,1.68,Female,No,Thur,Lunch,2
124 | 14.26,2.5,Male,No,Thur,Lunch,2
125 | 15.95,2.0,Male,No,Thur,Lunch,2
126 | 12.48,2.52,Female,No,Thur,Lunch,2
127 | 29.8,4.2,Female,No,Thur,Lunch,6
128 | 8.52,1.48,Male,No,Thur,Lunch,2
129 | 14.52,2.0,Female,No,Thur,Lunch,2
130 | 11.38,2.0,Female,No,Thur,Lunch,2
131 | 22.82,2.18,Male,No,Thur,Lunch,3
132 | 19.08,1.5,Male,No,Thur,Lunch,2
133 | 20.27,2.83,Female,No,Thur,Lunch,2
134 | 11.17,1.5,Female,No,Thur,Lunch,2
135 | 12.26,2.0,Female,No,Thur,Lunch,2
136 | 18.26,3.25,Female,No,Thur,Lunch,2
137 | 8.51,1.25,Female,No,Thur,Lunch,2
138 | 10.33,2.0,Female,No,Thur,Lunch,2
139 | 14.15,2.0,Female,No,Thur,Lunch,2
140 | 16.0,2.0,Male,Yes,Thur,Lunch,2
141 | 13.16,2.75,Female,No,Thur,Lunch,2
142 | 17.47,3.5,Female,No,Thur,Lunch,2
143 | 34.3,6.7,Male,No,Thur,Lunch,6
144 | 41.19,5.0,Male,No,Thur,Lunch,5
145 | 27.05,5.0,Female,No,Thur,Lunch,6
146 | 16.43,2.3,Female,No,Thur,Lunch,2
147 | 8.35,1.5,Female,No,Thur,Lunch,2
148 | 18.64,1.36,Female,No,Thur,Lunch,3
149 | 11.87,1.63,Female,No,Thur,Lunch,2
150 | 9.78,1.73,Male,No,Thur,Lunch,2
151 | 7.51,2.0,Male,No,Thur,Lunch,2
152 | 14.07,2.5,Male,No,Sun,Dinner,2
153 | 13.13,2.0,Male,No,Sun,Dinner,2
154 | 17.26,2.74,Male,No,Sun,Dinner,3
155 | 24.55,2.0,Male,No,Sun,Dinner,4
156 | 19.77,2.0,Male,No,Sun,Dinner,4
157 | 29.85,5.14,Female,No,Sun,Dinner,5
158 | 48.17,5.0,Male,No,Sun,Dinner,6
159 | 25.0,3.75,Female,No,Sun,Dinner,4
160 | 13.39,2.61,Female,No,Sun,Dinner,2
161 | 16.49,2.0,Male,No,Sun,Dinner,4
162 | 21.5,3.5,Male,No,Sun,Dinner,4
163 | 12.66,2.5,Male,No,Sun,Dinner,2
164 | 16.21,2.0,Female,No,Sun,Dinner,3
165 | 13.81,2.0,Male,No,Sun,Dinner,2
166 | 17.51,3.0,Female,Yes,Sun,Dinner,2
167 | 24.52,3.48,Male,No,Sun,Dinner,3
168 | 20.76,2.24,Male,No,Sun,Dinner,2
169 | 31.71,4.5,Male,No,Sun,Dinner,4
170 | 10.59,1.61,Female,Yes,Sat,Dinner,2
171 | 10.63,2.0,Female,Yes,Sat,Dinner,2
172 | 50.81,10.0,Male,Yes,Sat,Dinner,3
173 | 15.81,3.16,Male,Yes,Sat,Dinner,2
174 | 7.25,5.15,Male,Yes,Sun,Dinner,2
175 | 31.85,3.18,Male,Yes,Sun,Dinner,2
176 | 16.82,4.0,Male,Yes,Sun,Dinner,2
177 | 32.9,3.11,Male,Yes,Sun,Dinner,2
178 | 17.89,2.0,Male,Yes,Sun,Dinner,2
179 | 14.48,2.0,Male,Yes,Sun,Dinner,2
180 | 9.6,4.0,Female,Yes,Sun,Dinner,2
181 | 34.63,3.55,Male,Yes,Sun,Dinner,2
182 | 34.65,3.68,Male,Yes,Sun,Dinner,4
183 | 23.33,5.65,Male,Yes,Sun,Dinner,2
184 | 45.35,3.5,Male,Yes,Sun,Dinner,3
185 | 23.17,6.5,Male,Yes,Sun,Dinner,4
186 | 40.55,3.0,Male,Yes,Sun,Dinner,2
187 | 20.69,5.0,Male,No,Sun,Dinner,5
188 | 20.9,3.5,Female,Yes,Sun,Dinner,3
189 | 30.46,2.0,Male,Yes,Sun,Dinner,5
190 | 18.15,3.5,Female,Yes,Sun,Dinner,3
191 | 23.1,4.0,Male,Yes,Sun,Dinner,3
192 | 15.69,1.5,Male,Yes,Sun,Dinner,2
193 | 19.81,4.19,Female,Yes,Thur,Lunch,2
194 | 28.44,2.56,Male,Yes,Thur,Lunch,2
195 | 15.48,2.02,Male,Yes,Thur,Lunch,2
196 | 16.58,4.0,Male,Yes,Thur,Lunch,2
197 | 7.56,1.44,Male,No,Thur,Lunch,2
198 | 10.34,2.0,Male,Yes,Thur,Lunch,2
199 | 43.11,5.0,Female,Yes,Thur,Lunch,4
200 | 13.0,2.0,Female,Yes,Thur,Lunch,2
201 | 13.51,2.0,Male,Yes,Thur,Lunch,2
202 | 18.71,4.0,Male,Yes,Thur,Lunch,3
203 | 12.74,2.01,Female,Yes,Thur,Lunch,2
204 | 13.0,2.0,Female,Yes,Thur,Lunch,2
205 | 16.4,2.5,Female,Yes,Thur,Lunch,2
206 | 20.53,4.0,Male,Yes,Thur,Lunch,4
207 | 16.47,3.23,Female,Yes,Thur,Lunch,3
208 | 26.59,3.41,Male,Yes,Sat,Dinner,3
209 | 38.73,3.0,Male,Yes,Sat,Dinner,4
210 | 24.27,2.03,Male,Yes,Sat,Dinner,2
211 | 12.76,2.23,Female,Yes,Sat,Dinner,2
212 | 30.06,2.0,Male,Yes,Sat,Dinner,3
213 | 25.89,5.16,Male,Yes,Sat,Dinner,4
214 | 48.33,9.0,Male,No,Sat,Dinner,4
215 | 13.27,2.5,Female,Yes,Sat,Dinner,2
216 | 28.17,6.5,Female,Yes,Sat,Dinner,3
217 | 12.9,1.1,Female,Yes,Sat,Dinner,2
218 | 28.15,3.0,Male,Yes,Sat,Dinner,5
219 | 11.59,1.5,Male,Yes,Sat,Dinner,2
220 | 7.74,1.44,Male,Yes,Sat,Dinner,2
221 | 30.14,3.09,Female,Yes,Sat,Dinner,4
222 | 12.16,2.2,Male,Yes,Fri,Lunch,2
223 | 13.42,3.48,Female,Yes,Fri,Lunch,2
224 | 8.58,1.92,Male,Yes,Fri,Lunch,1
225 | 15.98,3.0,Female,No,Fri,Lunch,3
226 | 13.42,1.58,Male,Yes,Fri,Lunch,2
227 | 16.27,2.5,Female,Yes,Fri,Lunch,2
228 | 10.09,2.0,Female,Yes,Fri,Lunch,2
229 | 20.45,3.0,Male,No,Sat,Dinner,4
230 | 13.28,2.72,Male,No,Sat,Dinner,2
231 | 22.12,2.88,Female,Yes,Sat,Dinner,2
232 | 24.01,2.0,Male,Yes,Sat,Dinner,4
233 | 15.69,3.0,Male,Yes,Sat,Dinner,3
234 | 11.61,3.39,Male,No,Sat,Dinner,2
235 | 10.77,1.47,Male,No,Sat,Dinner,2
236 | 15.53,3.0,Male,Yes,Sat,Dinner,2
237 | 10.07,1.25,Male,No,Sat,Dinner,2
238 | 12.6,1.0,Male,Yes,Sat,Dinner,2
239 | 32.83,1.17,Male,Yes,Sat,Dinner,2
240 | 35.83,4.67,Female,No,Sat,Dinner,3
241 | 29.03,5.92,Male,No,Sat,Dinner,3
242 | 27.18,2.0,Female,Yes,Sat,Dinner,2
243 | 22.67,2.0,Male,Yes,Sat,Dinner,2
244 | 17.82,1.75,Male,No,Sat,Dinner,2
245 | 18.78,3.0,Female,No,Thur,Dinner,2
246 |
--------------------------------------------------------------------------------
/tip_prediction/ml_app/templates/ml_app/index.html:
--------------------------------------------------------------------------------
1 | {% extends 'ml_app/base.html' %}
2 |
3 | {% block title %}Restaurant Analytics Platform - Home{% endblock %}
4 |
5 | {% block extra_css %}
6 |
114 | {% endblock %}
115 |
116 | {% block content %}
117 |
118 |
119 |
120 |
121 |
122 |
123 | Restaurant Analytics Platform (By Dr. M. Aammar Tufail)
124 |
125 |
126 | Leverage the power of machine learning to predict tips and optimize your restaurant's performance
127 |
128 |
129 |
130 | Start Predicting Tips
131 |
132 |
133 | Learn More
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 | 95%
146 | Accuracy Rate
147 |
148 |
149 |
150 |
151 | 244
152 | Training Records
153 |
154 |
155 |
156 |
157 | 6
158 | Input Features
159 |
160 |
161 |
162 |
163 | XGBoost
164 | ML Algorithm
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
Smart Predictions
179 |
180 | Our XGBoost algorithm analyzes multiple factors including bill amount, party size, gender, smoking preference, day of week, and meal time to provide accurate tip predictions.
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
Data-Driven Insights
190 |
191 | Built on real restaurant data with 244 dining records, our model provides reliable insights to help optimize your restaurant's service and pricing strategies.
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
Instant Results
201 |
202 | Get real-time tip predictions in seconds. Simply input the dining details and receive immediate forecasts to better understand customer tipping patterns.
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
Powered by Modern Technology
214 |
215 | Python
216 | XGBoost
217 | Scikit-learn
218 | Bootstrap
219 | Django
220 | NumPy
221 |
222 |
223 | Built with industry-standard machine learning libraries and modern web technologies for optimal performance and reliability.
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
Ready to Get Started?
233 |
Start predicting tips now and discover insights about your restaurant's tipping patterns!
234 |
235 | Launch Tip Predictor
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
How It Works
245 |
Simple steps to get accurate tip predictions
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
1. Input Details
254 |
Enter bill amount, party size, and dining preferences
255 |
256 |
257 |
258 |
259 |
260 |
2. AI Processing
261 |
Our XGBoost model analyzes the data patterns
262 |
263 |
264 |
265 |
266 |
267 |
3. Get Prediction
268 |
Receive accurate tip amount prediction instantly
269 |
270 |
271 |
272 |
273 | {% endblock %}
274 |
275 | {% block extra_js %}
276 |
310 | {% endblock %}
311 |
--------------------------------------------------------------------------------
/tip_prediction/ml_app/templates/ml_app/home.html:
--------------------------------------------------------------------------------
1 | {% extends 'ml_app/base.html' %}
2 |
3 | {% block title %}Tip Predictor - Restaurant Analytics Platform{% endblock %}
4 |
5 | {% block extra_css %}
6 |
162 | {% endblock %}
163 |
164 | {% block content %}
165 |
166 |
167 |
168 |
169 |
170 |
171 | Home
172 |
173 |
174 |
175 | Tip Predictor
176 |
177 |
178 |
179 |
180 |
181 |
182 |
186 |
187 |
188 |
189 |
How it works:
190 |
Our XGBoost model analyzes bill amount, party size, gender, smoking preference, day of week, and meal time to predict tip amounts based on real restaurant data patterns.
191 |
192 |
193 |
194 | {% if messages %}
195 | {% for message in messages %}
196 |
197 |
198 | {{ message }}
199 |
200 |
201 | {% endfor %}
202 | {% endif %}
203 |
204 |
205 |
284 |
285 |
286 | {% if prediction %}
287 |
288 |
Prediction Result
289 |
${{ prediction }}
290 |
Based on the provided information, the expected tip amount is ${{ prediction }}
291 |
292 |
293 |
294 | This prediction is based on historical restaurant data and machine learning analysis
295 |
296 |
297 |
302 |
303 | {% endif %}
304 |
305 |
306 | {% endblock %}
307 |
308 | {% block extra_js %}
309 |
353 | {% endblock %}
354 |
--------------------------------------------------------------------------------
/tip_prediction/ml_app/templates/ml_app/predict_tip.html:
--------------------------------------------------------------------------------
1 | {% extends 'ml_app/base.html' %}
2 |
3 | {% block title %}Tip Predictor - Restaurant Analytics Platform{% endblock %}
4 |
5 | {% block extra_css %}
6 |
162 | {% endblock %}
163 |
164 | {% block content %}
165 |
166 |
167 |
168 |
169 |
170 |
171 | Home
172 |
173 |
174 |
175 | Tip Predictor
176 |
177 |
178 |
179 |
180 |
181 |
182 |
186 |
187 |
188 |
189 |
How it works:
190 |
Our XGBoost model analyzes bill amount, party size, gender, smoking preference, day of week, and meal time to predict tip amounts based on real restaurant data patterns.
191 |
192 |
193 |
194 | {% if messages %}
195 | {% for message in messages %}
196 |
197 |
198 | {{ message }}
199 |
200 |
201 | {% endfor %}
202 | {% endif %}
203 |
204 |
205 |
284 |
285 |
286 | {% if prediction %}
287 |
288 |
Prediction Result
289 |
${{ prediction }}
290 |
Based on the provided information, the expected tip amount is ${{ prediction }}
291 |
292 |
293 |
294 | This prediction is based on historical restaurant data and machine learning analysis
295 |
296 |
297 |
302 |
303 | {% endif %}
304 |
305 |
306 | {% endblock %}
307 |
308 | {% block extra_js %}
309 |
353 | {% endblock %}
354 |
--------------------------------------------------------------------------------
/deployment.md:
--------------------------------------------------------------------------------
1 | # Django ML Model Deployment Guide - Hostinger KVM VPS
2 |
3 | ## Prerequisites
4 | - Hostinger KVM VPS account
5 | - Use this link to purchase and get a discount: [Hostinger KVM VPS Discounted Link](https://hostinger.com?REFERRALCODE=1MUHAMMAD0984)
6 | - Domain name (optional but recommended)
7 | - Buy a domain from [Namecheap](https://www.namecheap.com) or [GoDaddy](https://www.godaddy.com) or [Hostinger](https://www.hostinger.com)
8 | - Local Django project ready for deployment
9 |
10 | ## Step 1: Server Setup and Initial Configuration
11 |
12 | ### 1.1 Connect to Your VPS using SSH
13 | ```bash
14 | ssh root@your_server_ip
15 | ```
16 |
17 | You can see the following guide to use ssh via hostinger: [Hostinger SSH Guide](https://www.hostinger.com/support/5723772-how-to-connect-to-your-vps-via-ssh-at-hostinger/)
18 |
19 | ### 1.2 Update System Packages and Install Dependencies
20 | ```bash
21 | # Update package lists
22 | sudo apt update && sudo apt upgrade -y
23 |
24 | # Install essential packages including uWSGI dependencies
25 | sudo apt install -y gcc python3-dev python3.12-venv nginx postgresql libpq-dev
26 | ```
27 |
28 | ## Step 2: Create Application User
29 |
30 | ### 2.1 Create Dedicated Django User
31 | ```bash
32 | # Create user with proper groups and shell
33 | sudo useradd -m -s /bin/bash -G www-data django_user
34 | # Set password for the user
35 | sudo passwd django_user
36 | #save the password
37 |
38 | # give sudo permission to django_user
39 | sudo usermod -aG sudo django_user
40 |
41 |
42 | # Switch to django user
43 | sudo su - django_user
44 | ```
45 |
46 | ### 2.2 Set Directory Permissions
47 | ```bash
48 | # Set proper permissions for home directory (important for Nginx access)
49 | chmod 711 /home/django_user
50 | cd /home/django_user
51 | ```
52 |
53 | ## Step 3: Setup PostgreSQL Database
54 |
55 | ### 3.1 Configure PostgreSQL
56 | ```bash
57 | # Switch to postgres user and access PostgreSQL
58 | sudo -u postgres psql
59 | ```
60 |
61 | ```sql
62 | CREATE DATABASE ml_model_db;
63 | CREATE USER ml_user WITH PASSWORD 'Yourpasswrd';
64 | ALTER ROLE ml_user SET client_encoding TO 'utf8';
65 | ALTER ROLE ml_user SET default_transaction_isolation TO 'read committed';
66 | ALTER ROLE ml_user SET timezone TO 'UTC';
67 | GRANT ALL PRIVILEGES ON DATABASE ml_model_db TO ml_user;
68 | ```
69 | > run the following commands:
70 |
71 | ```sql
72 | \c ml_model_db;
73 | ```
74 | > then run this
75 |
76 | ```sql
77 | GRANT ALL PRIVILEGES ON SCHEMA public TO ml_user;
78 | GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO ml_user;
79 | GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO ml_user;
80 | ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO ml_user;
81 | ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO ml_user;
82 | ```
83 |
84 | > press `\q` to exit.
85 |
86 |
87 | ## Step 4: Deploy Django Application
88 |
89 | ### 4.1 Clone Your Project
90 | ```bash
91 | # Make sure you're in django_user home directory
92 | sudo su django_user
93 | cd
94 | chmod 711 .
95 | ```
96 |
97 | ```bash
98 | git clone https://github.com/AammarTufail/tip_prediction_django_app.git
99 | ```
100 |
101 | ### 4.2 Create Virtual Environment
102 | ```bash
103 | # Create virtual environment in home directory (not in app directory)
104 | python3 -m venv .venv
105 | source .venv/bin/activate
106 | ```
107 |
108 | ### 4.3 Install Dependencies
109 | ```bash
110 | pip install -r ./tip_prediction_django_app/requirements.txt
111 | pip install uwsgi psycopg2-binary
112 | ```
113 |
114 | ### 4.4 Setup Auto-activation
115 | ```bash
116 | # Edit .bashrc to auto-activate virtual environment
117 | nano ~/.bashrc
118 | ```
119 |
120 | Add these lines to .bashrc at the end to automatically load the virtual environment when you log in to django_user:
121 | ```bash
122 | cd
123 | source .venv/bin/activate
124 | ```
125 | > press `Ctrl+D` and login again to django_user `sudo su django_user` you will see the virtual environment activated automatically.
126 |
127 | ### 4.5 Configure Django Settings for Production
128 | ```bash
129 | cd ./tip_prediction_django_app/tip_prediction
130 | nano tip_prediction/settings_prod.py
131 | ```
132 |
133 | Add:
134 | ```python
135 | from .settings import *
136 | import os
137 |
138 | DEBUG = False
139 | ALLOWED_HOSTS = ['your_domain.com', '45.xx.xxx.x (your IP)', 'localhost']
140 |
141 | DATABASES = {
142 | 'default': {
143 | 'ENGINE': 'django.db.backends.postgresql',
144 | 'NAME': 'ml_model_db',
145 | 'USER': 'ml_user',
146 | 'PASSWORD': 'Yourpasswrd', # you can change this according to your needs
147 | 'HOST': 'localhost',
148 | 'PORT': '5432',
149 | }
150 | }
151 |
152 | STATIC_ROOT = '/home/django_user/tip_prediction_django_app/tip_prediction/staticfiles'
153 | MEDIA_ROOT = '/home/django_user/tip_prediction_django_app/tip_prediction/media'
154 |
155 | # Security settings
156 | SECURE_BROWSER_XSS_FILTER = True
157 | SECURE_CONTENT_TYPE_NOSNIFF = True
158 | X_FRAME_OPTIONS = 'DENY'
159 | ```
160 |
161 | ### 4.6 Run Database Migrations and Collect Static Files
162 | ```bash
163 | export DJANGO_SETTINGS_MODULE=tip_prediction.settings_prod
164 | python manage.py collectstatic --noinput
165 | python manage.py migrate
166 | python manage.py createsuperuser
167 | ```
168 | > save the credentials which will be used later.
169 |
170 | ## Step 5: Configure uWSGI
171 |
172 | ### 5.1 Create uWSGI Configuration
173 | ```bash
174 | cd /home/django_user
175 | nano uwsgi.ini
176 | ```
177 |
178 | Add this configuration (corrected paths for your project structure):
179 | ```ini
180 | [uwsgi]
181 | chdir = /home/django_user/tip_prediction_django_app/tip_prediction
182 | module = tip_prediction.wsgi:application
183 | home = /home/django_user/.venv
184 | env = DJANGO_SETTINGS_MODULE=tip_prediction.settings_prod
185 |
186 | master = true
187 | processes = 2
188 | threads = 2
189 |
190 | socket = /home/django_user/uwsgi.sock
191 | chmod-socket = 660
192 | chown-socket = django_user:www-data
193 | vacuum = true
194 | die-on-term = true
195 |
196 | daemonize = /home/django_user/tip_prediction.log
197 | pidfile = /home/django_user/tip_prediction.pid
198 | ```
199 |
200 | ### 5.2 Test uWSGI
201 | ```bash
202 | # Clean start - stop any prior instance
203 | [ -f /home/django_user/tip_prediction.pid ] && uwsgi --stop /home/django_user/tip_prediction.pid || true
204 |
205 | # Start uWSGI
206 | uwsgi --ini /home/django_user/uwsgi.ini
207 | sleep 2
208 | # Check if socket was created
209 | ls -l /home/django_user/uwsgi.sock
210 | # Check logs
211 | tail -n60 /home/django_user/tip_prediction.log
212 | ```
213 |
214 | ## Step 6: Configure Nginx
215 |
216 | ```bash
217 | sudo apt install -y nginx
218 | ```
219 | ### 6.1 Generate Self-Signed Certificate for IP
220 | ```bash
221 | # Create self-signed certificate for IP address
222 | sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
223 | -keyout /etc/ssl/private/ip-selfsigned.key \
224 | -out /etc/ssl/certs/ip-selfsigned.crt \
225 | -subj "/CN=45.xx.xxx.x (your IP)" \
226 | -addext "subjectAltName = IP:45.xx.xxx.x (your IP)"
227 | ```
228 |
229 | ### 6.2 Create Nginx Configuration
230 | ```bash
231 | sudo nano /etc/nginx/conf.d/tip_prediction.conf
232 | ```
233 |
234 | Add this configuration:
235 | ```nginx
236 | server {
237 | listen 80 default_server;
238 | listen [::]:80 default_server;
239 | listen 443 ssl;
240 | server_name 45.xx.xxx.x (your IP);
241 |
242 | ssl_certificate /etc/ssl/certs/ip-selfsigned.crt;
243 | ssl_certificate_key /etc/ssl/private/ip-selfsigned.key;
244 |
245 | location / {
246 | include uwsgi_params;
247 | uwsgi_pass unix:/home/django_user/uwsgi.sock;
248 | }
249 |
250 | location /static/ {
251 | alias /home/django_user/tip_prediction_django_app/tip_prediction/staticfiles/;
252 | }
253 |
254 | location /media/ {
255 | alias /home/django_user/tip_prediction_django_app/tip_prediction/media/;
256 | }
257 | }
258 | ```
259 |
260 | ### 6.3 Test and Start Nginx
261 | ```bash
262 | # Test nginx configuration
263 | sudo nginx -t
264 |
265 | # Restart nginx
266 | sudo systemctl restart nginx
267 | ```
268 |
269 | ### 6.4 Fix Socket Permissions
270 | ```bash
271 | # Ensure proper permissions for socket file
272 | sudo chmod 711 /home/django_user
273 | sudo chgrp www-data /home/django_user/uwsgi.sock
274 | sudo chmod 660 /home/django_user/uwsgi.sock
275 | ```
276 |
277 | ## Step 7: SSL Certificate Setup
278 |
279 | ### 7.1 Generate Self-Signed Certificate for IP (if not done before)
280 | ```bash
281 | # Create self-signed certificate for IP address
282 | sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
283 | -keyout /etc/ssl/private/ip-selfsigned.key \
284 | -out /etc/ssl/certs/ip-selfsigned.crt \
285 | -subj "/CN=45.xx.xxx.x (your IP)" \
286 | -addext "subjectAltName = IP:45.xx.xxx.x (your IP)"
287 | ```
288 |
289 | ### 7.2 Install Certbot (for domain-based SSL later)
290 | ```bash
291 | sudo apt install -y certbot python3-certbot-nginx
292 | ```
293 |
294 | ## Step 8: Final Testing
295 |
296 | ### 8.1 Test Application
297 | ```bash
298 | # Test local connection
299 | curl -I http://127.0.0.1
300 |
301 | # Test external connection
302 | curl -I http://45.xx.xxx.x (your IP)
303 | ```
304 | > if 502 Bad Gateway error occurs, check the above logs for any errors.
305 | > If 200 OK response is received, your application is working correctly.
306 |
307 | **Visit your application at:**
308 | - `http://45.xx.xxx.x (your IP)/`
309 | - `https://45.xx.xxx.x (your IP)/` (with self-signed certificate)
310 | - For admin: `http://45.xx.xxx.x (your IP)/admin/`
311 |
312 | ### 8.2 Reload Application (when needed)
313 | ```bash
314 | # Reload uWSGI gracefully
315 | uwsgi --reload /home/django_user/tip_prediction.pid
316 |
317 | # View logs
318 | cat /home/django_user/tip_prediction.log
319 | ```
320 |
321 | ## Step 9: Maintenance and Updates
322 |
323 | ### 9.1 Update Application
324 | ```bash
325 | # Switch to django user
326 | sudo su - django_user
327 | cd tip_prediction_django_app
328 |
329 | # Update code
330 | git pull origin main
331 |
332 | # Update dependencies if needed
333 | pip install -r requirements.txt
334 |
335 | # Run migrations and collect static files
336 | cd tip_prediction
337 | export DJANGO_SETTINGS_MODULE=tip_prediction.settings_prod
338 | python manage.py migrate
339 | python manage.py collectstatic --noinput
340 |
341 | # Reload application
342 | cd /home/django_user
343 | uwsgi --reload tip_prediction.pid
344 | ```
345 |
346 | ### 9.2 Monitor Logs
347 | ```bash
348 | # uWSGI logs
349 | tail -f /home/django_user/tip_prediction.log
350 |
351 | # Nginx logs
352 | sudo tail -f /var/log/nginx/error.log
353 | sudo tail -f /var/log/nginx/access.log
354 | ```
355 |
356 | ## Troubleshooting
357 |
358 | ### Common Issues:
359 |
360 | #### 1. **502 Bad Gateway**
361 | ```bash
362 | # Check if uWSGI is running
363 | ps aux | grep uwsgi
364 |
365 | # Check socket file exists and has correct permissions
366 | ls -la /home/django_user/uwsgi.sock
367 |
368 | # Check uWSGI logs
369 | tail -20 /home/django_user/tip_prediction.log
370 |
371 | # Fix permissions if needed
372 | sudo chmod 711 /home/django_user
373 | sudo chgrp www-data /home/django_user/uwsgi.sock
374 | sudo chmod 660 /home/django_user/uwsgi.sock
375 |
376 | # Restart services
377 | uwsgi --reload /home/django_user/tip_prediction.pid
378 | sudo systemctl restart nginx
379 | ```
380 |
381 | #### 2. **uWSGI Won't Start**
382 | ```bash
383 | # Check if there's a stale PID file
384 | ls -la /home/django_user/tip_prediction.pid
385 |
386 | # Remove stale PID if exists
387 | rm -f /home/django_user/tip_prediction.pid
388 |
389 | # Start fresh
390 | uwsgi --ini /home/django_user/uwsgi.ini
391 |
392 | # Check logs for errors
393 | tail -f /home/django_user/tip_prediction.log
394 | ```
395 |
396 | #### 3. **Static Files Not Loading**
397 | ```bash
398 | # Recollect static files
399 | cd /home/django_user/tip_prediction_django_app/tip_prediction
400 | source /home/django_user/.venv/bin/activate
401 | export DJANGO_SETTINGS_MODULE=tip_prediction.settings_prod
402 | python manage.py collectstatic --clear --noinput
403 |
404 | # Check static files directory
405 | ls -la /home/django_user/tip_prediction_django_app/tip_prediction/staticfiles/
406 |
407 | # Restart nginx
408 | sudo systemctl restart nginx
409 | ```
410 |
411 | #### 4. **Permission Errors**
412 | ```bash
413 | # Fix ownership and permissions
414 | sudo chown -R django_user:www-data /home/django_user/tip_prediction_django_app
415 | sudo chmod -R 755 /home/django_user/tip_prediction_django_app
416 | sudo chmod 711 /home/django_user
417 | ```
418 |
419 | ## Security Best Practices
420 |
421 | 1. **Regular Updates**: Keep system and packages updated
422 | 2. **Firewall**: Configure UFW properly
423 | 3. **SSH Security**: Use key-based authentication
424 | 4. **Database Security**: Use strong passwords and limit access
425 | 5. **Django Security**: Follow Django security checklist
426 | 6. **SSL Certificate**: Use proper SSL certificates for production
427 |
428 | ## Quick Commands Reference
429 |
430 | ### Start/Stop/Reload uWSGI
431 | ```bash
432 | # Start
433 | uwsgi --ini /home/django_user/uwsgi.ini
434 |
435 | # Stop
436 | uwsgi --stop /home/django_user/tip_prediction.pid
437 |
438 | # Reload
439 | uwsgi --reload /home/django_user/tip_prediction.pid
440 |
441 | # Check status
442 | ps aux | grep uwsgi
443 | ```
444 |
445 | ### Nginx Commands
446 | ```bash
447 | # Test configuration
448 | sudo nginx -t
449 |
450 | # Restart
451 | sudo systemctl restart nginx
452 |
453 | # Check status
454 | sudo systemctl status nginx
455 | ```
456 |
457 | This guide provides a complete deployment solution based on your working script for Django ML model application on Hostinger KVM VPS.
458 |
459 | ## Attach your domain to hostinger
460 |
461 | 1. Log in to your Hostinger account.
462 | 2. Go to the "Domains" section.
463 | 3. Click on "Add Domain" and enter your domain name.
464 | 4. Follow the instructions to point your domain to your VPS IP address.
465 | 5. Once the DNS changes propagate, you should be able to access your application via your domain.
466 |
467 |
468 | ## Connecting Hostinger Subdomain from Another Account
469 |
470 | If you have a subdomain from another Hostinger account, you can point it to your VPS IP address by following these steps:
471 |
472 | ### Method 1: DNS Zone Management (Recommended)
473 |
474 | #### Step 1: Access DNS Zone Editor
475 | 1. Log into the Hostinger account that owns the main domain
476 | 2. Go to **Hosting** → **Manage** → **DNS Zone Editor**
477 | 3. Find your domain in the list
478 |
479 | #### Step 2: Add/Edit DNS Records
480 | ```bash
481 | # Add these DNS records in the DNS Zone Editor:
482 |
483 | # For subdomain (e.g., api.yourdomain.com)
484 | Type: A Record
485 | Name: app.yourdomain.com
486 | Points to: 45.xx.xxx.x (your IP) (your VPS IP)
487 | TTL: 3600
488 |
489 | # Optional: Add AAAA record if you have IPv6
490 | Type: AAAA Record
491 | Name: api
492 | Points to: your_ipv6_address
493 | TTL: 3600
494 | ```
495 |
496 |
497 | #### Step 3: Update Django Settings
498 | ```bash
499 | nano /home/django_user/tip_prediction_django_app/tip_prediction/tip_prediction/settings_prod.py
500 | ```
501 |
502 | Add your subdomain to ALLOWED_HOSTS:
503 | ```python
504 | ALLOWED_HOSTS = ['django.codanics.com', 'yourdomain.com', '45.xx.xxx.x (your IP)', 'localhost']
505 | ```
506 |
507 | #### Step 5: Get SSL Certificate for Domain
508 | ```bash
509 | # Stop nginx temporarily
510 | sudo systemctl stop nginx
511 |
512 | # Get SSL certificate for your domain
513 | sudo apt install -y certbot python3-certbot-nginx
514 | sudo ufw allow 'Nginx Full'
515 | sudo certbot --nginx -d django.codanics.com
516 |
517 |
518 | # Update nginx configuration to use real SSL
519 | sudo nano /etc/nginx/conf.d/tip_prediction.conf
520 | ```
521 |
522 | Update SSL configuration:
523 | ```nginx
524 | server {
525 | if ($host = app.yourdomain.com) {
526 | return 301 https://$host$request_uri;
527 | } # managed by Certbot
528 |
529 |
530 | listen 80;
531 | server_name app.yourdomain.com;
532 | return 301 https://$server_name$request_uri;
533 |
534 |
535 | }
536 | server {
537 | listen 80 default_server;
538 | listen [::]:80 default_server;
539 | listen 443 ssl;
540 | server_name app.yourdomain.com;
541 | ssl_certificate /etc/letsencrypt/live/app.yourdomain.com/fullchain.pem; # managed by Certbot
542 | ssl_certificate_key /etc/letsencrypt/live/app.yourdomain.com/privkey.pem; # managed by Certbot
543 |
544 |
545 | location / {
546 | include uwsgi_params;
547 | uwsgi_pass unix:/home/django_user/uwsgi.sock;
548 | }
549 |
550 | location /static/ {
551 | alias /home/django_user/tip_prediction_django_app/tip_prediction/staticfiles/;
552 | }
553 |
554 | location /media/ {
555 | alias /home/django_user/tip_prediction_django_app/tip_prediction/media/;
556 | }
557 |
558 | }
559 | ```
560 |
561 | #### Step 6: Restart Services
562 | ```bash
563 | # Test nginx configuration
564 | sudo nginx -t
565 | sudo systemctl stop nginx
566 | sudo systemctl stop nginx
567 | sudo pkill -9 nginx
568 | sudo rm -f /run/nginx.pid
569 | sudo nginx -t
570 | sudo systemctl start nginx
571 | sudo systemctl status nginx
572 | # Reload uWSGI
573 | uwsgi --reload /home/django_user/tip_prediction.pid
574 | ```
575 |
576 | ### Verification Steps
577 |
578 | ```bash
579 | # Check if DNS is working
580 | nslookup django.codanics.com
581 | dig django.codanics.com
582 |
583 | # Should return your VPS IP: 45.xx.xxx.x (your IP)
584 | ```
585 |
586 | #### Test Application Access
587 | ```bash
588 | # Test HTTP
589 | curl -I http://django.codanics.com
590 |
591 | # Test HTTPS (if SSL configured)
592 | curl -I https://django.codanics.com
593 | ```
594 |
595 | ### Important Notes
596 |
597 | 1. **DNS Propagation**: Changes can take 24-48 hours to fully propagate worldwide
598 | 2. **Access Required**: You need access to the DNS management of the domain/subdomain
599 | 3. **SSL Certificate**: You'll need to generate a new SSL certificate for the domain
600 | 4. **Multiple Domains**: You can point multiple subdomains to the same VPS
601 |
602 | ### Auto-SSL Renewal Setup
603 | ```bash
604 | # Add cron job for auto SSL renewal
605 | sudo crontab -e
606 |
607 | # Add this line:
608 | 0 12 * * * /usr/bin/certbot renew --quiet && systemctl reload nginx
609 | ```
610 |
611 | After completing these steps, your application will be accessible via your Hostinger subdomain!
612 |
613 |
614 | ### Add a cron job for automatic updates from github for the app
615 |
616 | ```bash
617 | # Switch to django user
618 | sudo su - django_user
619 |
620 | # Create update script
621 | nano ~/update_app.sh
622 | ```
623 |
624 | Add this content to the script:
625 | ```bash
626 | #!/bin/bash
627 | # Auto-update script for Django app
628 |
629 | # Log file
630 | LOG_FILE="/home/django_user/update_app.log"
631 | echo "$(date): Starting app update..." >> $LOG_FILE
632 |
633 | # Change to app directory
634 | cd /home/django_user/tip_prediction_django_app
635 |
636 | # Pull latest changes
637 | git pull origin main >> $LOG_FILE 2>&1
638 |
639 | # Update dependencies if requirements changed
640 | pip install -r requirements.txt >> $LOG_FILE 2>&1
641 |
642 | # Run migrations and collect static files
643 | cd tip_prediction
644 | export DJANGO_SETTINGS_MODULE=tip_prediction.settings_prod
645 | python manage.py migrate >> $LOG_FILE 2>&1
646 | python manage.py collectstatic --noinput >> $LOG_FILE 2>&1
647 |
648 | # Reload application
649 | cd /home/django_user
650 | uwsgi --reload tip_prediction.pid >> $LOG_FILE 2>&1
651 |
652 | echo "$(date): App update completed" >> $LOG_FILE
653 | ```
654 |
655 | Make the script executable:
656 | ```bash
657 | chmod +x ~/update_app.sh
658 | ```
659 |
660 | Add cron job (runs every day at 2 AM):
661 | ```bash
662 | crontab -e
663 |
664 | # Add this line:
665 | 0 2 * * * /home/django_user/update_app.sh
666 | ```
667 |
668 | View update logs:
669 | ```bash
670 | tail -f /home/django_user/update_app.log
671 | ```
672 |
673 |
674 | ## Refresh if some errors come
675 |
676 | ```bash
677 | # Clean start - stop any prior instance
678 | [ -f /home/django_user/tip_prediction.pid ] && uwsgi --stop /home/django_user/tip_prediction.pid || true
679 |
680 | # Start uWSGI
681 | uwsgi --ini /home/django_user/uwsgi.ini
682 | sleep 2
683 | # Check if socket was created
684 | ls -l /home/django_user/uwsgi.sock
685 | # Test nginx configuration
686 | sudo nginx -t
687 |
688 | # Restart nginx
689 | sudo systemctl restart nginx
690 | ```
691 |
692 | # Reset everything and start from scratch
693 |
694 | ```bash
695 | # Stop services
696 | sudo systemctl stop nginx
697 | sudo systemctl stop uwsgi
698 |
699 | # Remove application files
700 | sudo rm -rf /home/django_user/tip_prediction_django_app
701 |
702 | # Remove virtual environment
703 | sudo rm -rf /home/django_user/venvs/tip_prediction
704 |
705 | # Remove logs
706 | sudo rm -f /home/django_user/update_app.log
707 |
708 | # Remove SSL certificates
709 | sudo rm -f /etc/letsencrypt/live/app.yourdomain.com/fullchain.pem
710 | sudo rm -f /etc/letsencrypt/live/app.yourdomain.com/privkey.pem
711 |
712 | # Remove nginx configuration
713 | sudo rm -f /etc/nginx/sites-available/app.yourdomain.com
714 | sudo rm -f /etc/nginx/sites-enabled/app.yourdomain.com
715 | sudo rm -f /etc/nginx/conf.d/tip_prediction.conf
716 | # Remove uWSGI configuration
717 | sudo rm -f /home/django_user/uwsgi.ini
718 | # Remove PID and socket files
719 | sudo rm -f /home/django_user/tip_prediction.pid
720 | sudo rm -f /home/django_user/uwsgi.sock
721 | # Remove django user
722 | sudo userdel -r django_user
723 | ```
724 |
725 | > The End.
726 |
727 |
728 |
--------------------------------------------------------------------------------