stop flask duplicating a loaded variable - python

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.

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.

You need to initialise vm_list with an empty dict. And if a key exists, then append to its list, else set the dict[key] with an empty list. This is done by setdefault.
Try this:
def zip_list():
...
vm_list = {}
for node in driver.list_nodes():
vm_list.setdefault('vmid', []).append(node.uuid)
vm_list.setdefault('name', []).append(node.name)
vm_list.setdefault('state', []).append(node.state)
vm_list.setdefault('platform', []).append(node.platform)
...
myVms = zip(vm_list['name'], vm_list['vmid'], vm_list['platform'], vm_list['state'])
return myVms

Related

python new line from array

I am using Jinja template in the frontend and in my backend I am using python using which I have an array which is of type string:
#app.route('/', methods=['POST'])
def upload_image():
match = ''
if 'files[]' not in request.files:
flash('No file part')
#file stuff
discription = ""
for file in files:
if file and allowed_file(file.filename):
#OCR related stuffs
for i in range(0, output_ocr_len):
#preprocessing
for index, row in df.iterrows():
if cord_len > 0:
height = result_img.shape[0]
width = result_img.shape[1]
for elements in range(0, cord_len):
char_length = []
predicted_pattern_category = numpy.append(
predicted_pattern_category, 'Misdirection')
[char_length.append(x)
for x in predicted_pattern_category if x not in char_length]
your_predicted_pattern_category = str(char_length)
char_length = []
predicted_pattern_type = numpy.append(
predicted_pattern_type, 'Visual Interference')
[char_length.append(x) for x in predicted_pattern_type if x not in char_length]
your_predicted_pattern_type = "" + str(char_length)
for i in range(0,len(char_length)):
print("from ML :-",char_length[i])
index_of_key = key.index(char_length[i])
discription = discription + "" + value[index_of_key]
print(discription)
match = str(match) + " "
else:
char_length = []
[char_length.append(x)
for x in predicted_pattern_category if x not in char_length]
your_predicted_pattern_category = str(char_length)
if len(your_predicted_pattern_category) < 3:
your_predicted_pattern_category=''
char_length = []
[char_length.append(x) for x in predicted_pattern_type if x not in char_length]
your_predicted_pattern_type = str(char_length)
if len(your_predicted_pattern_type) < 3:
your_predicted_pattern_type=''
for i in range(0,len(char_length)):
print("from ML :-",char_length[i])
index_of_key = key.index(char_length[i])
discription = discription + '\r\n' + value[index_of_key]
print(discription)
return render_template('uploads/results.html',
msg='Processed successfully!',
match=match,
discription=discription
filenames=output_results
)
else:
return render_template('uploads/results.html',
msg='Processed successfully!',
match=match,
filenames=file_names)
To display the description, I am using Jinja template:
<tr>
<th class="table-info">Description</th>
<td>{{ description }}</td>
</tr>
I want that the description is printed on a new line whose content is present within the "value" variable.
currently the description renders together and not in a new line:
happy: is an emotionis: an extensionmy mood: relies on people
What I want is (every sentence in a new line)
happy: is an emotionis:
an extensionmy mood:
relies on people
From what I can tell, your code comes out on one line because you're repeatedly appending to the same variable. If you really want it all in one variable description, and on separate lines, I think you need a new line char, but I think HTML may ignore them...
For your fundamental problem, tables are designed to have information on separate rows. If you want the descriptions to be on separate lines, I think separate rows is the way to go. I would personally do the for-loop in the template instead of the backend.
{% for value in values %}
<tr>
<th class="table-info">Description</th>
<td>{{ value }}</td>
</tr>
{% endfor %}

Generating odoo report on the basis of active records

I am using following function to fetch records in my report.
def get_records(self):
recsss = self.pool.get('overtime_oms_bcube.overtime_oms_bcube').search(self.cr,self.uid, [], context=self.context)
resss = self.pool.get('overtime_oms_bcube.overtime_oms_bcube').browse(self.cr, self.uid, recsss)
return resss
and calling the records by following way:
<t t-set="i" t-value="1"/>
<tr t-foreach="get_records()" t-as="data">
<td style="display:none">
<t t-esc="i"/>
<t t-set="i" t-value="i+1"/>
</td>
<td t-esc="data['employee_code']"></td>
<td t-esc="data['employee'].name"></td>
<td t-esc="data['employee'].job_id.name"></td>
<td t-esc="data['no_of_days']"></td>
<td t-esc="data['employee'].contract_id.wage"></td>
<td t-esc="data['employee'].contract_id.wage*0.64516129"></td>
</tr>
The problem is that the resulting report is showing all the records saved in the data base. I want it to show only those records which are selected in the tree view. As you see the active/selected records in the image below.
And even in if we are in the single record view and generate a report, it still shows all the record but according to the flow it need to generate a report of that record from where we are generating that report.
please suggest something that helps in such requirement. Thanks in advance.
Step 1: Create Wizard
Example of odoo default product pricelist report wizard
Click on Print button system will call wizard print method
Step: 2: Create Print method in Wizard
def print_report(self, cr, uid, ids, context=None):
"""
To get the date and print the report
#return : return report
"""
if context is None:
context = {}
datas = {'ids': context.get('active_ids', [])}
res = self.read(cr, uid, ids, ['price_list','qty1', 'qty2','qty3','qty4','qty5'], context=context)
res = res and res[0] or {}
res['price_list'] = res['price_list'][0]
datas['form'] = res
return self.pool['report'].get_action(cr, uid, [], 'product.report_pricelist', data=datas, context=context)
In The Context you will get active ids and get_action method will print report
Relace this code:
def get_records(self):
recsss = self.pool.get('overtime_oms_bcube.overtime_oms_bcube').search(self.cr,self.uid, [], context=self.context)
resss = self.pool.get('overtime_oms_bcube.overtime_oms_bcube').browse(self.cr, self.uid, recsss)
return resss
withe the following
def get_records(self):
active_ids = self.context.get('active_ids',False)
recsss = self.pool.get('overtime_oms_bcube.overtime_oms_bcube').search(self.cr,self.uid, [('id','in',active_ids)], context=self.context)
resss = self.pool.get('overtime_oms_bcube.overtime_oms_bcube').browse(self.cr, self.uid, recsss)
return resss
It will generate the active Ids only.
Cheers!
Try to check if active_ids is present in context when calling your method. If it is present, just use the IDs for your browse() call.

Loop in dictionary in HTML

I have a Python script creating a dictionary and passing it to a html page to generate a report.
in Python:
data_query= {}
data_query["service1"] = "value1"
data_query["service2"] = "value2"
return data_query
in HTML:
% for name, count in data_query:
<tr>
<td>${name}</td>
<td>${count}</td>
</tr>
% endfor
it does not work, says that it does not return enough values.
I also tried (pointed out in a comment in the other question, that I deleted by mistake):
% for name, count in dict.iteritems():
It does not give any error, but does not work. Displays nothing.
${len(dict)}
gives the right dictionary length
${len(dict.iteritems())}
does not display anything and seem to have a weird effect on my table format.
Is there a way to iterate correctly a dictionart in HTMl to display both the key and value?
EDIT: How I transfer the dictionary to the html page.
from mako.lookup import TemplateLookup
from mako.runtime import Context
from mako.exceptions import text_error_template
html_lookup = TemplateLookup(directories=[os.path.join(self.dir_name)])
html_template = html_lookup.get_template('/templates/report.html')
html_data = { 'data_queries' : data_queries }
html_ctx = Context(html_file, **html_data)
try:
html_template.render_context(html_ctx)
except:
print text_error_template().render(full=False)
html_file.close()
return
html_file.close()
% for name, count in dict.items:
<tr>
<td>${name}</td>
<td>${count}</td>
</tr>
% endfor
should probably work ... typically you dont call the fn when you pass it to a templating language... alternatively
% for name in dict:
<tr>
<td>${name}</td>
<td>${dict[name]}</td>
</tr>
% endfor
would likely also work
as an aside ... dict is a terrible variable name as it shadows the builtin dict (which might be part of your problem if that is actually your variable name)

How to create a dynamic table

I am creating a table using the following code based on the input provided in XML which is working perfectly fine but I want to convert to code to create a table dynamically meaning if i add more columns,code should automatically adjust..currently I have hardcoded that the table will contain four columns..please suggest on what changes need to be done to the code to achieve this
Input XML:-
<Fixes>
CR FA CL TITLE
409452 WLAN 656885 Age out RSSI values from buffer in Beacon miss scenario
12345,45678 BT 54567,34567 Test
379104 BT 656928 CR379104: BT doesn’t work that Riva neither sends HCI Evt for HID ACL data nor response to HCI_INQUIRY after entering into pseudo sniff subrating mode.
</Fixes>
Python code
crInfo = [ ]
CRlist = [ ]
CRsFixedStart=xmlfile.find('<Fixes>')
CRsFixedEnd=xmlfile.find('</Fixes>')
info=xmlfile[CRsFixedStart+12:CRsFixedEnd].strip()
for i in info.splitlines():
index = i.split(None, 3)
CRlist.append(index)
crInfo= CRlisttable(CRlist)
file.close()
def CRlisttable(CRlist,CRcount):
#For logging
global logString
print "\nBuilding the CRtable\n"
logString += "Building the build combo table\n"
#print "CRlist"
#print CRlist
CRstring = "<table cellspacing=\"1\" cellpadding=\"1\" border=\"1\">\n"
CRstring += "<tr>\n"
CRstring += "<th bgcolor=\"#67B0F9\" scope=\"col\">" + CRlist[0][0] + "</th>\n"
CRstring += "<th bgcolor=\"#67B0F9\" scope=\"col\">" + CRlist[0][1] + "</th>\n"
CRstring += "<th bgcolor=\"#67B0F9\" scope=\"col\">" + CRlist[0][2] + "</th>\n"
CRstring += "<th bgcolor=\"#67B0F9\" scope=\"col\">" + CRlist[0][3] + "</th>\n"
CRstring += "</tr>\n"
TEMPLATE = """
<tr>
<td><a href='http://prism/CR/{CR}'>{CR}</a></td>
<td>{FA}</td>
<td>{CL}</td>
<td>{Title}</td>
</tr>
"""
for item in CRlist[1:]:
CRstring += TEMPLATE.format(
CR=item[0],
FA=item[1],
CL=item[2],
Title=item[3],
)
CRstring += "\n</table>\n"
#print CRstring
return CRstring
Although I have some reservations about providing this since you seem unwilling to even attempt doing so yourself, here's an example showing one way it could be done -- all in the hopes that perhaps at least you'll be inclined to the effort to study and possibly learn a little something from it even though it's being handed to you...
with open('cr_fixes.xml') as file: # get some data to process
xmlfile = file.read()
def CRlistToTable(CRlist):
cols = CRlist[0] # first item is header-row of col names on the first line
CRstrings = ['<table cellspacing="1" cellpadding="1" border="1">']
# table header row
CRstrings.append(' <tr>')
for col in cols:
CRstrings.append(' <th bgcolor="#67B0F9" scope="col">{}</th>'.format(col))
CRstrings.append(' </tr>')
# create a template for each table row
TR_TEMPLATE = [' <tr>']
# 1st col of each row is CR and handled separately since it corresponds to a link
TR_TEMPLATE.append(
' <td>{{{}}}</td>'.format(*[cols[0]]*2))
for col in cols[1:]:
TR_TEMPLATE.append(' <td>{{}}</td>'.format(col))
TR_TEMPLATE.append(' </tr>')
TR_TEMPLATE = '\n'.join(TR_TEMPLATE)
# then apply the template to all the non-header rows of CRlist
for items in CRlist[1:]:
CRstrings.append(TR_TEMPLATE.format(CR=items[0], *items[1:]))
CRstrings.append("</table>")
return '\n'.join(CRstrings) + '\n'
FIXES_START_TAG, FIXES_END_TAG = '<Fixes>, </Fixes>'.replace(',', ' ').split()
CRsFixesStart = xmlfile.find(FIXES_START_TAG) + len(FIXES_START_TAG)
CRsFixesEnd = xmlfile.find(FIXES_END_TAG)
info = xmlfile[CRsFixesStart:CRsFixesEnd].strip().splitlines()
# first line of extracted info is a blank-separated list of column names
num_cols = len(info[0].split())
# split non-blank lines of info into list of columnar data
# assuming last col is the variable-length title, comprising reminder of line
CRlist = [line.split(None, num_cols-1) for line in info if line]
# convert list into html table
crInfo = CRlistToTable(CRlist)
print crInfo
Output:
<table cellspacing="1" cellpadding="1" border="1">
<tr>
<th bgcolor="#67B0F9" scope="col">CR</th>
<th bgcolor="#67B0F9" scope="col">FA</th>
<th bgcolor="#67B0F9" scope="col">CL</th>
<th bgcolor="#67B0F9" scope="col">TITLE</th>
</tr>
<tr>
<td>409452</td>
<td>WLAN</td>
<td>656885</td>
<td>Age out RSSI values from buffer in Beacon miss scenario</td>
</tr>
<tr>
<td>12345,45678</td>
<td>BT</td>
<td>54567,34567</td>
<td>Test</td>
</tr>
<tr>
<td>379104</td>
<td>BT</td>
<td>656928</td>
<td>CR379104: BT doesnt work that Riva neither sends HCI Evt for HID ACL data nor
response to HCI_INQUIRY after entering into pseudo sniff subrating mode.</td>
</tr>
</table>
That doesn't look like an XML file - it looks like a tab delimited CSV document within a pair of tags.
I suggest looking into the csv module for parsing the input file, and then a templating engine like jinja2 for writing the HTML generation.
Essentially - read in the csv, check the length of the headers (gives you number of columns), and then pass that data into a template. Within the template, you'll have a loop over the csv structure to generate the HTML.

Sortable tables in Django

I read some of the other posts about this and some recommendations involved javascript and using other libraries. I did something quick by hand, but I'm new to Django and Python for that matter so I'm curious if this isn't a good way to do it.
HTML
<table>
<tr>
<td>To</td>
<td>Date</td>
<td>Type</td>
</tr>
{% for record in records %}
<tr><td>{{record.to}}</td><td>{{record.date}}</td><td>{{record.type}}</td></tr>
{% endfor %}
</table>
View
headers = {'to':'asc',
'date':'asc',
'type':'asc',}
def table_view(request):
sort = request.GET.get('sort')
if sort is not None:
if headers[sort] == "des":
records = Record.objects.all().order_by(sort).reverse()
headers[sort] = "asc"
else:
records = Record.objects.all().order_by(sort)
headers[sort] = "des"
else:
records = Record.objects.all()
return render_to_response("table.html",{'user':request.user,'profile':request.user.get_profile(),'records':records})
Looks good to me. I'd suggest one minor refactoring in the view code:
headers = {'to':'asc',
'date':'asc',
'type':'asc',}
def table_view(request):
sort = request.GET.get('sort')
records = Record.objects.all()
if sort is not None:
records = records.order_by(sort)
if headers[sort] == "des":
records = records.reverse()
headers[sort] = "asc"
else:
headers[sort] = "des"
return render_to_response(...)
My first port of call for sortable tables is usually sorttable.js ( http://www.kryogenix.org/code/browser/sorttable/ )
or sortable-table ( http://yoast.com/articles/sortable-table/ )

Categories