Capstone: Choosing and Justifying a Framework for a Real Project
Web Framework Internals
Chapter 10 ยท Capstone: Choosing and Justifying a Framework for a Real Project
Nine chapters built real routers, real template engines, real ORMs, and real middleware chains from scratch, then checked how five real frameworks each answer the identical underlying questions. This capstone puts all of it to work on one real, concrete decision — not "which framework is best," a question this course has deliberately never tried to answer, but "which framework is best for this project," worked through criterion by criterion using nothing but findings this course already verified.
The Scenario
A four-person team at a mid-size logistics company, Meridian Freight, has six weeks to replace a spreadsheet-based shipment tracker with a real internal tool. The real requirements, gathered directly from the team:
| # | Requirement |
|---|---|
| 1 | A genuinely relational data model — shipments, carriers, routes, customers — with reporting queries that regularly join across all four |
| 2 | A separate mobile-app team (a different company) needs a real, stable, documented JSON API to build a warehouse-scanning app against, with minimal back-and-forth |
| 3 | Internal staff view delivery notes containing rich text submitted by drivers through a separate intake form — this must never become an injection vector |
| 4 | No dedicated DBA or DevOps role; the schema will genuinely change nearly every week as real requirements get clarified |
| 5 | One team member has three real years of Django experience; the other three are generalists with no strong framework preference |
| 6 | A hard six-week deadline for a working first version |
Applying Chapters 2–3: Routing
Requirement 2 — a separate team needs a stable, documented API contract, with minimal back-and-forth — maps directly onto Chapter 3's own real, verified finding: FastAPI's item_id: int annotation does genuine double duty, driving both real request validation and the live, auto-generated /docs Swagger UI page from the identical source-code declaration. None of the other four routing systems Chapter 3 checked — Django, Express, Rails, Laravel — produce that documentation automatically from the route declaration itself. For a team with a genuinely separate, external consumer of the API who needs to work independently rather than asking questions in a shared chat channel, that's not a nice-to-have; it's the single clearest, most direct match between a real requirement and a real, previously-verified framework capability anywhere in this decision.
Applying Chapters 4–5: Templating
Requirement 3 — untrusted rich text, rendered on internal pages, must never become an injection vector — is precisely the real vulnerability Chapter 4 built and closed by hand, and Chapter 5 verified across seven real systems. Django's own quoted documentation states the strongest, most direct real guarantee of any system checked: "If you're using Django's template system, you're protected." Chapter 5 also verified a genuine, real second layer worth weighing for this specific requirement — Django's own documented refusal to "invent a programming language" inside its templates, contrasted directly against Jinja2's own real, quoted ability to call arbitrary functions with arguments from inside a template. For a field genuinely fed by outside submissions, a template language that's structurally incapable of executing arbitrary logic even if a future template were written carelessly is a real, concrete defense-in-depth property, not just a marketing point.
Applying Chapters 6–7: Data Access
Requirements 1 and 4 pull in genuinely opposite directions, and Chapter 7's own real findings name the exact tension directly. SQLAlchemy's own quoted Data Mapper design — keeping the mapped class "entirely separate" from persistence logic — is real, genuine strength for requirement 1's own complex, multi-table reporting joins, since nothing about the ORM's own design constrains how a query can be shaped. But Chapter 7 also verified, directly, that SQLAlchemy ships with zero built-in migration tooling at all — Alembic is a real, separate package, installed and configured independently. For requirement 4's own weekly schema churn, with no dedicated DBA to own a separate migration tool, that's a genuine, real cost. Django's own Active Record ORM, by contrast, ships migrations built directly in, tracked automatically — the exact opposite tradeoff, at the exact opposite requirement.
Applying Chapters 8–9: Middleware
Requirement 3's own security concern extends one layer further, into middleware. Chapter 9 verified Django's own real default MIDDLEWARE list ships CsrfViewMiddleware and SecurityMiddleware already correctly ordered, out of the box — per Chapter 9's own quoted finding, Django applies this list "top-down" for the request, with the security-relevant layers already placed where Django's own documentation recommends. For a four-person team with no dedicated security review process and a six-week deadline, a framework that ships a real, already-correctly-ordered default middleware stack removes an entire category of decision the team would otherwise have to get right themselves, under real time pressure.
The Real, Reasoned Decision
Every section above, except the routing section, points toward Django. Requirement 2 — the separate mobile team's own need for a documented API contract — is the one real requirement Django's own ecosystem, verified across this course's own five routing/data-access/middleware comparisons, simply doesn't answer as directly as FastAPI does. Forcing one single framework to be equally strong at both jobs would mean accepting a real, avoidable weakness somewhere in the system, for the sake of using only one framework.
Chapter 1's own real "micro vs. full-stack" framing — not a fixed property of a framework, but "a label for exactly how many of [the] four capabilities a given framework decides to ship as standard, versus leave as an explicit, deliberate integration point for something else" — applies just as well one level up, at the level of the whole system being built, not just one framework's own feature list. The real, reasoned decision: build the internal admin and reporting application in Django, leaning directly on its own verified migrations, secure-by-default templating, and correctly-ordered default middleware for a small team under real deadline pressure — and expose a small, separate FastAPI service, reading from the identical underlying database, specifically for the warehouse-scanner API. Neither framework is asked to do the one job the other is genuinely, verifiably better at.
What Made This Decision, Chapter by Chapter
| Chapters | Real, verified finding applied | Requirement it answered |
|---|---|---|
| 1 | "Micro vs. full-stack" as a spectrum, not a fixed label — reapplied at the system level | Justifying two frameworks over one |
| 2–3 | FastAPI's type hints driving both validation and real, auto-generated /docs | #2 — a documented API for a separate team |
| 4–5 | Django's quoted "you're protected" auto-escaping, plus its real "not a programming language" restriction | #3 — untrusted rich text rendered safely |
| 6–7 | SQLAlchemy's Data Mapper query flexibility vs. Django's real built-in migrations | #1 and #4, weighed against each other directly |
| 8–9 | Django's real, correctly-ordered default MIDDLEWARE list | #3's own security dimension, and #6's time pressure |
Course complete. Every real, verified finding across all nine prior chapters was reusable here, not as trivia, but as an actual decision-making tool — the entire real point of building each mechanism by hand before ever comparing five frameworks' own real answers to it.
Hands-On Exercises
Meridian Freight's real requirement 5 changes: the team gains a fifth member with three real years of Ruby on Rails experience, and loses its one Django-experienced developer. Re-run this chapter's own Chapter 6-7 and Chapter 8-9 reasoning with Rails substituted for Django, and explain whether the final two-framework decision (Rails + FastAPI, in this revised scenario) would still make sense, or whether some other combination now reads better.
๐ View solutionThis chapter's own decision explicitly weighs requirement 4 (weekly schema churn, no dedicated DevOps) more heavily than requirement 1 (complex reporting joins) when choosing Django's own built-in migrations over SQLAlchemy's own Data Mapper flexibility. Construct a genuinely different real scenario โ changing only requirements 1 and 4 โ where that specific weighting should flip, and explain why.
๐ View solutionThis chapter's own final decision uses two separate frameworks reading from one shared database. Using Chapter 8's own real middleware concepts specifically, identify one genuine, concrete risk this split introduces that a single-framework system would not have to deal with at all, and explain what kind of check (in either the Django app or the FastAPI service) would need to exist to manage it.
๐ View solutionChapter 10 Quick Reference
- The real question this capstone answers โ not "which framework is best," but "which framework is best for this project," using nothing but findings this course already verified
- Routing (Ch.2-3) โ FastAPI's own verified type-hint/auto-docs finding directly answered a real, separate-team API-documentation requirement
- Templating (Ch.4-5) โ Django's own quoted auto-escaping guarantee and its real "not a programming language" restriction directly answered a real untrusted-content requirement
- Data access (Ch.6-7) โ SQLAlchemy's real query flexibility vs. Django's real built-in migrations, weighed directly against this specific project's own real constraints
- Middleware (Ch.8-9) โ Django's own real, correctly-ordered default MIDDLEWARE list reduced real decision-making load under deadline pressure
- The real, honest conclusion โ two frameworks, each used specifically where its own verified strength directly serves a real requirement, applying Chapter 1's own "micro vs. full-stack" framing at the level of a whole system
- Course complete โ Web Framework Internals, 10/10 chapters