Django REST Framework: Exposing an API Layer
Food Tracker (Django)
Chapter 11 · Django REST Framework: Exposing an API Layer
Chapter 8 deliberately avoided DRF for one simple search endpoint. By now there are four genuinely JSON-shaped features — search, add-item, mark-used, recipe lookup — plus Chapter 5's own full-page-reload cost still unresolved. That's the actual threshold this chapter waits for.
Installing DRF
A Serializer Isn't a Second ModelForm
Like Chapter 6's ModelForm, ModelSerializer derives its fields directly from the same Item model — no separate schema class to duplicate. But it's built for JSON in, JSON out, with no HTML rendering assumption at all. And read_only_fields works differently from Chapter 6's own commit=False pattern: commit=False lets the view set server-controlled fields after the form validates but before saving; read_only_fields instead tells the serializer itself to include a field in output (a GET response) while silently ignoring any attempt to set it via input — a genuinely different mechanism arriving at a similarly-shaped safety outcome, not the identical technique wearing a new name.
ViewSets and Routers: The Pattern Repeats, One Level Up
One ViewSet class, registered with a router, auto-generates a full set of RESTful endpoints — list, create, retrieve, update, delete — with no individual view functions written by hand for any of them. It's Django's own "batteries included" philosophy repeating itself one level deeper, this time inside DRF specifically.
The Honest Hybrid Shape
This chapter doesn't throw away Chapters 3 through 10 and replace everything with DRF. The admin (Chapter 3) stays exactly what it was. The dashboard and history pages could keep their server-rendered templates for the parts that don't need deep interactivity, while search, add-item, mark-used, and recipe lookup can genuinely migrate to these new /api/ endpoints, called via fetch() instead of a full-page form POST or redirect. Some pages stay templates; some features become a real JSON API. This hybrid shape is the honest, common reality most substantial Django applications actually settle into — not a failure to fully commit to one philosophy.
/api/items/ in an ordinary browser renders a genuinely pleasant, interactive HTML exploration UI for the JSON API itself — automatically, with zero extra code required to get it.
fetch() a DRF endpoint directly from the browser doesn't exempt that call from Django's own CSRF protection — a same-origin, session-authenticated browser request still needs the CSRF token included in the request's own headers for any unsafe method (POST/PUT/DELETE). Forgetting it produces the exact same 403 rejection Chapter 6 already covered for a template form, just now from JavaScript instead of an HTML <form>.
Where This Course Is Headed
Deployment, and a capstone tying every chapter together into one complete, working app.
Hands-On Exercises
Explain why this chapter is genuinely the right point to introduce DRF, tying your answer back to Chapter 8's own reasoning for avoiding it. What specifically changed between Chapter 8 and now?
📄 View solutionExplain the difference between Chapter 6's commit=False pattern and this chapter's read_only_fields. Both prevent user control of a field — how do they actually achieve that differently?
📄 View solutionExplain why switching Chapter 5's scan flow from a template form POST to a fetch() call against a DRF endpoint doesn't bypass Django's CSRF protection, and what would happen if the CSRF token were left out of that fetch() call.
📄 View solutionChapter 11 Quick Reference
ModelSerializer— derives from the same model asModelForm, but for JSON, not HTMLread_only_fieldsvs.commit=False— genuinely different mechanisms, similar safety outcomeViewSet+ router — one class auto-generates a full RESTful endpoint set- The hybrid shape — templates and a JSON API coexisting is the honest norm, not a compromise
- CSRF still applies to same-origin
fetch()calls — the token must be sent explicitly in headers - Next chapter: Deployment