6  Checkpoints on the Software Developer Journey

6.1 Looks anf Feels by HTML

This tutorial provides an introduction to essential HTML elements and styling techniques. For more detailed information, visit the MDN Web Docs.

6.1.1 Section Heading

HTML headings are defined with the <h1> to <h6> tags. Here’s an example of a section heading:

<h2>Section Heading Example</h2>

Render:

Section Heading Example

6.1.2 Paragraphs, Divs, and Spans

  • Paragraphs are defined with the <p> tag.
  • Divs are used as block-level containers with the <div> tag.
  • Spans are used for inline styling with the <span> tag.

Example:

<p>This is a paragraph.</p>
<p>This is another paragraph.</p>
<div>This is a div</div>
<div>This is another div</div>
<span>This text is inside a span.</span>
<span>This another text is inside a span.</span>

Render:

This is a paragraph.

This is another paragraph.

This is a div
This is another div
This text is inside a span. This another text is inside a span.
Compare tags: p, div, span

The HTML code provided consists of two paragraph elements (<p>), two division elements (<div>), and two span elements (<span>). Each of these elements serves a different purpose in the structure and styling of a webpage:

  • Paragraph (<p>) Elements: Define paragraphs, typically resulting in a visual break with a new line and space before and after the text.
  • Division (<div>) Elements: Serve as containers to segment the page vertically. They do not inherently cause any visual break or create space unless styled with CSS.
  • Span (<span>) Elements: Inline elements used to group or apply styles to parts of a text within other elements. They do not cause any line breaks or add extra space.

This comparison shows how HTML tags dictate the structure and flow of content on a webpage, affecting how text and containers appear in the browser.

6.1.3 Simple Text Styling

HTML provides several tags for styling text:

  • Bold: <strong>bold text</strong> or <b>bold text</b>
  • Italic: <em>italic text</em> or <i>italic text</i>
  • Underline: <u>underlined text</u>

Example:

<p>This is <strong>bold</strong>, <em>italic</em>, and <u>underlined</u> text.</p>

This is bold, italic, and underlined text.

6.1.4 Lists

6.1.4.1 Ordered List

An ordered list is defined with the <ol> tag.

<ol>
  <li>First item</li>
  <li>Second item</li>
  <li>Third item</li>
</ol>
  1. First item
  2. Second item
  3. Third item

6.1.4.2 Unordered List

An unordered list is defined with the <ul> tag.

<ul>
  <li>First item</li>
  <li>Second item</li>
  <li>Third item</li>
</ul>
  • First item
  • Second item
  • Third item

6.1.5 Images

Images are inserted using the <img> tag, which requires the src, alt, width, and height attributes.

<img src="https://loremflickr.com/640/480/abstract" alt="Description of image" width="300" height="200">
Description of image

6.1.6 Tables

Tables are defined with the <table> tag, and include rows (<tr>) and cells (<td> for data, <th> for headers).

<table>
  <tr>
    <th>Header 1</th>
    <th>Header 2</th>
  </tr>
  <tr>
    <td>Data 1</td>
    <td>Data 2</td>
  </tr>
</table>
Header 1 Header 2
Data 1 Data 2

6.1.7 Further Information

For more detailed information on HTML elements, visit the HTML Elements Reference on MDN.

6.2 Deploy Django Server on DigitalOcean

6.2.1 Infrastructure as a Service

Since we are deploying our Django application on DigitalOcean, we don’t need to worry about physical hardware. Instead, we leverage DigitalOcean’s cloud infrastructure, which provides us with virtualised resources. These resources are part of what is known as Infrastructure as a Service (IaaS), where the provider (DigitalOcean) manages the physical servers, storage, and networking.

6.2.2 Key Components of DigitalOcean

  • Droplets: In DigitalOcean, the virtual servers are called Droplets. These Droplets are essentially virtual machines with dedicated CPU, memory, and storage resources. Depending on your application’s needs, you can choose a Droplet with the appropriate amount of resources. For example, you might start with a basic Droplet with 1 GB of RAM and 1 vCPU for a small application and scale up as needed.

  • Scalability: One of the key advantages of using cloud services like DigitalOcean is scalability. You can easily resize your Droplet or add more Droplets to your setup as your application grows, without needing to worry about purchasing or maintaining physical hardware.

  • Backup and Redundancy: DigitalOcean provides options for automated backups and snapshots, which are critical for maintaining data integrity and ensuring that you can recover your application in case of failure.

6.2.3 Software of Choice

In deploying your Django application on DigitalOcean, several key software components are required to ensure a stable, secure, and efficient production environment. Below are the specific versions of the software used in this deployment setup:

  • Operating System: The Droplet runs Ubuntu 24.04 LTS (GNU/Linux 6.8.0-40-generic x86_64). Ubuntu is a popular Linux distribution known for its stability, security, and extensive support in server environments, making it an ideal choice for hosting web applications.

  • Python: Python 3.12.3 is used to run Django. Python is the core language for Django, and ensuring compatibility with the version used in development is crucial for avoiding runtime issues.

  • Django: The application is built with Django 5.1, a high-level Python web framework that encourages rapid development and clean, pragmatic design. Django handles everything from database queries to rendering HTML.

  • Gunicorn: Gunicorn 23.0.0 serves as the WSGI HTTP server. Gunicorn is a robust, scalable server that handles the communication between the web server (Nginx) and your Django application.

  • Nginx: Nginx 1.24.0 is used as the web server. Nginx is known for its high performance, stability, rich feature set, simple configuration, and low resource consumption. It acts as a reverse proxy, handling client requests, serving static files, and passing requests to Gunicorn for dynamic content.

  • SQLite: SQLite 3.45.1 is the database used for this deployment. While SQLite is often used for development and testing due to its simplicity, it can also be used in production environments where a lightweight, file-based database is sufficient.

  • HTTP/HTTPS: Currently, the setup uses HTTP 1.1. However, it is crucial to upgrade to HTTPS to ensure secure communication between the client and server. This upgrade involves obtaining an SSL/TLS certificate and configuring Nginx to handle HTTPS traffic.

This software stack ensures that your Django application is running on a solid foundation, with each component playing a critical role in delivering a secure, scalable, and efficient web service.

Diagram:

G User 👤 User Nginx 🌐 Nginx User->Nginx Send Request Nginx->User Send Response Gunicorn 🦄 Gunicorn Nginx->Gunicorn Forward Dynamic Request Gunicorn->Nginx Receive Dynamic Response Django 🐍 Django Gunicorn->Django Handle Request Django->Gunicorn Handle Response

6.2.4 Clone Django Project and Activate Python

  1. Clone the Repository: This command clones the Django project from the GitHub repository to your local machine.
  2. Navigate to the Project Directory: After cloning, navigate into the project directory.
  3. Create a Virtual Environment: This command creates a virtual environment named .venv inside your project directory.
  4. Activate the Virtual Environment: This command activates the virtual environment, allowing you to install packages specific to your project without affecting the global Python environment.
  5. Create a new secret key for Django production server.
git clone https://github.com/jeremy886/mvp24.git
cd mvp24
python -m venv .venv
source .venv/bin/activate
echo "export SECRET_KEY='$(openssl rand -hex 40)'" > .DJANGO_SECRET_KEY
source .DJANGO_SECRET_KEY

6.2.5 Install Django and Gunicorn

Install Django and Gunicorn:

python -m pip django
python -m pip install gunicorn

Run server:

  1. test django server
  2. test gunicorn
  3. run gunicorn and keep alive after logout using nohup and &
# test django server
python manage.py runserver '0.0.0.0:8888'
# test gunicorn
source .DJANGO_SECRET_KEY
export DJANGO_SETTINGS_MODULE='mvp24.settings.production'
gunicorn --workers 1 --bind 0.0.0.0:8888 mvp24.wsgi:application
nohup gunicorn --workers 1 --bind 0.0.0.0:8888 mvp24.wsgi:application & 

You also need to set up your domain name so you can visit http://cyber.mrchen.store:8888.

Kill gunicorn after testing.

pgrep gunicorn  # view jobs
pkill -f gunicorn  # kill jobs

6.2.6 Django Settings for Production and Development

  • mvp24/settings/base.py
  • production.py
  • development.py
mvp24/settings/base.py
from pathlib import Path

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


import os
try:
    SECRET_KEY = os.environ["SECRET_KEY"]
except KeyError as e:
    raise RuntimeError("Could not find a SECRET_KEY in environment") from e


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'crm.apps.CrmConfig',
]

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 = 'mvp24.urls'

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

WSGI_APPLICATION = 'mvp24.wsgi.application'


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

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


# Password validation
# https://docs.djangoproject.com/en/5.0/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.0/topics/i18n/

LANGUAGE_CODE = 'en-au'

TIME_ZONE = 'Australia/Melbourne'

USE_I18N = True

USE_TZ = True


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


# URL to use when referring to static files
STATIC_URL = '/static/'

# Additional locations to search for static files
STATICFILES_DIRS = [
    BASE_DIR / 'static',  # Include additional directories here
]

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

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

# Redirect to home URL after login (Default redirects to /accounts/profile/)
LOGIN_REDIRECT_URL = '/'
# Also redirect to home after logout
LOGOUT_REDIRECT_URL = '/'
mvp24/settings/development.py
from .base import *

DEBUG = True

# The directory where static files will be collected
STATIC_ROOT = BASE_DIR / 'staticfiles'

ALLOWED_HOSTS = []
mvp24/settings/production.py
# production.py

from .base import *

DEBUG = False

# The directory where static files will be collected
STATIC_ROOT = '/var/www/cyber.mrchen.store/static'

ALLOWED_HOSTS = ['localhost', 'cyber.mrchen.store']

Create the directory for static files:

(.venv) $ sudo mkdir -pv /var/www/cyber.mrchen.store/static/
(.venv) $ sudo chown -cR jeremy:jeremy /var/www/cyber.mrchen.store/static

6.2.7 Setup Gunicorn

Create config/gunicorn/prod.py

conf/gunicorn/prod.py
"""Gunicorn *production* config file"""

# Django WSGI application path in pattern MODULE_NAME:VARIABLE_NAME
wsgi_app = "mvp24.wsgi:application"
# The granularity of Error log outputs
loglevel = "info"
# The number of worker processes for handling requests
workers = 1
# The socket to bind
bind = "0.0.0.0:8888"  # Use standard HTTP port
# Reload is disabled in production
reload = False
# Write access and error info to /var/log
accesslog = errorlog = "/var/log/gunicorn/prod.log"
# Redirect stdout/stderr to log file
capture_output = True
# PID file so you can easily fetch process ID
pidfile = "/var/run/gunicorn/prod.pid"
# Daemonize the Gunicorn process (detach & enter background)
daemon = True

Sudo commands to set up log files

sudo mkdir -pv /var/{log,run}/gunicorn/
sudo chown -cR jeremy:jeremy /var/{log,run}/gunicorn/  # jeremy:jeremy

Test gunicorn settings

gunicorn -c config/gunicorn/prod.py
tail -f /var/log/gunicorn/prod.log

Remember to kill gunicorn jobs after testing.

6.2.8 Set up HTTP Server Nginx

Install Nginx

apt-get install -y nginx
nginx -v
systemctl start nginx
systemctl status nginx

Nginx config file

/etc/nginx/sites-available/cyber
server_tokens               off;
access_log                  /var/log/nginx/supersecure.access.log;
error_log                   /var/log/nginx/supersecure.error.log;

# This configuration will be changed to redirect to HTTPS later
server {
  server_name               .cyber.mrchen.store;
  listen                    80;
  
  location / {
    proxy_pass              http://localhost:8888;
    proxy_set_header        Host $host;
  }
  
  location /static {
    autoindex on;
    alias /var/www/cyber.mrchen.store/static/;
  }
  
}

Test Nginx Config File

service nginx configtest /etc/nginx/sites-available/cyber

Enable Site Configuration

cd /etc/nginx/sites-enabled
ln -s ../sites-available/cyber .

Restart Ngnix

systemctl reload nginx

6.2.9 Turning on HTTPS

An SSL/TLS certificate is like a digital ID card for websites, confirming their identity and enabling secure, encrypted connections between the site and its users. This encryption protects sensitive information, like passwords and credit card numbers, ensuring it can’t be intercepted or altered during transmission.

Let’s Encrypt is a free service that provides these SSL/TLS certificates. It automates the process of getting and renewing certificates, making it easy for anyone to secure their website with HTTPS, which is the secure version of HTTP. This ensures that data shared on the site stays private and protected.

sudo apt-get update -y
sudo apt-get install certbot python3-certbot-nginx -y
sudo certbot --nginx -d cyber.mrchen.store

Result:

Requesting a certificate for cyber.mrchen.store

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/cyber.mrchen.store/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/cyber.mrchen.store/privkey.pem
This certificate expires on 2024-11-15.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

Deploying certificate
Successfully deployed certificate for cyber.mrchen.store to /etc/nginx/sites-enabled/cyber
Congratulations! You have successfully enabled HTTPS on https://cyber.mrchen.store

Certbot will be run twice a day.

$ sudo systemctl status certbot
 certbot.service - Certbot
     Loaded: loaded (/usr/lib/systemd/system/certbot.service; static)
     Active: inactive (dead)
TriggeredBy: ● certbot.timer
       Docs: file:///usr/share/doc/python-certbot-doc/html/index.html
             https://certbot.eff.org/docs
$ sudo systemctl status certbot.timer
 certbot.timer - Run certbot twice daily
     Loaded: loaded (/usr/lib/systemd/system/certbot.timer; enabled; preset: enabled)
     Active: active (waiting) since Sat 2024-08-17 11:02:25 UTC; 13min ago
    Trigger: Sat 2024-08-17 17:34:49 UTC; 6h left
   Triggers: ● certbot.service

This is the updated Nginx configuration file:

/etc/nginx/sites-available/cyber
server_tokens               off;
access_log                  /var/log/nginx/supersecure.access.log;
error_log                   /var/log/nginx/supersecure.error.log;

# This configuration will be changed to redirect to HTTPS later
server {
  server_name               .cyber.mrchen.store;
  
  location / {
    proxy_pass              http://localhost:8888;
    proxy_set_header        Host $host;
    proxy_set_header        X-Forwarded-Proto $scheme;
  }

  location /static {
    autoindex on;
    alias /var/www/cyber.mrchen.store/static/;
  }


    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/cyber.mrchen.store/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/cyber.mrchen.store/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}


server {
    if ($host = cyber.mrchen.store) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


  server_name               .cyber.mrchen.store;
  listen                    80;
    return 404; # managed by Certbot


}

Test Nginx Configuration file:

sudo nginx -t

If okay, then restart Nginx:

sudo systemctl reload nginx

Easier Way to Run the Server

Remembering all the necessary commands can be challenging, so let’s simplify the process by putting them into a script that you can run with a single command.

source ./run_server.sh production
run_server.sh
#!/bin/bash

# Check for the correct number of arguments
if [ "$#" -ne 1 ]; then
    echo "Usage: $0 <environment>"
    echo "Where <environment> is 'development' or 'production'."
    exit 1
fi

# Set the DJANGO_SETTINGS_MODULE based on the argument
if [ "$1" == "development" ]; then
    export DJANGO_SETTINGS_MODULE='mvp24.settings.development'
elif [ "$1" == "production" ]; then
    export DJANGO_SETTINGS_MODULE='mvp24.settings.production'
else
    echo "Invalid environment: $1"
    echo "Please choose 'development' or 'production'."
    exit 1
fi

# Generate a new secret key
# echo "export SECRET_KEY='$(openssl rand -hex 40)'" > .DJANGO_SECRET_KEY
source .DJANGO_SECRET_KEY

# Print the settings being used
echo "Starting Django server with settings: $DJANGO_SETTINGS_MODULE"
echo "Using SECRET_KEY: $SECRET_KEY"

# Collect static files in production
if [ "$1" == "production" ]; then
    echo "Collecting static files..."
    python manage.py collectstatic --noinput
fi

# Start the server
# For development:
if [ "$1" == "development" ]; then
    python manage.py runserver
# For production, assuming you use gunicorn:
elif [ "$1" == "production" ]; then
    gunicorn -c config/gunicorn/prod.py
fi

6.2.10 Firewall

6.2.11 Introduction to UFW

UFW (Uncomplicated Firewall) is a user-friendly tool designed to help configure and manage iptables firewall rules on Linux systems. It simplifies the process of setting up basic firewall policies, allowing you to easily control incoming and outgoing traffic to your server. UFW is particularly useful for securing applications like Django, providing a straightforward way to enforce security measures and protect your server from unauthorized access.

Inactive Firewall

To showcase networking functionalities, the firewall is inactive currently. Remember to activate UFW or another firewall solution after the demonstration to secure your server.

6.2.12 UFW Configuration for a Django Application

1. Install UFW:

sudo apt-get update  
sudo apt-get install ufw

2. Allow SSH Access:

sudo ufw allow 22/tcp

3. Allow HTTP and HTTPS Traffic:

sudo ufw allow 80/tcp  
sudo ufw allow 443/tcp

4. Restrict MySQL/PostgreSQL Access (if applicable):

sudo ufw allow from 127.0.0.1 to any port 3306   # MySQL  
sudo ufw allow from 127.0.0.1 to any port 5432   # PostgreSQL

5. Enable UFW:

sudo ufw enable

6. Check UFW Status:

sudo ufw status verbose

7. Deny All Other Incoming Traffic:

sudo ufw default deny incoming  
sudo ufw default allow outgoing

8. Allow Other Necessary Services:

sudo ufw allow 2222/tcp   # Example for a custom SSH port

9. Advanced: Rate Limiting:

sudo ufw limit ssh/tcp

10. Disabling or Resetting UFW:

sudo ufw disable  
sudo ufw reset

6.2.13 Commands to Run the Server:

cd DjangoProjects/mvp24 && source .venv/bin/activate
source run_server.sh production

6.2.14 Credit

Adapted from:

6.3 How To Upgrade Your Server

6.3.1 Ongoing Development

(.venv) $ git log --oneline --decorate --graph --all
*   85f2d19 (HEAD -> production, origin/production) Merge branch 'feature/event' into production
|\  
| * bdf660c (origin/feature/event, feature/event) add quiz app, change home page
| * 8ffde36 start a new branch and add event
* | 4c29357 update gitignore
|/  
* 32641b3 make home page responsive with bootstrap
| *   ad081d9 (origin/main, main) Merge branch 'production'
| |\  
| |/  
|/|   
* | a534d23 udpate gitignore
* | 2071b38 update manage.py for development settings
* | 72808e9 add run_server.sh
* | 44bbc47 add gunicorn config
* | 7d4db21 add image to home page
| * 39987bb add gunicorn config
| * 264c408 add image to home page
|/  
* 8359617 (tag: v1.0.0) new updates from production
*   9b3afa2 Merge production into main: Kept development.py and production.py, deleted settings.py
|\  
| * b530716 modify settings files for development (PyCharm)
* | 8b650f7 Upgrade Django to 5.1 (Security fix)
(.venv) $ git branch -a
  feature/event
  main
* production
  remotes/origin/feature/event
  remotes/origin/main
  remotes/origin/production
Branches
  • main: to show the simplest product (MVP)
  • production: to run on the server
  • feature/event: additional event app, quiz app

6.3.2 Run The New Code

Merge the feature/event branch into the production branch.

git checkout production
git pull origin production
git merge feature/event
# Resolve conflicts if necessary
git push origin production

6.3.3 Update Django Server

# check if gunicorn is running; if so, stop it
pgrep gunicorn
pkill -f gunicorn
# restart gunicorn
source .venv/bin/activate
source .DJANGO_SECRET_KEY
# make sure you have this if you want to run manage.py
export DJANGO_SETTINGS_MODULE='mvp24.settings.production'
# run makemigrations and migrate if there is any model change.
python manage.py makemigrations
python manage.py migrate
source run_server.sh production

Gunicorn Issue

We might need to create a systemd config for gunicorn because /var/run dictories will disappear after reboot.

gunicorn -c config/gunicorn/prod.py
tail -f /var/log/gunicorn/prod.log
Error: /var/run/gunicorn doesn't exist. Can't create pidfile.

[2024-08-25 10:00:39 +0000] [1400] [INFO] Starting gunicorn 23.0.0

Error: /var/run/gunicorn doesn't exist. Can't create pidfile.

This will be fixed by:

sudo mkdir -pv /var/{log,run}/gunicorn/
sudo chown -cR jeremy:jeremy /var/{log,run}/gunicorn/

Make Migrations

If you have change your models, make sure:

python manage.py makemigrations quiz
python manage.py migrate quiz

Send files

python manage.py dumpdata quiz > quiz_data.json
scp -i ~/.ssh/id_rsa quiz_data.json jeremy@cyber.mrchen.store:/tmp/
python manage.py loaddata /tmp/quiz_data.json

6.4 What is Responsive Web Development?

Responsive web development is an approach to building websites that ensures a seamless and optimal user experience across a wide range of devices, from desktops and laptops to tablets and smartphones. The key idea is that the website layout and content should adapt to the screen size, resolution, and orientation of the device being used.

6.4.1 Key Features of Responsive Web Development:

  • Flexible Layouts: The use of fluid grids and flexible images that automatically resize and rearrange based on the screen size.
  • Media Queries: CSS techniques that apply different styles based on the characteristics of the device, such as screen width or resolution.
  • Viewport Meta Tag: A tag that controls the layout on mobile browsers by setting the viewport size and scale.
  • Optimized Performance: Ensuring that the website loads quickly and efficiently on all devices, often by serving different content or images based on device capabilities.

Responsive design is essential in modern web development because it provides a consistent and user-friendly experience, regardless of the device being used, which is crucial in an era where mobile and tablet usage is prevalent.

6.4.2 How Bootstrap Enables Responsive Web Design

Bootstrap is a popular front-end framework that makes it easier to create responsive websites. It comes with a set of pre-designed components, CSS classes, and JavaScript plugins that help developers quickly build responsive, mobile-first web pages. Here’s how Bootstrap achieves responsiveness:

6.4.2.1 1. Fluid Grid System

Bootstrap uses a 12-column fluid grid system that automatically adjusts the layout of your website based on the screen size. The grid is responsive, meaning it resizes and repositions content depending on the device’s viewport size. By applying classes like .col-md-6 or .col-sm-12, you can control how much space a content block occupies on different devices.

6.4.2.2 2. Responsive Breakpoints

Bootstrap includes predefined breakpoints that allow you to apply different styles at different screen widths. These breakpoints correspond to common device sizes (e.g., mobile phones, tablets, desktops). For instance, .d-none d-md-block hides an element on small screens and shows it on medium and larger screens.

6.4.2.3 3. Flexible Media

Bootstrap provides utility classes for making media elements, like images and videos, responsive. For example, the .img-fluid class ensures that images scale to fit the width of their container, preventing them from overflowing or distorting.

6.4.2.4 4. Responsive Components

Many of Bootstrap’s built-in components, such as the navbar, modals, and carousels, are designed to be responsive out of the box. For example, the navigation bar automatically collapses into a mobile-friendly menu on smaller screens.

6.4.2.5 5. Mobile-First Design

Bootstrap is designed with a mobile-first approach, meaning that it prioritizes the mobile experience and then scales up to larger devices. This ensures that your website is optimized for the smallest screen first and progressively enhanced for larger screens.

By leveraging Bootstrap’s grid system, breakpoints, flexible media, and responsive components, developers can create websites that look great and function well across a variety of devices without needing to write extensive custom CSS.

6.4.3 Case Study: Making a Non-Responsive Home Page Responsive

The current home page is not fully responsive. Specifically, the image and text do not adapt well to different screen sizes, making the page difficult to use on mobile devices. Let’s explore how to improve this page’s responsiveness using Bootstrap.

6.4.3.1 Current Home Page Code:

{% extends 'base.html' %}

{% load static %}
{% block content %}
    <h1>Welcome to Cool Code Coach Membership Management</h1>
    <img src="{% static 'crm/images/crm_home.webp' %}" width="500" alt="Hi!"/>
    <br/>
    Developer: {{ records.developer }}
{% endblock %}

6.4.3.2 Issues:

  1. Fixed Width Image: The image has a fixed width of 500px, which may cause it to overflow or not display correctly on smaller screens.
  2. Text and Image Layout: The text and image layout does not adjust based on screen size, making it hard to read on small devices.

6.4.3.3 Making the Home Page Responsive:

  1. Use Bootstrap’s Responsive Classes:
    • Replace the fixed width of the image with Bootstrap’s .img-fluid class to make it responsive.
    • Wrap the content in a Bootstrap container and grid system to ensure proper alignment and spacing across devices.
  2. Improving Layout with Bootstrap Grid:
    • Utilize Bootstrap’s grid system to create a layout that stacks the content vertically on smaller screens.

6.4.3.4 Updated Home Page Code:

{% extends 'base.html' %}

{% load static %}
{% block content %}
    <div class="container">
        <div class="row">
            <div class="col-12 text-center">
                <h1>Welcome to Cool Code Coach Membership Management</h1>
            </div>
            <div class="col-12 text-center">
                <img src="{% static 'crm/images/crm_home.webp' %}" class="img-fluid" alt="Hi!"/>
            </div>
            <div class="col-12 text-center mt-3">
                Developer: {{ records.developer }}
            </div>
        </div>
    </div>
{% endblock %}

6.4.3.5 Explanation:

  • container: This class centers the content and adds padding on the sides for better presentation across different screen sizes.
  • row and col-12: Bootstrap’s grid system is used to organise the content into rows and columns. The col-12 class ensures that each piece of content takes up the full width of the container on smaller screens, while adjusting automatically on larger screens.
  • img-fluid: This class makes the image responsive, allowing it to scale appropriately depending on the screen size.
  • text-center: This class centers the text and image, improving the visual alignment on all devices.

By applying these changes, the home page will become more user-friendly and responsive, providing a better experience across different screen sizes.

6.4.3.6 Responsive Homepage On a Mobile Phone