Day 10 · 1 Hour
Frontend — HTML + JS + API
fetch() calls your Django API — build a live dashboard without page reloads.
🔥 Real-World Hook (0–5 min)
Your DRF API returns JSON. But no one wants to use curl. Users want buttons, tables, forms.
Today you build an HTML + JavaScript frontend that calls your Django API and shows real data. This is exactly how Swiggy's web frontend talks to their Python backend — fetch() hits an API endpoint, the response renders in the browser. No page reloads. Full-stack.
🌐 Browser ↔ API in 3 Steps (5–25 min)
💡 The Pattern
Step 1: User loads the HTML page — just static HTML, no data yet.
Step 2: JavaScript runs fetch("/api/students/") — calls your Django API.
Step 3: API returns JSON — JavaScript puts it in the page without reloading.
💻 Live Coding — Student Dashboard (25–45 min)
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>Student Dashboard</title>
<style>
body { font-family: sans-serif; max-width: 800px; margin: 2rem auto; padding: 0 1rem; }
table { width: 100%; border-collapse: collapse; margin-top: 1rem; }
th, td { padding: .6rem 1rem; border: 1px solid #ddd; text-align: left; }
th { background: #2563eb; color: white; }
tr:nth-child(even) { background: #f8f9fa; }
.btn { background:#2563eb; color:#fff; border:none; padding:.5rem 1rem; border-radius:6px; cursor:pointer; }
.form-row { display:flex; gap:.5rem; margin:.5rem 0; }
.form-row input { flex:1; padding:.4rem; border:1px solid #ccc; border-radius:4px; }
</style>
</head>
<body>
<h1>🐍 Student Dashboard</h1>
<div class="form-row">
<input id="name" placeholder="Name">
<input id="email" placeholder="Email">
<input id="dept" placeholder="Dept">
<input id="gpa" placeholder="GPA" type="number" step=".1">
<button class="btn" onclick="addStudent()">Add</button>
</div>
<table>
<thead><tr><th>Name</th><th>Email</th><th>Dept</th><th>GPA</th><th>Action</th></tr></thead>
<tbody id="table-body"></tbody>
</table>
<script>
const API = "http://127.0.0.1:8000/api/students/";
async function loadStudents() {
const res = await fetch(API);
const data = await res.json();
const tbody = document.getElementById("table-body");
tbody.innerHTML = data.map(s => `
<tr>
<td>${s.name}</td>
<td>${s.email}</td>
<td>${s.dept}</td>
<td>${s.gpa}</td>
<td><button class="btn" onclick="deleteStudent(${s.id})">Delete</button></td>
</tr>`).join("");
}
async function addStudent() {
const body = {
name: document.getElementById("name").value,
email: document.getElementById("email").value,
dept: document.getElementById("dept").value,
gpa: document.getElementById("gpa").value,
};
await fetch(API, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body)
});
loadStudents(); // refresh table
}
async function deleteStudent(id) {
await fetch(`${API}${id}/`, { method: "DELETE" });
loadStudents();
}
loadStudents(); // load on page open
</script>
</body>
</html>
🎯 You Code It (45–55 min)
- Create the HTML file above, open it in browser — is the table loading from your API?
- Add an "Edit" button that shows a prompt, takes a new GPA, and sends PATCH request
- Add a search input + filter button: on click, fetch
?search=termand refresh table - Add CSS: highlight rows where GPA < 2.5 in red background
- Bonus: Add department filter dropdown — selecting "CS" fetches only CS students
- Show: Add a student, delete one, search by name — all without page reload
📄 Day 10 Cheat Sheet — JS + Fetch API
fetch() Patterns
| fetch(url) | GET request |
| await fetch(url) | Wait for response |
| await res.json() | Parse JSON body |
| res.status === 200 | Check success |
| res.ok | True if 2xx status |
POST / PUT / DELETE
| method: "POST" | Create |
| method: "PUT" | Full update |
| method: "PATCH" | Partial update |
| method: "DELETE" | Delete |
| headers: {Content-Type: application/json} | Tell server it's JSON |
DOM Manipulation
| document.getElementById("id") | Get element |
| el.innerHTML = html | Set HTML content |
| el.value | Input value |
| data.map(x => `html`).join("") | Array to HTML |
| onclick="fn(id)" | Click handler |
async / await
| async function fn() {} | Declare async |
| await promise | Wait for result |
| try { } catch(e) { } | Handle errors |
| Promise.all([p1, p2]) | Run in parallel |