Barcode Lookup: Integrating Open Food Facts
Food Tracker (Django)
Chapter 4 · Barcode Lookup: Integrating Open Food Facts
The admin gave a working CRUD interface for free. This chapter writes the first genuinely custom code in this course: a view that turns a scanned barcode into a real product name.
URLs and Views: Two Separate Files, on Purpose
Django deliberately keeps "which URL triggers this code" (urls.py) separate from "what that code actually does" (views.py) — two files, wired together explicitly. FastAPI's own decorator-based routing (@app.get("/path")) puts both in the same place, directly above the function it decorates. Neither is objectively better; it's a real, structural difference in where that one piece of wiring lives, worth knowing rather than assuming every framework does it the same way.
A Second Model: BarcodeCache
Open Food Facts needs no API key here either, so the same reasoning that justified a Cloud Function in this app's own Firebase sibling course applies again: caching, consistent error handling, future-proofing — nothing about secrecy.
Note primary_key=True on barcode here — the exact opposite of Chapter 2's own Item model, where barcode is deliberately an ordinary field, never the primary key, because the same product can be purchased and tracked more than once. BarcodeCache genuinely is one record per product, so keying it directly by barcode is correct here.
The View
Wiring the URL
<str:barcode> is Django's own path converter — it types and captures the URL segment directly inside the route pattern string, rather than as a Python function type annotation the way FastAPI declares a path parameter's type.
Migrating the New Model
requests Isn't a Django Battery
Worth being precise about what "batteries included" actually covers: Django ships an ORM, an admin, forms, and templating — everything for building the app's own request/response cycle. Making an outbound call to someone else's API is a different job entirely, and needs a separate library (pip install requests) regardless of how much Django itself provides natively.
Item tracks purchased instances (many can share a barcode); BarcodeCache tracks canonical products (exactly one per barcode). This app's own Firebase sibling course faced the identical question for its items vs. barcodeCache collections, and landed on the same answer for the same underlying reason — proof this is a genuine data-modeling principle, not a coincidence of one particular database technology.
/lookup/<a-real-barcode>/ directly in a browser returns the raw JSON response — a genuinely useful way to confirm this view works correctly before any frontend exists at all, the same "test one layer in isolation" habit Chapter 3's manage.py shell tip already established.
try/except around the requests.get() call at all. If Open Food Facts is slow, times out, or is simply down, this raises an unhandled exception, and whoever called this endpoint gets a raw Django 500 error page instead of a clean, meaningful response. This is a genuine, known gap in this simple version — a production-ready version would wrap the request in error handling and return a proper JSON error response instead of letting the exception propagate.
Where This Course Is Headed
Camera-based barcode scanning, the add-item flow via Django Forms, expiry alerts, item history and search, marking items used, recipe lookup, Django REST Framework, deployment, and a capstone.
Hands-On Exercises
Explain the structural difference between Django's separated urls.py/views.py routing and FastAPI's decorator-based routing. Where does "this URL maps to this code" actually live in each?
📄 View solutionExplain why BarcodeCache uses barcode as its primary key while Item does not, and connect this to how the Firebase sibling course resolved the identical design question.
📄 View solutionExplain what actually happens right now if Open Food Facts is down or times out while this view is running, and why this is described as a genuine, known gap rather than an acceptable final state.
📄 View solutionChapter 4 Quick Reference
- urls.py / views.py — routing and logic deliberately kept separate, unlike FastAPI's combined decorator approach
BarcodeCache—barcodeas primary key, correctly, since this collection is one-per-product<str:barcode>— Django's own URL path converter/typing systemrequests— not a Django battery; outbound API calls still need a separate library- Known gap — no error handling yet for a failing Open Food Facts request; a real 500 error results today
- Next chapter: Camera-Based Barcode Scanning (Frontend)