# Python Tutorial: Generate a Web Portfolio and Resume from One JSON File

## Метаданные

- **Канал:** Corey Schafer
- **YouTube:** https://www.youtube.com/watch?v=ECt0TAl41Zk
- **Дата:** 11.03.2025
- **Длительность:** 24:10
- **Просмотры:** 37,347

## Описание

In this video, we'll be learning how to use Python and JSON to create both a web portfolio and a traditional resume from a single source of data. We'll use Jinja2 templates to generate static HTML files that are easy to deploy and maintain. This approach ensures your portfolio and resume are never out of sync, as updates to your JSON file automatically reflect in both versions. We'll cover the complete process, from structuring your data in JSON to setting up templates and writing the Python code that bridges them together. By the end of this tutorial, you'll have a streamlined way to manage your web portfolio and resume efficiently. Let's get started...

The code from this video can be found at:
https://github.com/CoreyMSchafer/portfolio_generator

Deploy Portfolio Tutorial - https://youtu.be/AD-3nVI3-_U
JSON Resume Site - https://jsonresume.org/

✅ Support My Channel Through Patreon:
https://www.patreon.com/coreyms

✅ Become a Channel Member:
https://www.youtube.com/channel/UCCezIgC97PvUuR4_gbFUs5g/join

✅ One-Time Contribution Through PayPal:
https://goo.gl/649HFY

✅ Cryptocurrency Donations:
Bitcoin Wallet - 3MPH8oY2EAgbLVy7RBMinwcBntggi7qeG3
Ethereum Wallet - 0x151649418616068fB46C3598083817101d3bCD33
Litecoin Wallet - MPvEBY5fxGkmPQgocfJbxP6EmTo5UUXMot

✅ Corey's Public Amazon Wishlist
http://a.co/inIyro1

✅ Equipment I Use and Books I Recommend:
https://www.amazon.com/shop/coreyschafer

▶️ You Can Find Me On:
My Website - http://coreyms.com/
My Second Channel - https://www.youtube.com/c/coreymschafer
Facebook - https://www.facebook.com/CoreyMSchafer
Twitter - https://twitter.com/CoreyMSchafer
Instagram - https://www.instagram.com/coreymschafer/

#Python #Portfolio

## Содержание

### [0:00](https://www.youtube.com/watch?v=ECt0TAl41Zk) Segment 1 (00:00 - 05:00)

hey there how's it going everybody in this video we're going to be learning how to create a web portfolio and a resume using Python and Json so this is the process that I personally use to update my own portfolio and resume and I think a lot of you are going to find this useful so if you only have a resume and don't have a web portfolio with a URL that you can send to a potential employer then I think you're really limiting yourself in terms of uh who you might be able to get your information in front of for potential jobs uh but having mult versions of something like this uh can be a bit of a pain when you want to make updates uh so in this video I'm going to show how I use Python and Json to create both versions of these from a single source of data so that they're never out of sync and you don't have to go in and update each of those manually uh you just have to update your Json file and both of them get generated simultaneously uh to show you what I mean let's look at the finished product of what we'll be creating in this video so a while back in my community tab I asked you all to send me in some examples of your current resumés and I took a lot of inspiration from those in order to create a template of both a web portfolio and a resume that I think is going to work for a lot of you and I'm just using a custom CSS stylesheet that I created to style this so if you don't necessarily like the style and you know some CSS uh then this should be super easy for you to update to and add your own customizations um and even style it completely from scratch if you'd like uh with CSS uh you basically have unlimited styling options so here we have the web portfolio and this would be something that you'd host on a website that you can send to employers these are usually a bit more relaxed than a traditional resume and allow you to show a bit more of your personality so here you can see that I have a couple of social media links in here uh there are some images further down I list some hobbies and interests and things like that and I also styled this to be responsive uh so if we resize this um then it should uh respond accordingly and look good on uh smaller Windows as well so on mobile or um desktop now with this same data I also generated a more traditional looking resumé uh that's using a strip down version of that same data uh so this is this here and we can see that uh this resume is more traditional and More in line with uh what companies expect to see when you send them a resume in PDF or print form so I've taken out the social media links I've removed the images and we don't have things like interest or Hobbies or anything like that um I think it's fine to put interests or hobbies in some uh traditional resumés if you have the room uh but for this example I just wanted this to fit onto a single page uh when we printed this so if I go to print this then we can see that this fits nicely on one page and we can also easily uh save this as a PDF so that's the portfolio and resume that are both generated within python both of them are static HTML files which means that they uh don't need any backend code to serve them up and are also a lot easier to deploy uh so let's take a look at the data that was used to generate these pages and then we'll go over the python code that ties all of this together so let me bring up my vs code here so I have a lot of these files already created here and all of the code from this video is going to be available on my GitHub and I'll leave a link to that repository in the description section below so first off let's look at the Json file here so this is called portfolio. Json now this is the format that I use for my personal portfolio and resume but you can change this depending on your needs as well the whole point here is to make something that works easily for you uh whatever that is but you can see here that this is basically just a Json that holds a bunch of in information uh that you might find in a portfolio so we have our name we have our contact information um here we have our social media links uh for anything that has an image I put uh a relative path to that image so uh you can see here that I have some svgs for the social media links and those svgs are located in the IMG image folder then as we go uh further down here I just have uh these different sections broken up in a way that they're most useful uh to me so I have my work experience and uh that's a list of different uh Json objects uh for each of uh my previous jobs and every object has the company name uh my position there start date in date a summary and things like that and if I scroll down a little bit further uh we can just see some more information that we might uh want to

### [5:00](https://www.youtube.com/watch?v=ECt0TAl41Zk&t=300s) Segment 2 (05:00 - 10:00)

show off so I have some projects here um if I go down a little further we have some volunteer experience uh our education history and things like that now I should mention that as I was making this video I was curious if anyone else uh did their rums and portfolios like this and I stumbled onto a site called Json res. org and they have an open- Source standard that they've come up with for uh J on resumé data and it's a bit different than how I have mine set up here uh but if you're interested I'm going to leave a link to that page in the description section below so you can see that the way that they structure theirs um they do a lot of similar things to how I have mine set up and after looking theirs over I even took a couple of their ideas and implemented it into mine here okay so that's the data that we're working with uh the next thing that we need is an HTML template uh for how we want this data to be presented so I have two templates one is for our web portfolio and the other is for our more traditional resume and again we're going to be using Ginger 2 and some of you have probably seen what Ginger 2 templates look like if you've ever worked with flask uh it's similar to the templating language uh used in D Jango as well so let me pull up these HTML templates and show you what these look like so we can see that this looks pretty much like a normal HTML file uh since I was putting this code out there for others to use I updated this to use modern HTML where I could and tried to keep things uh certain things in mind when designing this uh like keeping it as simple as possible and also adding in some things that can help with SEO accessibility and things like that and I've also added in comments throughout here um so that we can uh understand exactly uh what's going on and why each uh piece of this HTML code is in here now the big difference between this template and a normal HTML file is that we're going to use these placeholders throughout to specify where we want certain things from our data so for example we can see that the uh title for my web page here uh has this name within braces and then this hyphen portfolio so when our template is populated with our data this name placeholder will be replaced with the name that's in our data so right now I just have the sample file so that is uh just your name so this is going to say your name- portfolio for the title of that page and really it's almost as simple as that uh now it can get a little bit more in depth so for example we might want a conditional where a certain part of the HTML is only generated if the data exists uh so if I scroll down here a bit um right here then we can see here that we have a conditional where I only want this image created if there is an image path in the data so that makes it so that uh some of your data can be optional so if we leave the image path blank then it'll just skip over this part of the HTML and leave out an image and these Ginger 2 conditionals have their own syntax so that we uh we can see here that these uh have these braces and then percent signs uh to open it up and then we have our if statement and we're saying if image path and then all of this is within the conditional here and then down here at the bottom we have to close out with this end if so that's the basic syntax that you're likely going to see when working with Ginger 2 templates um now it doesn't get much more complicated uh than that if I scroll down here we can see that we have a for Loop here so I'm Le uh looping over the uh social media links here I'm just saying for Link in social media links and then creating uh some HTML tags for each of those and then down here instead of indif I'm doing an end4 now you're most likely not going to be doing anything too complicated in these templates if there's anything too complicated that you need to do then I recommend doing that in the python script before passing it to the templates if possible uh but sometimes we will want to filter out our data just a bit uh so for example I have one example here with our phone number and right here within the braces for the template I'm saying that I want the contact. phone number and then I'm using this pipe character here and that pipe character is a ginger filter operator and that allows us to run some methods on our data in this case I'm just removing the uh replacing the hyphens and replacing them with an empty string so that only the digits are

### [10:00](https://www.youtube.com/watch?v=ECt0TAl41Zk&t=600s) Segment 3 (10:00 - 15:00)

left in this uh HTML code here and that's really about as complicated as it gets at least for this example now if I scroll down here a bit um then I don't think there is much more I think there was let me find it here I think it was with the uh svgs yep right here uh I'm just marking this as safe because uh we are putting in some SVG data that we actually uh have saved on our local file system and we're just telling it that this is safe uh so that we're protecting ourselves from some cross-site scripting otherwise any type of code or HTML uh that you try to uh put into your templates it's going to get Auto escaped which is a good thing because we don't want uh things being injected into our HTML files so really quick we actually haven't looked at the template all that much yet um so let me just go through um and point out a few things here so we just have our header here and in our header we're going to have things like our name our contact information our social media links and a summary and then down here in the main part of the page that's where we get to things like uh work experience and looping over all those and then our projects of those volunteer experience references and then in my sidebar here that's where I'm putting the information for um education skills um language interests and that is it at the bottom I have a uh copyright tag there so that is the entire HTML template for the web portfolio and you can have as many different templates as you want uh so I also have a template for the print version of this resumé so if I open this up this is rumor template. HTML so in here we're going to have a few differences uh some of these HTML headers are going to be the same uh which as I'm saying that out loud now uh probably means that it should be in its own template so that we're not repeating ourselves uh but that's something I could perhaps add later on um anyways let me scroll down here to see what's different so one of the main differences here is that I have this main. css stylesheet that I use in the portfolio template but I'm also adding this resume. CSS stylesheet that overwrites several of those styles to make them more printer friendly and also Styles it with a more traditional look that we are going for with this more traditional resume and this template's also going to be a lot shorter because I'm not using all of the data from the J Json uh this one is meant to be more stripped down so it doesn't have the images I'm not including those and some of the extra sections like interests and things like that um aren't included here okay so now we've seen the Json data and both of the templates that we're working with now let's look at the python script that Bridges both of these together now I already have this written out but we'll go over this to make sure that we know exactly what it's doing and then I'll show you how I can drop in my own personal data and images and generate some pages for myself so first of all to get this to run you're going to need to install Ginger 2 and you can do that with a simple pip install Ginger 2 and at the top of the script here we're importing a few things that we're using from the standard Library uh and then from Ginger 2 we're importing environment and file system loader to set up our templating so the first thing we do is we load in our Json data using json. load on that portfolio that we saw earlier and this will load in all of that data as a python dictionary and since this is just a python dictionary if we need to add any additional information after we loaded in the Json then we can do that just by adding more key value pairs so for example right here I'm adding the current year to our data because in the portfolio template I have it generate a copyright tag automatically using the person's name in the data so generating uh this year dynamically uh should always give us the right year for that tag and also here for the social media logos I just have the path to the SVG file listed in the data but to embed the svgs directly into the HTML what I'm doing here is I'm going to open those a SVG files and store the content into a new key called SVG data so basically just to walk through this all I'm saying is if we have social media links then Loop over all of those links and then we get the SVG path which is the file path open that and then we are going to read in that the contents of that file and

### [15:00](https://www.youtube.com/watch?v=ECt0TAl41Zk&t=900s) Segment 4 (15:00 - 20:00)

then add that uh to a new key value pair uh within that link called SVG data so that allows us to keep our Json nice and clean without putting in the full contents of the SVG data in there and just putting that file path and then just adding that in here in the python after we read in that file so adding extra stuff to the data like this before passing it into the template uh might not be something that you need to do when working with Ginger templates but just in case you do I wanted to have a couple of examples in here uh just so we could see what that looks like to add to our data before passing it to our templates okay so now we're ready to pass our data to those HTML templates that we saw earlier so to do this we're going to create a Ginga environment and then we are using the file system loader to tell Ginger to uh look for our templates in the current directory which is what this uh dot here is now if your templates are located in a different location then you can specify that uh here but for this project I have the Python scripts and the templates in the same directory and we are also enabling uh Auto escaping like I mentioned before to help protect against cross-site scripting attacks by automatically escaping HTML in our output and this is all we need to do in order to set up our Ginger 2 environment now if you've used Frameworks like flask these environments get set up automatically for us uh but when working with Ginger 2 directly like we're doing here then this is usually how we're going to do it okay so now after creating this environment uh we use it to get uh both of our templates with the get template method here uh one of these I have located at index template. HTML and the other is at rum template. HTML and now we can pass the data to our templates to render the final static HTML so we're using the render method on this index template and what I'm doing here is I'm unpacking the dictionary and passing that into our render method now if you've never seen unpacking before then I've added a comment below here uh to show what this is equivalent to uh essentially it's the same as passing each key value pair as a separate keyword argument so it's basically the same as saying name is equal to the value of name within the data label label within the data and so on and basically this just makes it to where the ginger template receives each value directly rather than having to look up each value within that dictionary okay so that render method is going to take that data pass it into our template and then generate the HTML and we've captured that HTM ml output into two different variables here so we have our HTML output and our resumé output this should probably be portfolio output um I can change that later and now with that HTML uh we're just going to write these out to two new files and I called these index. html and resume. HTML and finally at the end of the script here I have a uh simple print statement saying that the HTML files have been generated so if I run this script then we can see that it says HTML file generated successfully and since these are static HTML files that got generated I don't need a web server or anything fancy to run these I can simply just open these up in the browser directly so to do this if I just uh copy the path of this index. html uh and go to my browser then without running um a web server or anything I can just post that in and um we can see that it renders our static HTML for us and just to make sure that we have both of these let me replace this index with resume and run that and we can see that our print version looks good as well okay so we can see that these look pretty good now everything that I've shown so far is what I'm going to ship with the code and post up on GitHub for other people to use if they want uh but let me show an example of how someone might do this if they decide to use it for themselves so with my project here let me open up um my two different locations here so this is basically the file structure that uh we're going to see if that someone would see if they downloaded this from GitHub and what I'm going to do here is I'm just going to drop in uh my own portfolio. Json file uh that has my personal information in it and I've just labeled that portfolio dy- uh or Json and then I have some portfolio media here this is just some

### [20:00](https://www.youtube.com/watch?v=ECt0TAl41Zk&t=1200s) Segment 5 (20:00 - 24:00)

uh pictures and images um that I am going to link within that data so now let me go back to VSS code here and I'm going to uh pull up this new Json file that I just dropped in and I could have kept this named portfolio. Json I just named it uh differently to differentiate from what we had before but we can see that I have my basic info in here uh for the image path I'm using the relative path to uh a JPEG photo uh that's in that portfolio media directory that I just dropped in and for the rest of this I'm using my uh own social media links and work history and things like that um so just the things that you would see on any portfolio or resume so I haven't changed anything else here other than uh changing this Json and um dropping in that portfolio media with some pictures so now I can just come back to my python script here and regenerate our portfolio and resume now I did change the name of that Json file uh so just to uh differentiate between the one that we already had mine I called portfolio Das Corey I could have left it as portfolio but I'm going to change that to the new Json file and now if I just run this we can see that it generated successfully and now if I go back to the browser here if I reload this then we can see that it's now using uh my data from that Json file and the images that I specifi uh specified within that directory and real quick let me make sure that both versions worked yep and we can see here um that it has my name my information things like that so that worked just by changing the data from the Json that I dropped in so if I ever wanted to change this then I can simply update that Json file and regenerate both of these with that python script and that's basically what I was wanting to show you in this video uh showing how we can use Python and Ginger 2 templates like this to generate multiple files from the same data in the last video I released I showed how we can take a static site like the ones that we've created here and put them online for free using GitHub Pages um that way you'll have a URL to your portfolio that you can send directly to potential employers so if you want to learn how we could push a site like this up to GitHub Pages uh then I'll be sure to leave a link to that video in the description section below uh it's one that I just released now one thing that I do want to mention is that a lot of what we saw in this video is a bit opinionated in terms of what works best for me and what I think looks good but uh I openly admit I'm not a front-end developer or a web designer so I definitely encourage you to play around with your own Styles and layouts for your templates if you decide to use this method for your own portfolios I wrote custom CSS for this but you could always use a framework like bootstrap or Tailwind if you're more comfortable with those uh I mainly want this to be a starting point uh to give you some ideas for how you can more easily manage your portfolios and resumés but with that said I think that's going to do it for this video I hope you feel like you got some ideas for how you can use a process like this in your day-to-day workflow even if it's not uh spefic specifically for portfolio data but if anyone has any questions about what will be covered in this video then feel free to ask in the comment section below and I'll do my best to answer those and if you enjoy these tutorials and would like to support them then there are several ways you can do that the easiest way is to Simply like the video and give it a thumbs up also it's a huge help to share these videos with anyone who you think would find them useful and if you have the means you can contribute through patreon or YouTube and there are links to those pages in the description section below be sure to subscribe for future videos and thank you all for watching oh

---
*Источник: https://ekstraktznaniy.ru/video/11714*