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-science / analytics style?