Perfect 🚀 Let’s expand your Country Data Dashboard into a modular, production-style repo with SQLite + SQLAlchemy integration.


📂 Final Repo Structure

string_project/
├── app.py                # Flask entrypoint
├── config.py             # Config (DB path, API URL)
├── requirements.txt
├── data_fetch.py         # Fetch data from API
├── data_clean.py         # String cleaning & transformations
├── models.py             # SQLAlchemy ORM models
├── populate_db.py        # Populate DB with cleaned data
├── templates/
│   ├── home.html
│   └── countries.html
├── static/
│   └── style.css
└── dashboard.db          # SQLite DB (auto-created)

🔹 requirements.txt

flask
pandas
requests
sqlalchemy
plotly

🔹 config.py

API_URL = "https://restcountries.com/v3.1/all"
DB_URL = "sqlite:///dashboard.db"

🔹 models.py

from sqlalchemy import Column, Integer, String, Float
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from config import DB_URL

Base = declarative_base()
engine = create_engine(DB_URL, echo=False)
SessionLocal = sessionmaker(bind=engine)

class Country(Base):
    __tablename__ = "countries"
    id = Column(Integer, primary_key=True, index=True)
    name = Column(String, unique=True, nullable=False)
    region = Column(String)
    capital = Column(String)
    population = Column(Integer)
    area = Column(Float)
    name_length = Column(Integer)

def init_db():
    Base.metadata.create_all(bind=engine)

🔹 data_fetch.py

import requests
import pandas as pd
from config import API_URL

def fetch_data():
    res = requests.get(API_URL)
    countries = res.json()
    df = pd.json_normalize(countries)
    return df

🔹 data_clean.py

import pandas as pd

def clean_data(df):
    df['name.common'] = df['name.common'].str.strip().str.title()
    df['region'] = df['region'].fillna("Unknown").str.upper()
    df['capital'] = df['capital'].astype(str).str.replace(r"[\[\]']", "", regex=True)
    df['name_length'] = df['name.common'].str.len()

    return df[['name.common', 'region', 'capital', 'population', 'area', 'name_length']]

🔹 populate_db.py

from data_fetch import fetch_data
from data_clean import clean_data
from models import Country, init_db, SessionLocal

def populate():
    init_db()
    df = clean_data(fetch_data())
    session = SessionLocal()

    for _, row in df.iterrows():
        country = Country(
            name=row['name.common'],
            region=row['region'],
            capital=row['capital'],
            population=row['population'],
            area=row['area'],
            name_length=row['name_length']
        )
        session.merge(country)  # merge avoids duplicate insert
    session.commit()
    session.close()

if __name__ == "__main__":
    populate()
    print("Database populated successfully ✅")

🔹 app.py

from flask import Flask, render_template, request
from models import SessionLocal, Country

app = Flask(__name__)

@app.route("/")
def home():
    session = SessionLocal()
    total_countries = session.query(Country).count()
    total_population = session.query(Country).with_entities(Country.population).all()
    total_population = sum([p[0] for p in total_population if p[0]])
    largest_country = session.query(Country).order_by(Country.area.desc()).first()
    session.close()

    summary = {
        "total_countries": total_countries,
        "total_population": total_population,
        "largest_country": largest_country.name if largest_country else None
    }
    return render_template("home.html", summary=summary)

@app.route("/countries")
def countries():
    q = request.args.get("q", "")
    session = SessionLocal()
    query = session.query(Country)
    if q:
        query = query.filter(Country.name.ilike(f"%{q}%"))
    countries = query.all()
    session.close()
    return render_template("countries.html", countries=countries, query=q)

if __name__ == "__main__":
    app.run(debug=True)

🔹 templates/home.html

<!DOCTYPE html>
<html>
<head>
  <title>Country Dashboard</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
</head>
<body class="container mt-4">
  <h1>🌍 Country Dashboard</h1>
  <p>Total Countries: {{ summary.total_countries }}</p>
  <p>Total Population: {{ summary.total_population }}</p>
  <p>Largest Country (Area): {{ summary.largest_country }}</p>
  <a href="/countries" class="btn btn-primary mt-3">Browse Countries</a>
</body>
</html>

🔹 templates/countries.html

<!DOCTYPE html>
<html>
<head>
  <title>Countries</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
</head>
<body class="container mt-4">
  <h2>Countries</h2>
  <form method="get">
    <input type="text" name="q" value="{{ query }}" placeholder="Search by name">
    <button type="submit" class="btn btn-primary btn-sm">Search</button>
  </form>
  <table class="table table-striped mt-3">
    <thead>
      <tr>
        <th>Name</th>
        <th>Region</th>
        <th>Capital</th>
        <th>Population</th>
        <th>Area</th>
        <th>Name Length</th>
      </tr>
    </thead>
    <tbody>
      {% for c in countries %}
      <tr>
        <td>{{ c.name }}</td>
        <td>{{ c.region }}</td>
        <td>{{ c.capital }}</td>
        <td>{{ "{:,}".format(c.population) if c.population else "" }}</td>
        <td>{{ c.area }}</td>
        <td>{{ c.name_length }}</td>
      </tr>
      {% endfor %}
    </tbody>
  </table>
</body>
</html>

🔹 How to Run

# 1. Clone / create folder
cd string_project

# 2. Create env & install deps
python -m venv venv
venv\Scripts\activate      # Windows
source venv/bin/activate   # Linux/Mac
pip install -r requirements.txt

# 3. Populate DB
python populate_db.py

# 4. Run Flask app
python app.py

Then open → http://127.0.0.1:5000/


⚡ This repo is now:
✔ Modular (fetch → clean → DB → app).
✔ SQLite via SQLAlchemy ORM.
✔ Easily extendable (charts, filters, etc.).


Do you also want me to add interactive charts (Plotly) into the dashboard (e.g., population by continent) to make it more data-