Insert or update items listed in an HTML page of a CherryPy web app

  • In this topic, we will see how to add a new item to a list of items or update an existing item in a list that we have in our database, from a web application developed using Python CherryPy framework.
    Data can be stored in any kind of database or may be in a pre-defined list within the application (For CRUD samples utilizing different kinds of databases, you can refer the links on the right side of this page).
    In this sample, we are going to work on a list of items that we are keeping in JSON format in a separate JSON file. We will add a new item to this list and also update an existing item.

  • Python libraries required

    Following python libraries are to be installed to run this sample.

    CherryPy: An object-oriented web application framework to develop python based web application. Install this using the command pip install CherryPy

    Jinja2: A template engine for Python. Jinja2 helps in serving the html to the user. Using this library along with CherryPy helps in faster code development.

  • Listing items

    In order to work on insert and update, we should have a list of items displayed on our web page.
    For this, copy code for three files items.json, listitems.html and list.py from Listing Items in CherryPy Web App and paste in your code folder.
    items.json has the list of items that we are going to modify.

  • HTML Code

    Once the above set of code is copied, we can proceed with adding a new button in the List page to add new items. Also next to each row, we need to add a new link button, Edit to navigate to the Edit page.

    Add a new link button in the listitems.html above the table.

        <a class="btn btn-primary" href="openitemdetails/0">Add New Item</a>
    

    Then modify the HTML table in the listitems.html as below to add the Edit button.

    Copied
        <table class="table">
            <thead>
                <tr>
                <th scope="col">Id</th>
                <th scope="col">Name</th>
                <th scope="col">Age</th>
                <th scope="col">Edit</th>
                </tr>
            </thead>
            <tbody>
                {% for emp in emps %}
                    <tr>
                        <td>{{ emp.id }}</th>
                        <td>{{ emp.name }}</td>
                        <td>{{ emp.age }}</td>
                        <td><a href='openitemdetails/{{ emp.id }}'>Edit</a></td>
                    </tr>
                {% endfor %}
            </tbody>
        </table>
    

    Now add the new html file, additem.html and place the below code.
    This page contains text box controls to enter/update the details. Note that we have provided the name and value properties for each of the text boxes. name property is used to access the control by name and value property is used to do the two way binding of the corresponding controls' data.

    Copied
    <!DOCTYPE html>
    <html lang="en-US" dir="ltr">
    <head>
        <title>Details</title>
        
        <link rel="stylesheet" crossorigin="anonymous"
    	href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" >
        
    	<script crossorigin="anonymous"
    	src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" >
    	</script>
    
    </head>
    
    <body>
        <h2>Details</h2>
    
        <form action="../savedetails" method = "POST">
            <div class="form-group row">
              <label for="id">Id</label>
              <input type="text" class="form-control" name="id" value="{{emp.id}}">
            </div>
            <div class="form-group row">
                <label for="name">Name</label>
                <input type="text" class="form-control" name="name" value="{{emp.name}}">
            </div>
            <div class="form-group row">
                <label for="age">Year</label>
                <input type="text" class="form-control" name="age" value="{{emp.age}}">
            </div>
            <button type="btnAdd" class="btn btn-primary">Submit</button>
            <a href="/" class="btn btn-primary">Cancel</a>
          </form>
    </body>
    
  • Python Code

    Copy the below code and paste it after index() method, to add two more route methods, openitemdetails() and savedetails() in list.py to handle routing to the Details page and saving the data (Double check the pasted contents are properly intended).

    Add button in the list page calls openitemdetails route with ID as 0. So Details page opens in Create mode with empty text boxes.
    Edit link next to each row also calls openitemdetails route, but passes ID number to the Details page. So the details of the selected item is fetched from the JSON file and bind to the corresponding text boxes in the HTML page.

    savedetails route is called on Submit button click. If the entered ID number doesn't exist, new item gets added. Otherwise, existing record is updated.

    Copied
        @cherrypy.expose
        def openitemdetails(self, id=0):
            templenv = Environment(loader=FileSystemLoader(os.getcwd()))
            if int(id) == 0:
                return templenv.get_template('additem.html').render(emp=[])
            else:
                with open(jsnfile) as b:
                    emps = json.load(b)
                emp = [x for x in emps if x['id'] == id][0]
                return templenv.get_template('additem.html').render(emp=emp)
        
        @cherrypy.expose
        def savedetails(self, id=0, name='', age=0):
            idexists = 0
            with open(jsnfile) as b:
                emps = json.load(b)
            if(len([x for x in emps if x['id'] == id]) == 0):
                emps.append({"id": id, "name": name, "age": age})
            else:
                for emp in emps:
                    if(int(emp['id']) == int(id)):
                        emp['name'] = name
                        emp['age'] = age
                        break
            with open(jsnfile, 'w') as bw:
                json.dump(emps, bw)
            raise cherrypy.HTTPRedirect("/")
    
  • Running this sample

    From command prompt, navigate to code folder and execute command py list.py or python list.py
    We will see the below message when execution starts without any issues.

    	[08/Jun/2022:18:11:50] ENGINE Listening for SIGTERM.
    	[08/Jun/2022:18:11:50] ENGINE Bus STARTING
    	CherryPy Checker:
    	The Application mounted at '' has an empty config.
    
    	[08/Jun/2022:18:11:50] ENGINE Started monitor thread 'Autoreloader'.
    	[08/Jun/2022:18:11:50] ENGINE Serving on http://127.0.0.1:8080
    	[08/Jun/2022:18:11:50] ENGINE Bus STARTED
    

    Copy the URL http://127.0.0.1:8080 to your browser and run to add/edit items.

Absolute Code Works - Python Topics