pythonhtmlvariablesflasklibcloud

stop flask duplicating a loaded variable


I'm building a basic cloud infrastructure management site and have a problem with the page that lists virtual machines.

The flask app pulls a list that is generated via various cloud platform's APIs, and is in the below format:

vm_list = {
    'vmid': [],
    'name': [],
    'state': [],
    'platform': []
}

the list is populated by looping through the API output and appending each value like so:

def zip_list():
    ...
    for node in driver.list_nodes():
        vm_list["vmid"].append(node.uuid)
        vm_list["name"].append(node.name)
        vm_list["state"].append(node.state)
        vm_list["platform"].append(driver.name)
    ...
        myVms = zip(vm_list['name'], vm_list['vmid'], vm_list['platform'], vm_list['state'])
        return myVms

I'm loading this via my flask app like this:

@app.route('/vms/')
def vms():
    myVms = {}
    myVms = vm.zip_list()
    return render_template('VMs.html', vm_list=myVms)

The VMs.html page loads this data into a table:

<table class="tableClass">
  <tr>
    <th>Name</th>
    <th>id</th>
    <th>Plaform</th>
    <th>State</th>
  </tr>
  {% for row in vm_list %}
  <tr>
    <td>{{ row[0] }}</td>
    <td>{{ row[1] }}</td>
    <td>{{ row[2] }}</td>
    <td>{{ row[3] }}</td>
  <tr>
  {% endfor %}
</table>

And this works fine, loading the data as expected. However my problem is each time I refresh the page, the data is loaded and appended to the list once again, doubling the table size. Each refresh adds the whole vm_list list to the table once more.

I had thought this may be resolved by "nulling" the myVms variable each time it's called (i.e. myVms = {}) in the flask app script and/or the zip_list function but that doesn't seem to work; the issue still persists.

I also looked into flask-caching to see if clearing flask's cache each reload would fix it but it appears not to.

I'm thinking that I can change something in the html file to force this to only load once per session or something similar, but my front-end skills don't reach out that far.

Does anyone have any idea what I can do in this situation or where I'm going wrong? Any advice is greatly appreciated.


Solution

  • You are close - the variable you actually need to reset each time is not myVms but vm_list, as follows:

    class Node:
        counter = 0
    
        def __init__(self):
            c_str = str(Node.counter)
            self.uuid = "asdf" + c_str
            self.name = "test " + c_str
            self.state = "wow " + c_str + " such state"
            Node.counter += 1
    
    
    class Driver:
        def __init__(self, number_of_nodes):
            self.nodes = []
            for x in range(number_of_nodes):
                self.nodes.append(Node())
            self.name = "the greatest driver"
    
        def list_nodes(self) -> list:
            return self.nodes
    
    
    driver = Driver(10)
    
    
    def zip_list():
        vm_list = {'vmid': [], 'name': [], 'state': [], 'platform': []}
        for node in driver.list_nodes():
            vm_list["vmid"].append(node.uuid)
            vm_list["name"].append(node.name)
            vm_list["state"].append(node.state)
            vm_list["platform"].append(driver.name)
    
        myVms = zip(vm_list['name'], vm_list['vmid'], vm_list['platform'], vm_list['state'])
        return myVms
    
    
    print("First time:")
    
    my_list = zip_list()
    for i in my_list:
        print(i)
    
    print("Second time:")
    
    my_list = zip_list()
    for i in my_list:
        print(i)
    

    If you initialise vm_list outside of the zip_list() function instead, you will see the doubling up that you are experiencing.