Python Tutorial: Generate a Web Portfolio and Resume from One JSON File
Based on Corey Schafer's video on YouTube. If you like this content, support the original creators by watching, liking and subscribing to their content.
Store all portfolio and resume content in one JSON file so updates propagate to both outputs automatically.
Briefing
A single JSON file can drive both a web portfolio and a traditional one-page resume—generated automatically by Python—so updates never fall out of sync. Instead of editing multiple documents by hand, the workflow centralizes all personal and career data (contact info, social links, work history, projects, volunteer work, education, and optional images) in one place, then renders two separate static HTML outputs from that same source.
The finished deliverables are two static pages: a more personality-forward portfolio suitable for sharing via a URL, and a stripped-down resume designed to print cleanly and fit on one page. The portfolio keeps elements like social media links, images, and sections such as hobbies/interests, and it’s styled to be responsive for smaller screens. The resume version removes those extras—no social links, no images, and fewer sections—so it aligns with what employers expect in PDF or print form.
Under the hood, the approach uses Jinja2 templates (similar in concept to templating in Flask/Django). One HTML template targets the portfolio layout, while a second template targets the resume layout. The templates use placeholders to pull values from the JSON, conditionals to include optional content only when data exists (for example, rendering an image block only if an image path is present), and loops to repeat sections like social media links or work experience entries. Simple data cleanup also happens inside templates using Jinja filters—for instance, formatting phone numbers by stripping hyphens.
To keep the JSON tidy, image and SVG assets are referenced by relative paths rather than embedded directly. Before rendering, the Python script loads the JSON into a dictionary, then enriches it by reading SVG files from disk and injecting their contents into a new field (so the templates can safely inline the SVG markup). It also adds computed values like the current year for the copyright line.
The script sets up a Jinja2 environment with auto-escaping enabled to reduce cross-site scripting risk, loads both templates from the filesystem, renders them with the same data, and writes the results to two static files (index.html for the portfolio and resume.html for the resume). Because the outputs are plain HTML, there’s no backend server required—either page can be opened directly in a browser or deployed easily.
Finally, the workflow is designed to be reusable: swapping in a different portfolio JSON file (and adding matching images under a media folder) regenerates both the portfolio and resume with the new content. The CSS styling is intentionally customizable—Corey Schafer notes the layout is opinionated and encourages replacing the styling with frameworks like Bootstrap or Tailwind if preferred. The overall payoff is operational: one source of truth, two formats, and a repeatable process that’s easy to rerun whenever career details change.
Cornell Notes
Centralizing resume and portfolio content in one JSON file lets Python generate two separate static HTML outputs: a responsive web portfolio and a print-friendly, one-page resume. Jinja2 templates pull values from the JSON using placeholders, loops for repeating sections (like work history and social links), and conditionals to include optional blocks (like images) only when data exists. The Python script loads the JSON, enriches it by inlining SVG contents from file paths, adds computed fields like the current year, and renders both templates with auto-escaping enabled for safer HTML output. Because the results are static HTML, they can be opened directly or deployed without a backend.
How does one JSON file become two different documents without duplicating data entry?
What mechanisms in Jinja2 make the templates flexible for real-world resume data?
Why does the Python script read SVG files and inject them into the JSON data before rendering?
How does the setup reduce security and formatting problems in generated HTML?
What makes the outputs easy to deploy compared with a typical web app?
Review Questions
- If your JSON has an empty image path, what should happen in the portfolio HTML, and which template feature enforces that behavior?
- Where in the workflow does SVG content get inlined, and why isn’t it stored directly in the JSON from the start?
- How do the portfolio and resume templates differ in which sections they render, and how does that affect print/PDF readiness?
Key Points
- 1
Store all portfolio and resume content in one JSON file so updates propagate to both outputs automatically.
- 2
Use two Jinja2 templates—one portfolio layout and one resume layout—so the same data renders into different formats.
- 3
Rely on Jinja2 conditionals to include optional sections (like images) only when the JSON provides the needed fields.
- 4
Use Jinja2 loops and filters to render repeated lists (work history, social links) and to format values (like stripping hyphens from phone numbers).
- 5
Inline SVG icons by having Python read SVG files from paths listed in JSON and inject the SVG markup into the data before rendering.
- 6
Generate static HTML files with auto-escaping enabled to reduce XSS risk, then deploy or print without needing a backend server.
- 7
Swap in a new JSON file (and matching media assets) and rerun the script to regenerate both documents with new content.