Flask
Resume Maker In Flask

Resume Maker In Flask

Here, we present a resume maker in Flask.

This resume maker will ask user for various data such as name, address, phone no, email, education, experience, publications, skills, awards etc. and then generate a resume based on these informations.

The backend of this web application is completed with the help of Python and Flask. While html, javascript and bootstrap has been used for the front end.

The data of the user has been stored in json format.

This web application has been hosted in render.com

https://resume-maker-mgqb.onrender.com

You can also find this files and codes of this web application in github.

https://github.com/gunjanak/resume_maker.git

We will begin this tutorial by creating a virtual environment.

Creating A virtual environment

mkdir resume_maker
cd resume_maker
python3 -m venv venv
source venv/bin/activate

Create Basic Files and Folders

mkdir static templates
mkdir static/js static/css
touch app.py static/css/form.css static/js/form.js
touch templates/{awards,basic,education,experience,index,publications,resume,skills}.html

Tree so far

Create a basic flask application

#install flask
pip3 install Flask

app.py

from flask import Flask
from flask import Flask,render_template,request

app = Flask(__name__)

@app.route("/")
def index():
    return "<h1>This is resume maker </h1>"

if __name__ == '__main__':
    app.run(port=5000,debug=True)
#save above application and run
flask run

Output

The index page

Here we create the index page where we ask user to enter his/her basic information. I have tried to render it using bootstrap. After submitting this form, we are redirected to ‘/education/’.

index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
  
</head>

    </head>
    <body>
        <div class="container py-5 px-10 bg-info">
            
               

                <div class="row g-2">
                  <div class="col-sm-12" style="border : 2px solid black;" >
                      <h1 class="text-center">The Resume Application in Flask</h1>
                  </div>
  
              </div>




              <div class="row g-2">
                <div class="col-sm-12">
                  <p></p>
                  <form class="p-3 form-horizontal" action="/education/" id="mainform" method="post" name="mainform">
                
                    <div class="form-group">
                        <label class="control-label col-sm-2" for="text">Name:</label>
                        <div class="col-sm-10">          
                          <input type="text" class="form-control" id="name" placeholder="Name" name="Full Name">
                        </div>
                    </div>
    
                    <div class="form-group">
                        <label class="control-label col-sm-2" for="address">Address:</label>
                        <div class="col-sm-10">
                          <input type="text" class="form-control" id="address" placeholder="Enter address" name="Address">
                        </div>
                      </div>
    
    
                    <div class="form-group">
                    <label class="control-label col-sm-2" for="email">Email:</label>
                    <div class="col-sm-10">
                      <input type="email" class="form-control" id="email" placeholder="Enter email" name="email">
                    </div>
                  </div>
    
    
                  <div class="form-group">
                    <label class="control-label col-sm-2" for="number">Phone:</label>
                    <div class="col-sm-10">          
                      <input type="number" class="form-control" id="phoneNumber" placeholder="Phone Number" name="Phone Number">
                    </div>
                </div>
    
                <div class="form-group">
                  <label class="control-label col-sm-2" for="address">About:</label>
                  <div class="col-sm-10">
                    <textarea class="form-control" rows="5" cols="100" name="description">
                     
                    </textarea>
                    
                    
                  </div>
                </div>
                
    
                 
                  <div class="form-group">        
                    <div class="col-sm-offset-2 col-sm-10">
                      <button type="submit" class="btn btn-default">Submit</button>
                    </div>
                  </div>
                </form>

                </div>
              </div>
            
          </div>
    </body>
</html>

app.py

from flask import Flask
from flask import Flask,render_template,request

app = Flask(__name__)

@app.route("/")
def index():
    return render_template('index.html')

if __name__ == '__main__':
    app.run(port=5000,debug=True)

Output

Creating basic.html

We will create dynamic forms for user to enter remaining data. Following pages will have similar pattern and look, so we need to create a base format which will be used as template for rest of the pages.

Here, we have created two rows. First row containing the header, this will remain constant through all the pages. The second row contains two columns. Left column will contain buttons. These buttons will be responsible for generating form in right columns.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
        <script src="/static/js/form.js"></script>

    </head>
    <body>
        <div class="container py-5 px-10 bg-info">
            <div class="row">
                <div class="col-sm-12" style="border : 2px solid black;" >
                    <h1 class="text-center">The Resume Application in Flask</h1>
                </div>

            </div>
            <div class="row">
                <div class="col-sm-4 text-center">
                    
                    {% block body %}
                    {% endblock %}

                        <button class="btn btn-primary btn-block" onclick="resetElements()">Reset</button>
                </div>
                <div class="col-sm-8  text-center m-5"  >

                    {% block content%}
                    {% endblock %}
                    
                    <p></p><input class="btn btn-primary" type="submit" value="Submit">
                    </form>

                </div>
            </div>
        </div>
    </body>
</html>

Creating education.html

The education.html will inherit few features from basic.html. We will add four functions regarding education.

After filling form generated in ‘education.html’ user will be redirected to ‘/experience/’

{% extends "basic.html" %}
{% block body %}
<h2>Education</h2>
<h4>Click to Choose</h4>
<button class="btn btn-primary btn-block"  onclick="phdFunction()">PhD</button>
<br>
<br>
<button class="btn btn-primary btn-block"  onclick="PostGradFunction()">PostGrad</button>
<br>
<br>
<button class="btn btn-primary btn-block"  onclick="UnderGradFunction()">UnderGrad</button>
<br>
<br>
<button class="btn btn-primary btn-block"  onclick="HighSchoolFunction()">HighSchool</button>
<br>
<br>

{% endblock %}

{% block content %}
<h2>Enter Information about your Education</h2>
<hr  style="height:2px;border-width:0;color:gray;background-color:gray">
<form action="/experience/" id="mainform" method="post" name="mainform">
<span id="myForm">

</span>
{% endblock %}

form.js

This javascript file contains several function.

The first function ‘removeElement’ is used to remove a form section when ‘x’ is clicked.

The following functions are regarding several level of education. Where part of form is created dynamically when created button is clicked. Here element is created and several attributes are added to this element.

/*
---------------------------------------------

Function to Remove Form Elements Dynamically
---------------------------------------------

*/
function removeElement(parentDiv, childDiv){
    if (childDiv == parentDiv){
        alert("The parent div cannot be removed.");
    }

    else if (document.getElementById(childDiv)){
        var child = document.getElementById(childDiv);
        var parent = document.getElementById(parentDiv);
        parent.removeChild(child);
    }
    else{
        alert("Child div has already been removed or does not exist.");
        return false;
    }
}

/*
----------------------------------------------------------------------------

Functions that will be called upon, when user click on the PhD text field.

----------------------------------------------------------------------------
*/
function phdFunction(){
    var r = document.createElement('span');
    var phd = document.createElement('h1');
    phd.innerHTML = "PHD";
    r.appendChild(phd);
    var y = document.createElement("INPUT");
    y.setAttribute("type", "text");
    y.setAttribute("class","form-control")
    y.setAttribute("placeholder", "University");

    
    //increment();

    y.setAttribute("Name", "phd_uni");
    r.appendChild(y);
    
    
    
    
    var start_date = document.createElement("INPUT");
    start_date.setAttribute("class","form-control")
    start_date.setAttribute("type","date");
    start_date.setAttribute("placeholder","start_date")
    start_date.setAttribute("Name","start_date")
    r.appendChild(start_date)
    
    var end_date = document.createElement("INPUT");
    end_date.setAttribute("class","form-control");
    end_date.setAttribute("type","date");
    end_date.setAttribute("placeholder","end_date")
    end_date.setAttribute("Name","end_date")
    r.appendChild(end_date)
    
    var thesis = document.createElement("INPUT");
    thesis.setAttribute("class","form-control")
    thesis.setAttribute("type","text");
    thesis.setAttribute("placeholder","Your Thesis Title")
    thesis.setAttribute("Name","phd_thesis")
    r.appendChild(thesis)
    
    var thesis_url = document.createElement("INPUT");
    thesis_url.setAttribute("class","form-control");
    thesis_url.setAttribute("type","href");
    thesis_url.setAttribute("placeholder","Your Thesis Url here")
    thesis_url.setAttribute("Name","phd_thesis_url")
    r.appendChild(thesis_url);



    r.setAttribute("id", "phd");
    document.getElementById("myForm").appendChild(r);
    
    
    


    document.getElementById("myForm").appendChild(r);
        //console.log(r);
        let child_of_r = r.children;
        console.log(child_of_r[0]);

        for (let i = 1; i < child_of_r.length; i++) {
            child_of_r[i].setAttribute("class","form-control");

            
          }
          

    var cross = document.createElement("IMG");
    cross.setAttribute('width','10%');
    cross.setAttribute('height','10%');
    cross.setAttribute("src", "https://www.freeiconspng.com/uploads/x-delete-button-png-15.png");
    cross.setAttribute("onclick", "removeElement('myForm','phd')");
    r.appendChild(cross);

    var horizontal_line = document.createElement('hr');
    horizontal_line.setAttribute("height","20px");
    horizontal_line.setAttribute("color","gray");
    r.addpendChild(horizontal_line);


   


    }
   
    /*
    
    ----------------------------------------------------------------------------
    
    Functions that will be called upon, when user click on the PostGrad text field.
    
    ----------------------------------------------------------------------------
    */
    function PostGradFunction(){
        var r = document.createElement('span');
        var postgrad = document.createElement('h1');
        postgrad.innerHTML = "Post Graduation";
        r.appendChild(postgrad);
        var y = document.createElement("INPUT");
        y.setAttribute("type", "text");
        y.setAttribute("placeholder", "University");
        //increment();
        y.setAttribute("Name", "postgrad_uni");
        r.appendChild(y);
     
        
    
        var postgrad_degree = document.createElement("INPUT");
        postgrad_degree.setAttribute("type","text");
        postgrad_degree.setAttribute("placeholder","Name of Degree");
        postgrad_degree.setAttribute("Name","postgrad_degree");
        r.appendChild(postgrad_degree)
        
        
        var start_date = document.createElement("INPUT");
        start_date.setAttribute("type","date");
        start_date.setAttribute("placeholder","start_date")
        start_date.setAttribute("Name","postgrad_start_date")
        r.appendChild(start_date)
        
        var end_date = document.createElement("INPUT");
        end_date.setAttribute("type","date");
        end_date.setAttribute("placeholder","end_date")
        end_date.setAttribute("Name","postgrad_end_date")
        r.appendChild(end_date)
    
    
        var thesis = document.createElement("INPUT");
        thesis.setAttribute("type","text");
        thesis.setAttribute("placeholder","Your Thesis Title")
        thesis.setAttribute("Name","postgrad_thesis")
        r.appendChild(thesis)
    
        var thesis_url = document.createElement("INPUT");
        thesis_url.setAttribute("type","href");
        thesis_url.setAttribute("placeholder","Your Thesis Url here")
        thesis_url.setAttribute("Name","postgrad_thesis_url")
        r.appendChild(thesis_url)
        
        r.setAttribute("id", "postgrad");
        
        



        document.getElementById("myForm").appendChild(r);
        let child_of_r = r.children;

        for (let i = 1; i < child_of_r.length; i++) {

            child_of_r[i].setAttribute("class","form-control");

            
          }

        var cross = document.createElement("IMG");
        cross.setAttribute('width','10%');
        cross.setAttribute('height','10%');
        cross.setAttribute("src", "https://www.freeiconspng.com/uploads/x-delete-button-png-15.png");
        cross.setAttribute("onclick", "removeElement('myForm','postgrad')");
        r.appendChild(cross);



        
        }
    
    
    
    /*
    
    ----------------------------------------------------------------------------
    
    Functions that will be called upon, when user click on the UnderGrad text field.
    
    ----------------------------------------------------------------------------
    */
    function UnderGradFunction(){
        var r = document.createElement('span');
        var undergrad = document.createElement('h1');
        undergrad.innerHTML = "Under Graduation";
        r.appendChild(undergrad);
        var y = document.createElement("INPUT");
        y.setAttribute("type", "text");
        y.setAttribute("placeholder", "University");
        y.setAttribute("Name", "undergrad_uni");
        r.appendChild(y);
        var degree = document.createElement("INPUT");
        degree.setAttribute("type","text");
        degree.setAttribute("placeholder","Name of Degree");
        degree.setAttribute("Name","undergrad_degree");
        r.appendChild(degree)
    
    
    
        var start_date = document.createElement("INPUT");
        start_date.setAttribute("type","date");
        start_date.setAttribute("placeholder","start_date")
        start_date.setAttribute("Name","undergrad_start_date")
        r.appendChild(start_date)
        
        var end_date = document.createElement("INPUT");
        end_date.setAttribute("type","date");
        end_date.setAttribute("placeholder","end_date")
        end_date.setAttribute("Name","undergrad_end_date")
        r.appendChild(end_date)
    
    
        var thesis = document.createElement("INPUT");
        thesis.setAttribute("type","text");
        thesis.setAttribute("placeholder","Your Final Year Project Title")
        thesis.setAttribute("Name","undergrad_project")
        r.appendChild(thesis)
    
        var thesis_url = document.createElement("INPUT");
        thesis_url.setAttribute("type","href");
        thesis_url.setAttribute("placeholder","Your Final Year Project Url here")
        thesis_url.setAttribute("Name","undergrad_project_url")
        r.appendChild(thesis_url)

        r.setAttribute("id", "undergrad");
        
        document.getElementById("myForm").appendChild(r);

        document.getElementById("myForm").appendChild(r);
        document.getElementById("myForm").appendChild(r);
        
        let child_of_r = r.children;

        for (let i = 1; i < child_of_r.length; i++) {

            child_of_r[i].setAttribute("class","form-control");

            
          }

        var cross = document.createElement("IMG");
        cross.setAttribute('width','10%');
        cross.setAttribute('height','10%');
        cross.setAttribute("src", "https://www.freeiconspng.com/uploads/x-delete-button-png-15.png");
        cross.setAttribute("onclick", "removeElement('myForm','undergrad')");
        r.appendChild(cross);


        }
    
    
    
    /*
    
    ----------------------------------------------------------------------------
    
    Functions that will be called upon, when user click on the HighSchool text field.
    
    ----------------------------------------------------------------------------
    */
    function HighSchoolFunction(){
        var r = document.createElement('span');
        var HighSchool = document.createElement('h1');
        HighSchool.innerHTML = "High School";
        r.appendChild(HighSchool);
        var y = document.createElement("INPUT");
        y.setAttribute("type", "text");
        y.setAttribute("placeholder", "School");
        y.setAttribute("Name", "School");
        r.appendChild(y);
        
        
        var start_date = document.createElement("INPUT");
        start_date.setAttribute("type","date");
        start_date.setAttribute("placeholder","start_date")
        start_date.setAttribute("Name","highschool_start_date")
        r.appendChild(start_date)
        
        var end_date = document.createElement("INPUT");
        end_date.setAttribute("type","date");
        end_date.setAttribute("placeholder","end_date")
        end_date.setAttribute("Name","highschool_end_date")
        r.appendChild(end_date)
    
        
        r.setAttribute("id", "highschool");
        
        document.getElementById("myForm").appendChild(r);


    
          let child_of_r = r.children;
  
          for (let i = 1; i < child_of_r.length; i++) {
  
              child_of_r[i].setAttribute("class","form-control");
  
              
            }
  
          var cross = document.createElement("IMG");
          cross.setAttribute('width','10%');
          cross.setAttribute('height','10%');
          cross.setAttribute("src", "https://www.freeiconspng.com/uploads/x-delete-button-png-15.png");
          cross.setAttribute("onclick", "removeElement('myForm','highschool')");
          r.appendChild(cross);
  

        }

app.py

Here, we need to import os and jsonlines.

While os comes with python package, we need to import jsonlines.

pip3 install jsonlines
import os
import jsonlines
@app.route("/education/",methods=['POST'])
def education():
     
    #this receives data from index.html and writes it in json file.s
    if request.method == 'POST':
        
        if os.path.exists("resume.json"):
            os.remove("resume.json")
            name_of_file = "resume.json"
        else:
            name_of_file = "resume.json"
        
        with jsonlines.open(name_of_file, "x") as writer:
            print("Writing Data from index.html") 
            writer.write(request.form)
        print(type(request.form))

    return render_template("education.html")


/*
-----------------------------------------------------------------------------

Functions that will be called upon, when user click on the Reset Button.

------------------------------------------------------------------------------
*/
function resetElements(){
    document.getElementById('myForm').innerHTML = '';
    }
    

As this education page will land to experience page, we have added ‘/experience/’.

app.py at this stage

from flask import Flask
from flask import Flask,render_template,request
import os
import jsonlines

app = Flask(__name__)

@app.route("/")
def index():
    return render_template('index.html')


@app.route("/education/",methods=['POST'])
def education():
     
    #this receives data from index.html and writes it in json file.s
    if request.method == 'POST':
        
        if os.path.exists("resume.json"):
            os.remove("resume.json")
            name_of_file = "resume.json"
        else:
            name_of_file = "resume.json"
        
        with jsonlines.open(name_of_file, "x") as writer:
            print("Writing Data from index.html") 
            writer.write(request.form)
        print(type(request.form))

    return render_template("education.html")

@app.route("/experience/",methods=['POST'])
def experience():
    return "<p>Experience</p>"

if __name__ == '__main__':
    app.run(port=5000,debug=True)

Output

experience.html

This page also extends “basic.html”. The function added here are: CurrentJobFunction and ExperienceFunction.

{% extends "basic.html" %}
{% block body %}
<h2>Experience</h2>
<h4>Click to Choose</h4><button class="btn btn-primary btn-block" onclick="CurrentJobFunction()">Current Job</button>
<button class="btn btn-primary btn-block" onclick="ExperienceFunction()">Experience</button>
{% endblock %}


{% block content %}
<h2>Enter Information about your Job and Experience</h2>
<hr  style="height:2px;border-width:0;color:gray;background-color:gray">
<form action="/publications/" id="mainform" method="post" name="mainform">
<span id="myForm">

</span>
{% endblock %}

Adding functions in form.js

var i = 0; /* Set Global Variable i */
function increment(){
i += 1; /* Function for automatic increment of field's "Name" attribute. */
}

/*
----------------------------------------------------------------------------

Functions that will be called upon, when user click on the Experience text field.

----------------------------------------------------------------------------
*/
function ExperienceFunction(){
    var r = document.createElement('span');
    var currentjob = document.createElement('h1');
    currentjob.innerHTML = "Experience";
    r.appendChild(currentjob);


    var y = document.createElement("INPUT");
    y.setAttribute("type", "text");
    y.setAttribute("placeholder", "Company");
    //var g = document.createElement("IMG");
    //g.setAttribute("src", "delete.png");
    increment();
    y.setAttribute("Name", "company_"+i);
    r.appendChild(y);
    //g.setAttribute("onclick", "removeElement('myForm','id_" + i + "')");
    //r.appendChild(g);

    var position = document.createElement("INPUT");
    position.setAttribute("type","text");
    position.setAttribute("placeholder","Position")
    position.setAttribute("Name","position_"+i)
    r.appendChild(position)
    
    
    var start_date = document.createElement("INPUT");
    start_date.setAttribute("type","date");
    start_date.setAttribute("placeholder","start_date")
    start_date.setAttribute("Name","job_start_date_"+i)
    r.appendChild(start_date)


    var end_date = document.createElement("INPUT");
    end_date.setAttribute("type","date");
    end_date.setAttribute("placeholder","end_date")
    end_date.setAttribute("Name","job_end_date_"+i)
    r.appendChild(end_date)
    
    var responsibility = document.createElement("INPUT");
    responsibility.setAttribute("type","text");
    responsibility.setAttribute("placeholder","Responsibility")
    responsibility.setAttribute("Name","responsibility_"+i)
    r.appendChild(responsibility)
    
    
    r.setAttribute("id", "job"+i);
    
    document.getElementById("myForm").appendChild(r);



    let child_of_r = r.children;
  
    for (let i = 1; i < child_of_r.length; i++) {

        child_of_r[i].setAttribute("class","form-control");

        
    }

    var cross = document.createElement("IMG");
    cross.setAttribute('width','10%');
    cross.setAttribute('height','10%');
    cross.setAttribute("src", "https://www.freeiconspng.com/uploads/x-delete-button-png-15.png");
    //cross.setAttribute("onclick", "removeElement('myForm','job'+i)");
    cross.setAttribute("onclick", "removeElement('myForm','job" + i + "')");
    r.appendChild(cross);
  
    }


/*
----------------------------------------------------------------------------

Functions that will be called upon, when user click on the Current Job text field.

----------------------------------------------------------------------------
*/
function CurrentJobFunction(){
    var r = document.createElement('span');
    var currentjob = document.createElement('h1');
    currentjob.innerHTML = "Current Job";
    r.appendChild(currentjob);


    var y = document.createElement("INPUT");
    y.setAttribute("type", "text");
    y.setAttribute("placeholder", "Company");
    //var g = document.createElement("IMG");
    //g.setAttribute("src", "delete.png");
    //increment();
    y.setAttribute("Name", "current_company");
    r.appendChild(y);
    //g.setAttribute("onclick", "removeElement('myForm','id_" + i + "')");
    //r.appendChild(g);

    var position = document.createElement("INPUT");
    position.setAttribute("type","text");
    position.setAttribute("placeholder","Current Position")
    position.setAttribute("Name","current_position")
    r.appendChild(position)
    
    
    
    var start_date = document.createElement("INPUT");
    start_date.setAttribute("type","date");
    start_date.setAttribute("placeholder","start_date")
    start_date.setAttribute("Name","current_job_start_date")
    r.appendChild(start_date)

    var responsibility = document.createElement("INPUT");
    responsibility.setAttribute("type","text");
    responsibility.setAttribute("placeholder","Responsibility")
    responsibility.setAttribute("Name","current_responsibility")
    r.appendChild(responsibility)

    r.setAttribute("id", "currentjob");
    
    document.getElementById("myForm").appendChild(r);



    let child_of_r = r.children;
  
    for (let i = 1; i < child_of_r.length; i++) {

        child_of_r[i].setAttribute("class","form-control");

        
    }

    var cross = document.createElement("IMG");
    cross.setAttribute('width','10%');
    cross.setAttribute('height','10%');
    cross.setAttribute("src", "https://www.freeiconspng.com/uploads/x-delete-button-png-15.png");
    cross.setAttribute("onclick", "removeElement('myForm','currentjob')");
    r.appendChild(cross);

    }

app.py in current stage after adding ‘/experience/’

from flask import Flask
from flask import Flask,render_template,request
import os
import jsonlines

app = Flask(__name__)

@app.route("/")
def index():
    return render_template('index.html')


@app.route("/education/",methods=['POST'])
def education():
     
    #this receives data from index.html and writes it in json file.s
    if request.method == 'POST':
        
        if os.path.exists("resume.json"):
            os.remove("resume.json")
            name_of_file = "resume.json"
        else:
            name_of_file = "resume.json"
        
        with jsonlines.open(name_of_file, "x") as writer:
            print("Writing Data from index.html") 
            writer.write(request.form)
        print(type(request.form))

    return render_template("education.html")



@app.route("/experience/",methods=['POST'])
def experience():
     #data = json.load(f)
    #this receives data from education.html and writes it in json file.s
    if request.method == 'POST':
       
        name_of_file = "resume.json"
        # filename.jsonl is the name of the file
        with jsonlines.open(name_of_file, "a") as writer:
            print("Writing Data from education.html") 
            writer.write(request.form)


    return render_template("experience.html")

@app.route("/publications/",methods=['POST'])
def publications():
    return "<p>Publications</p>"


if __name__ == '__main__':
    app.run(port=5000,debug=True)

Output

Publications.html

{% extends "basic.html" %}
{% block body %}
<h2>Publications</h2>
<h4>Click to Choose</h4><button class="btn btn-primary btn-block" onclick="publicationFunction()">Publications</button>

{% endblock %}

{% block content %}
<h2>Enter Information about your Publications</h2>
<hr  style="height:2px;border-width:0;color:gray;background-color:gray">
<form action="/skills/" id="mainform" method="post" name="mainform">
<span id="myForm">

</span>
{% endblock %}

Adding related functions to form.js

/*
----------------------------------------------------------------------------

Functions that will be called upon, when user click on the Publications text field.

----------------------------------------------------------------------------
*/
function publicationFunction(){
    var r = document.createElement('span');
    var publication = document.createElement('p');
    publication.innerHTML = "Publicationss";
    r.appendChild(publication);


    var y = document.createElement("INPUT");
    y.setAttribute("type", "text");
    y.setAttribute("placeholder", "Paper Title");
    //var g = document.createElement("IMG");
    //g.setAttribute("src", "delete.png");
    increment();
    y.setAttribute("Name", "paper_"+i);
    r.appendChild(y);
    //g.setAttribute("onclick", "removeElement('myForm','id_" + i + "')");
    //r.appendChild(g);
    
    
    var organization = document.createElement("INPUT");
    organization.setAttribute("type","text");
    organization.setAttribute("placeholder","Name of Journal/Conference")
    organization.setAttribute("Name","journal_org_"+i)
    r.appendChild(organization)


    var date = document.createElement("INPUT");
    date.setAttribute("type","date");
    date.setAttribute("placeholder","Journal Date")
    date.setAttribute("Name","journal_date_"+i)
    r.appendChild(date)

    
    
    r.setAttribute("id", "journal_"+i);
    
    document.getElementById("myForm").appendChild(r);



    let child_of_r = r.children;
  
    for (let i = 1; i < child_of_r.length; i++) {

        child_of_r[i].setAttribute("class","form-control");

        
    }

    var cross = document.createElement("IMG");
    cross.setAttribute('width','10%');
    cross.setAttribute('height','10%');
    cross.setAttribute("src", "https://www.freeiconspng.com/uploads/x-delete-button-png-15.png");
    cross.setAttribute("onclick", "removeElement('myForm','journal_" + i + "')");
    r.appendChild(cross);



    }

Skills.html

{% extends "base.html" %}
{% block body %}
<h2>Skills</h2>
<h4>Click to Choose</h4>

<button class="btn btn-primary btn-block" onclick="technicalSkillsFunction()">Skills</button>
<button class="btn btn-primary btn-block" onclick="softSkillsFunction()">Soft Skills</button>


{% endblock %}


{% block content %}
<h2>Enter Information about your Skills</h2>
<hr  style="height:2px;border-width:0;color:gray;background-color:gray">
<form action="/awards/" id="mainform" method="post" name="mainform">
<span id="myForm">

</span>
{% endblock %}

Adding related functions to form.js


/*
----------------------------------------------------------------------------

Functions that will be called upon, when user click on the Soft Skills text field.

----------------------------------------------------------------------------
*/
function softSkillsFunction(){
    var r = document.createElement('span');
    var soft_skills = document.createElement('h1');
    soft_skills.innerHTML = "Soft Skills";
    r.appendChild(soft_skills);


    var y = document.createElement("INPUT");
    y.setAttribute("type", "text");
    y.setAttribute("placeholder", "Skill");
    //var g = document.createElement("IMG");
    //g.setAttribute("src", "delete.png");
    increment();
    y.setAttribute("Name", "soft_skill_"+i);
    r.appendChild(y);
    //g.setAttribute("onclick", "removeElement('myForm','id_" + i + "')");
    //r.appendChild(g);
    
    r.setAttribute("id", "soft_skill_"+i);
    
    document.getElementById("myForm").appendChild(r);



    let child_of_r = r.children;
  
    for (let i = 1; i < child_of_r.length; i++) {

        child_of_r[i].setAttribute("class","form-control");

        
    }

    var cross = document.createElement("IMG");
    cross.setAttribute('width','10%');
    cross.setAttribute('height','10%');
    cross.setAttribute("src", "https://www.freeiconspng.com/uploads/x-delete-button-png-15.png");
    cross.setAttribute("onclick", "removeElement('myForm','soft_skill_" + i + "')");
    r.appendChild(cross);



    }






/*
----------------------------------------------------------------------------

Functions that will be called upon, when user click on the Skills text field.

----------------------------------------------------------------------------
*/
function technicalSkillsFunction(){
    var r = document.createElement('span');
    var skills = document.createElement('h1');
    skills.innerHTML = "Major Skills";
    r.appendChild(skills);

    var y = document.createElement("INPUT");
    y.setAttribute("type", "text");
    y.setAttribute("placeholder", "Skill");
    //var g = document.createElement("IMG");
    //g.setAttribute("src", "delete.png");
    increment();
    y.setAttribute("Name", "skill_"+i);
    r.appendChild(y);
    //g.setAttribute("onclick", "removeElement('myForm','id_" + i + "')");
    //r.appendChild(g);
    
    var rating = document.createElement("INPUT");
    rating.setAttribute("type","number");
    rating.setAttribute("min","0");
    rating.setAttribute("max","5");
    rating.setAttribute("placeholder","Rating 0-5")
    rating.setAttribute("Name","rating_"+i)
    r.appendChild(rating)

    
    r.setAttribute("id", "skill_"+i);
    
    document.getElementById("myForm").appendChild(r);

    let child_of_r = r.children;
  
    for (let i = 1; i < child_of_r.length; i++) {

        child_of_r[i].setAttribute("class","form-control");

        
    }

    var cross = document.createElement("IMG");
    cross.setAttribute('width','10%');
    cross.setAttribute('height','10%');
    cross.setAttribute("src", "https://www.freeiconspng.com/uploads/x-delete-button-png-15.png");
    cross.setAttribute("onclick", "removeElement('myForm','skill_" + i + "')");
    r.appendChild(cross);

    }

Awards.html

{% extends "basic.html" %}
{% block body %}
<h2>Awards</h2>
<h4>Click to Choose</h4>
<button class="btn btn-primary btn-block" onclick="awardsFunction()">Award</button>

{% endblock %}

{% block content %}
<h2>Enter Information about your Awards</h2>
<hr  style="height:2px;border-width:0;color:gray;background-color:gray">
<form action="/resume/" id="mainform" method="post" name="mainform">
<span id="myForm">

</span>
{% endblock %}

Adding functions to form.js

/*
----------------------------------------------------------------------------

Functions that will be called upon, when user click on the Awards text field.

----------------------------------------------------------------------------
*/
function awardsFunction(){
    var r = document.createElement('span');
    var award = document.createElement('h1');
    award.innerHTML = "Awards";
    r.appendChild(award);


    var y = document.createElement("INPUT");
    y.setAttribute("type", "text");
    y.setAttribute("placeholder", "Name of Award");
    //var g = document.createElement("IMG");
    //g.setAttribute("src", "delete.png");
    increment();
    y.setAttribute("Name", "award_"+i);
    r.appendChild(y);
    //g.setAttribute("onclick", "removeElement('myForm','id_" + i + "')");
    //r.appendChild(g);
    
    
    
    var organization = document.createElement("INPUT");
    organization.setAttribute("type","text");
    organization.setAttribute("placeholder","Name of Organization")
    organization.setAttribute("Name","award_org_"+i)
    r.appendChild(organization)


    var date = document.createElement("INPUT");
    date.setAttribute("type","date");
    date.setAttribute("placeholder","Award Date")
    date.setAttribute("Name","award_date_"+i)
    r.appendChild(date)

    
    
    r.setAttribute("id", "award_"+i);
    
    document.getElementById("myForm").appendChild(r);

    let child_of_r = r.children;
  
    for (let i = 1; i < child_of_r.length; i++) {

        child_of_r[i].setAttribute("class","form-control");

        
    }

    var cross = document.createElement("IMG");
    cross.setAttribute('width','10%');
    cross.setAttribute('height','10%');
    cross.setAttribute("src", "https://www.freeiconspng.com/uploads/x-delete-button-png-15.png");
    cross.setAttribute("onclick", "removeElement('myForm','award_" + i + "')");
    r.appendChild(cross);

    }

‘resume’

Finally the from ‘awards.html’ is sent to ‘/resume/’. Here all data is sent to ‘process_data’ to make the data suitable for ‘resume.html’ using ‘jinja’.

def process_data(data):
    profile = {}
    profile['name'] = data[0]['Full Name']
    profile['address'] = data[0]['Address']
    profile['email'] = data[0]['email']
    profile['number'] = data[0]['Phone Number']
    profile['about'] = data[0]['description']


    if(len(data[2]) >0 ):
        profile['current_company'] = data[2]['current_company']
        profile['current_position'] = data[2]['current_position']
        profile['current_job_start_date'] = data[2]['current_job_start_date']
        profile['current_responsibility'] = data[2]['current_responsibility']

    #Education
    if(len(data[1]) > 0):
        profile['education'] = data[1]

    #Previous Experience
    if(len(data[2]) > 0):
        companies_list = list(data[2])
        companies_list = companies_list[4:]
        no_of_pre_company = int(len(companies_list)/5)
        company_list= []
        position_list = []
        job_start_date = []
        job_end_date = []
        prev_responsibility = []
        for i in range(no_of_pre_company):
            company_list.append(data[2]['company_'+str(i+1)])
            position_list.append(data[2]['position_'+str(i+1)])
            job_start_date.append(data[2]['job_start_date_'+str(i+1)])
            job_end_date.append(data[2]['job_end_date_'+str(i+1)])
            prev_responsibility.append(data[2]['responsibility_'+str(i+1)])

        profile['previous_companies'] = company_list
        profile['previous_positions'] = position_list
        profile['previous_start_dates'] = job_start_date
        profile['previous_end_dates'] = job_end_date
        profile['previous_responsibilities'] = prev_responsibility


    #Publications
    paper = []
    journal = []
    published_date = []
    for i in range(int(len(data[3])/3)):
        paper.append(data[3]['paper_'+str(i+1)])
        journal.append(data[3]['journal_org_'+str(i+1)])
        published_date.append(data[3]['journal_date_'+str(i+1)])

    profile['publications'] = paper
    profile['journals'] = journal
    profile['paper_published_date'] = published_date

    if(len(data[5]) > 0):
        #Awards
        awards = []
        awards_org = []
        awards_date = []
        for i in range(int(len(data[5])/3)):
            awards.append(data[5]['award_'+str(i+1)])
            awards_org.append(data[5]['award_org_'+str(i+1)])
            awards_date.append(data[5]['award_date_'+str(i+1)])

        profile['awards'] = awards
        profile['awards_org'] = awards_org
        profile['awards_date'] = awards_date

        



    #skills
    count = 0
    for keys in data[4]:
        print(keys[:5])
        if(keys[:5] == 'skill'):
            count += 1
    
    
    
    skills = []
    rating = []
    count_2 = 0
    for keys in data[4]:
        if(count_2 > (2*count-1)):
            break

        if(count_2%2 == 0):
            skills.append(data[4][keys])
        else:
            rating.append(data[4][keys])
        count_2 += 1
    
    count_3 = 0
    soft_skills = []
    for keys in data[4]:
        if(count_3 > count_2):
            soft_skills.append(data[4][keys])
        count_3 += 1

    profile['primary_skills'] = skills
    profile['rating'] = rating
    profile['soft_skills'] = soft_skills


    return profile


#Following functions are the part of app.py
@app.route("/resume/",methods=['POST'])
def resume():
    #data = json.load(f)
    if request.method == 'POST':
        # Print the form data to the console
        for key, value in request.form.items():
            print(f'{key}: {value}')

    name_of_file = "resume.json"
    
    with jsonlines.open(name_of_file, "a") as writer:
        print("Writing Data from language.html") 
        writer.write(request.form)

    with jsonlines.open(name_of_file, 'r') as jsonl_f:
        data = [obj for obj in jsonl_f]

    data = process_data(data)


    return render_template("resume.html",data=data)

resume.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>

	<title>{{ data['name'] }} | {{data['current_position']}} | {{ data['email'] }}</title>
	<meta http-equiv="content-type" content="text/html; charset=utf-8" />

	<meta name="keywords" content="" />
	<meta name="description" content="" />

	<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.7.0/build/reset-fonts-grids/reset-fonts-grids.css" media="all" /> 
	<link rel="stylesheet" type="text/css" href="resume.css" media="all" />
    <link rel="stylesheet" type="text/css" href="{{url_for('static',filename='main.css')}}">
    <link rel="stylesheet" href="/static/css/form.css"/>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
     <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
	 
</head>
<body>
  


	

<div id="doc2" class="yui-t7">
	
	<div id="inner">
        <div id="hd">
			<div class="yui-gc">
				<div class="yui-u first">
					<h1>{{ data['name'] }}</h1>
					<h2>{{data['current_position']}}</h2>
				</div>

				<div class="yui-u">
					<div class="contact-info">
						<!-- <h3> <a id="pdf" href="#">Download PDF</a> </h3> -->
						<h3><a href="mailto:{{ data['email'] }}">{{ data['email'] }}</a></h3>
						<h3>{{ data['number'] }}</h3>
						<button onclick="window.print()">Print It</button>
					</div><!--// .contact-info -->
				</div>
			</div><!--// .yui-gc -->
		</div><!--// hd -->
	
        <div id="bd">
			<div id="yui-main">
				<div class="yui-b">

					<div class="yui-gf">
						<div class="yui-u first">
							<h2>Profile</h2>
						</div>
						<div class="yui-u">
							<p class="enlarge">
								{{data['about']}}
							</p>
						</div>
					</div><!--// .yui-gf -->




                    <div class="yui-gf">
						<div class="yui-u first">
							<h2>Skills</h2>
						</div>

                       
                        {% for i in range(data['primary_skills']|length) %}
                    
						<div class="yui-u">

								<div class="talent">
									<h2>{{ data['primary_skills'][i] }}  
										
									</h2>
									<p>	Rating: {% for i in range(data['rating'][i]|int) %}
										{{'*'}}
                                        
										{% endfor %}
									</p>
									
								</div>
						</div>
                        {% endfor %}
                        

					</div><!--// .yui-gf -->

                    <div class="yui-gf">
						<div class="yui-u first">
							<h2>Soft Skills</h2>
						</div>
						<div class="yui-u">
							{% for items in data['soft_skills'] %}
							<ul class="talent">
								<li>{{ items }}</li>
								
							</ul>
							{% endfor %}
						</div>
					</div><!--// .yui-gf-->

                    <div class="yui-gf">
	
						<div class="yui-u first">
							<h2>Experience</h2>
						</div><!--// .yui-u -->


                        
						<div class="yui-u">
                            {% if data['current_company']%}
							<div class="job">
								<h2>{{ data['current_company'] }}</h2>
								<h3>{{ data['current_position']}}</h3>
								<h4>{{ data['current_job_start_date'][:4]}} - Present</h4>
								<p>{{ data['current_responsibility'] }}</p>
							</div>
                            {% endif %}

                            {% for i in range(data['previous_companies']|length) %}
                            

							<div class="job">
								<h2>{{ data['previous_companies'][i] }}</h2>
								<h3>{{ data['previous_positions'][i] }}</h3>
								<h4>{{ data['previous_start_dates'][i][:4] }} -{{ data['previous_end_dates'][i][:4] }}</h4>
								<p>{{ data['previous_responsibilities'][i] }}</p>
							</div>

							{% endfor %}
                            

						</div><!--// .yui-u -->
					</div><!--// .yui-gf -->



                    {% if data['education'] %}
                    <div class="yui-gf">
						<div class="yui-u first">
							<h2>Education</h2>
						</div>

                       {% if data['education']['phd_uni']%}
                        <div class="yui-u">
                            <div class="job">
                               
                                <h2>{{ data['education']['phd_uni'] }}</h2>
                                <h3> Doctor of Philosophy </h3>
                                <h4> {{ data['education']['start_date'][:4] }}- {{ data['education']['end_date'][:4] }} </h4>
                                {% if data['education']['phd_thesis'] %}
                                
                                <p><strong>Thesis Title: </strong><a href="{{ data['education']['phd_thesis_url'] }}">{{ data['education']['phd_thesis'] }}</a></p>
                                
                                {% endif %}

                            </div>
                           
							
							<div class="horizontalgap" style="width:10px"></div>
						</div>
                        {% endif %}


                        {% if data['education']['postgrad_uni']%}
                        <div class="yui-u">
                            <div class="job">
                                <h2>{{ data['education']['postgrad_uni'] }}</h2>
                                <h3>{{ data['education']['postgrad_degree'] }}</h3>
                                <h4> {{ data['education']['postgrad_start_date'][:4] }}- {{ data['education']['postgrad_end_date'][:4] }} </h4>
                                {% if data['education']['postgrad_thesis'] %}
                                
                                <p><strong>Thesis Title: </strong><a href="{{ data['education']['postgrad_thesis_url'] }}">{{ data['education']['postgrad_thesis'] }}</a></p>
                                
                                {% endif %}

                            </div>
							
							<div class="horizontalgap" style="width:10px"></div>
						</div>
                        {% endif %}


                        {% if data['education']['undergrad_uni']%}
                        <div class="yui-u">
                            <div class="job">
                                <h2>{{ data['education']['undergrad_uni'] }}</h2>
                                <h3>{{ data['education']['undergrad_degree'] }}</h3>
                                <h4> {{ data['education']['undergrad_start_date'][:4] }}- {{ data['education']['undergrad_end_date'][:4] }} </h4>
                                {% if data['education']['undergrad_project'] %}
                                
                                <p><strong>Project Title: </strong><a href="{{ data['education']['undergrad_project_url'] }}">{{ data['education']['undergrad_project'] }}</a></p>
                                
                                {% endif %}

                            </div>
							
							<div class="horizontalgap" style="width:10px"></div>
						</div>
                        {% endif %}

                        
                        {% if data['education']['School']%}
                        <div class="yui-u">
                            <div class="job">
                                <h2>{{ data['education']['School'] }}</h2>
                               
                                <h4> {{ data['education']['highschool_start_date'][:4] }}- {{ data['education']['highschool_end_date'][:4] }} </h4>
                               
                            </div>
							
						</div>
                        {% endif %}

					</div><!--// .yui-gf -->
                    {% endif %}
					
					

					<div class="yui-gf">
						<div class="yui-u first">
							<h2>Publications</h2>
						</div>
					  
						{% for i in range(data['publications']|length) %}
						<div class="yui-u">
							
							<div class="job">
								<h2>{{ data['journals'][i] }}</h2>
								<h3> {{ data['publications'][i]}} </h3>
								<h4> {{ data['paper_published_date'][i]}}</h4>
							</div>
						</div>
						{% endfor %}
					
					
					</div><!--// .yui-gf -->


                 
					<div class="yui-gf last">
						<div class="yui-u first">
							<h2>Awards</h2>
						</div>
					  
						{% for i in range(data['awards']|length) %}
						<div class="yui-u">
							
							<div class="job">
								<h2>{{ data['awards'][i] }}</h2>
								<h3> {{ data['awards_org'][i]}} </h3>
								<h4> {{ data['awards_date'][i]}}</h4>
							</div>
						</div>
						{% endfor %}
					
					
					</div><!--// .yui-gf -->
                    



					



					


				</div><!--// .yui-b -->
			</div><!--// yui-main -->
		</div><!--// bd -->

        <div id="ft">
			<p>{{ data['name'] }} &mdash; <a href="mailto:{{ data['email'] }}">{{ data['email'] }}</a> &mdash; {{ data['number'] }}</p>
		</div><!--// footer --
		

		
	</div><!-- // inner -->


</div><!--// doc -->

       
</body>
</html>

form.css

/*
---------------------------------------------------------------------------------
	STRIPPED DOWN RESUME TEMPLATE
    html resume

    v0.9: 5/28/09

    design and code by: thingsthatarebrown.com 
                        (matt brown)
---------------------------------------------------------------------------------
*/


.msg { padding: 10px; background: #222; position: relative; }
.msg h1 { color: #fff;  }
.msg a { margin-left: 20px; background: #408814; color: white; padding: 4px 8px; text-decoration: none; }
.msg a:hover { background: #266400; }

/* //-- yui-grids style overrides -- */
body { font-family: Georgia; color: #444; }
#inner { padding: 10px 80px; margin: 80px auto; background: #f5f5f5; border: solid #666; border-width: 8px 0 2px 0; }
.yui-gf { margin-bottom: 2em; padding-bottom: 2em; border-bottom: 1px solid #ccc; }

/* //-- header, body, footer -- */
#hd { margin: 2.5em 0 3em 0; padding-bottom: 1.5em; border-bottom: 1px solid #ccc }
#hd h2 { text-transform: uppercase; letter-spacing: 2px; }
#bd, #ft { margin-bottom: 2em; }

/* //-- footer -- */
#ft { padding: 1em 0 5em 0; font-size: 92%; border-top: 1px solid #ccc; text-align: center; }
#ft p { margin-bottom: 0; text-align: center;   }

/* //-- core typography and style -- */
#hd h1 { font-size: 48px; text-transform: uppercase; letter-spacing: 3px; }
h2 { font-size: 152% }
h3, h4 { font-size: 122%; }
h1, h2, h3, h4 { color: #333; }
p { font-size: 100%; line-height: 18px; padding-right: 3em; }
a { color: #990003 }
a:hover { text-decoration: none; }
strong { font-weight: bold; }
li { line-height: 24px; border-bottom: 1px solid #ccc; }
p.enlarge { font-size: 144%; padding-right: 6.5em; line-height: 24px; }
p.enlarge span { color: #000 }
.contact-info { margin-top: 7px; }
.first h2 { font-style: italic; }
.last { border-bottom: 0 }


/* //-- section styles -- */

a#pdf { display: block; float: left; background: #666; color: white; padding: 6px 50px 6px 12px; margin-bottom: 6px; text-decoration: none;  }
a#pdf:hover { background: #222; }

.job { position: relative; margin-bottom: 1em; padding-bottom: 1em; border-bottom: 1px solid #ccc; }
.job h4 { position: absolute; top: 0.35em; right: 0 }
.job p { margin: 0.75em 0 3em 0; }

.last { border: none; }
.skills-list {  }
.skills-list ul { margin: 0; }
.skills-list li { margin: 3px 0; padding: 3px 0; }
.skills-list li span { font-size: 152%; display: block; margin-bottom: -2px; padding: 0 }
.talent { width: 32%; float: left }
.talent h2 { margin-bottom: 6px; }

#srt-ttab { margin-bottom: 100px; text-align: center;  }
#srt-ttab img.last { margin-top: 20px }

/* --// override to force 1/8th width grids -- */
.yui-gf .yui-u{width:80.2%;}
.yui-gf div.first{width:12.3%;}


/* -- Horizontal tab--*/
div.horizontalgap {
    float: left;
    overflow: hidden;
    height: 10px;
    width: 0px;
  }

Entering Data

Let us enter the data and see how our resume builder works.

Final Output