This question already has answers here:
stop flask duplicating a loaded variable
(2 answers)
Closed 3 years ago.
I'm building a simple data analysis web-app using an API endpoint from an ERP.
I want to display the result of my query in a table, so I iter through the results and my data gets displayed nicely.
However when I refresh my page, my data gets duplicated.
My problem is the same as in this post.
I have tried to fix my code using the solution of the post above but without success.
This is my route for my Flask app
#app.route('/results', methods=["POST", "GET"])
def results():
code = hasCode()
if request.method == "POST":
quote_reference = request.form["quote"]
products = resultsList(code, quote_reference)
try:
return render_template("results.html", products=products)
except BaseException:
return "There was a problem with your request"
else:
return render_template("/")
my products are being initiated in the resultList() function and refers to the function underneath:
def resultsList(code, quote_reference):
"""Creates a list of results that can be passed to the template of the
results.html template
"""
# initiating the variable
my_list = {
'quantity': [],
'description': [],
'price': [],
'img': []
}
# The pandalize function fetches the data from the ERP
query = pandalize(code, quote_reference)
# Grabbing all reasults from the "pandalize function" and appending them to the list
for i, row in query.iterrows():
my_list["quantity"].append(row["quantity"])
my_list["description"].append(row["name"])
my_list["price"].append(row["price"])
my_list["img"].append(row["id"])
# Zipping the list
products = zip(
my_list["quantity"],
my_list["description"],
my_list["price"],
my_list["img"]
)
return products
finally, the loop is in the results.html file:
{% for i in products %}
<tr>
<td class="quantity">{{ i[0] }}</td>
<td class="description">{{ i[1] }}</td>
<td class="price">{{ i[2] }}</td>
<td class="img">{{ i[3] }}</td>
</tr>
{% endfor %}
According to this answer I would need to initialize my list (products) inside my resultsList() function for it to work. However I still experience doubling of data.
I don't really understand what I'm doing wrong. Any ideas ?
After checking the results of all functions and going back upstream, it seemed that the original answer was correct. I need to initialize the list each time.
I noticed that my initial list was being populated by my request (the 'pandalize()' function). This had for effect that each time the pandalize function was called, the list became longer and longer.
It has now been fixed.
Related
I am using django to display a webpage. I want to display details of files from database. These files can be of any number. I am using a form to input a date from HTML file which is accepted by a django view function. This function checks if the request is of type POST and returns the data between the mentioned date. Now when I use pagination to display these pages, pressing the next doesn't show anything as this time the request gets changed to GET. In my django view function, data is fetched in a list. Every file's data is in a list. So, all the data consists lists of lists. How will I be able to display these lists using pagination without sending the requests again. Is it possible to do so?
My data is stored in a database according to dates. I am fetching the data in a given range. This range comes from html page. Here is how I am trying to fetch the details:
<div class="container">
<form method="POST">
{% csrf_token %}
<input type="date" name="start_date">
<input type="date" name="end_date">
<button type="Submit">Get Details</button>
</form>
</div>
This is the code that I use at the backend to serve the webpage.
def data_range(request):
if request.method == 'POST':
form = Form(request.POST)
try:
if form.is_valid():
start_date = form.data.get('start_date')
end_date = form.data.get('end_date')
page_data = get_page_details(start_date, end_date)
else:
current_date = datetime.datetime.now()
start_date = end_date = current_date.strftime("%Y-%m-%d")
page_data = get_page_details(start_date, end_date)
except Exception:
return render(request, 'UserInterface/no_data_fort.html', {'list_item_count': 0})
else:
return render(request, 'UserInterface/no_data_fort.html', {'list_item_count': 0})
if page_data:
# Calculating total files in fortnightly data
list_item_count = len(page_data)
# Adding Paginator or pagination
paginator = Paginator(page_data, 1)
page = request.GET.get('page')
data = paginator.get_page(page)
return render(request, 'UserInterface/fortnightly_range.html', {'page_data_list': data, 'list_item_count': list_item_count})
else:
return render(request, 'UserInterface/no_data_fort.html', {'list_item_count': 0})
page_data that I fetch is a list of lists.
What I want to do:
Get user input from HTML form, store input in variables within Django and perform calculations with variables.
To accomplish that, I use following code:
my_var = requst.POST.get('my_var')
To prevent having 'None' stored in 'my_var' when a Django page is first rendered, I usually use
if my_var == None:
my_var = 1
To keep it simple when using a bunch of variables I came up with following idea:
I store all variable names in a list
I loop through list and create a dictionary with variable names as key and user input as value
For that I wrote this code in python which works great:
list_eCar_properties = [
'car_manufacturer',
'car_model',
'car_consumption',]
dict_sample_eCar = {
'car_manufacturer' : "Supr-Duper",
'car_model' : "Lightning 1000",
'car_consumption' : 15.8,
}
dict_user_eCar = {
}
my_dict = {
'car_manufacturer' : None,
'car_model' : None,
'car_consumption' : None,
}
for item in list_eCar_properties:
if my_dict[item] == None:
dict_user_eCar[item] = dict_sample_eCar[item]
else:
dict_user_eCar[item] = my_dict[item]
print(dict_user_eCar)
Works great - when I run the code, a dictionary (dict_user_eCar) is created where user input (in this case None simulated by using a second dictionary my_dict) is stored. When User leaves input blank - Data from dict_sample_eCar is used.
Now, when I transfer that code to my Django view things don't work not as nice anymore. Code as follows:
def Verbrauchsrechner_eAuto(request):
list_eCar_properties = [
'car_manufacturer',
'car_model',
'car_consumption',
]
dict_model_eCar = {
'car_manufacturer' : "Supr-Duper",
'car_model' : "Lightning 1000",
'car_consumption' : 15.8,
}
dict_user_eCar = {
}
for item in list_eCar_properties:
dict_user_eCar[item] = dict_model_eCar[item]
context = {
'dict_user_eCar' : dict_user_eCar,
'dict_model_eCar' : dict_model_eCar,
'list_eCar_properties' : list_eCar_properties,
}
return render(request, 'eAuto/Verbrauchsrechner_eAuto.html', context = context)
Result: The page gets rendered with only the first dictionary entry. All others are left out. In this cases only car_manufacturer gets rendered to html-page.
Sorry folks - as I was reviewing my post, I realized, that I had a major srew-up at the last part's indentation:
context and return both were part of the for-loop which obviously resulted in a page-rendering after the first loop.
I corrected the code as follows:
for item in list_eCar_properties:
dict_user_eCar[item] = dict_model_eCar[item]
context = {
'dict_user_eCar' : dict_user_eCar,
'dict_model_eCar' : dict_model_eCar,
'list_eCar_properties' : list_eCar_properties,
}
return render(request, 'eAuto/Verbrauchsrechner_eAuto.html', context = context)`
Since I didn't want the time I spend to write this post to be wasted - I simply posted it anyway - even though I found the mistake myself.
Lessons learned for a Newbie in programming:
To many comments in your own code might result in a big confusion
Try to be precise and keep code neat and tidy
Do 1 and 2 before writing long posts in stackoverflow
Maybe someone else will benefit from this.
This question already has answers here:
How can I use Ansible nested variable?
(2 answers)
Closed 4 years ago.
My question looks trivial but I already spend some hours on it.
How to dynamically navigate into a json variable, with jinja2.
ex: I get
ansible_lvm.vgs:
"vgs": {
"vgdata": {
"free_g": "16",
"size_g": "0"
},
"vgswap": {
"free_g": "0",
"size_g": "00"
}
}
In a jinja2 structure I would like to get "free_g" attribut for "vgdata":
None of the code hereafter works:
{% set my_vg_name = 'vg_data' %}
{% set my_vg_size = ansible_lvm.vgs.(my_vg_name).free_g %}
{% set my_vg_size = ansible_lvm.vgs.{{my_vg_name}}.free_g %}
{% set my_vg_size = ansible_lvm.vgs|selectattr(my_vg_name, 'free_g') %}
Thanks for your help,
So, I hope that code snippet at the top is just an example, and not really what you are using, since it's malformed JSON. And I hope you are not actually asking the vgs object for vg_data when the key is vgdata, because that will never end well.
That aside:
You access dict objects in python using vgs[my_vg_name] syntax, or if you aren't sure that vgs contains that key, vgs.get(my_vg_name, {}) to provide an empty dict as the default if vgs does not contain a key whose value is in the my_vg_name variable.
Perhaps it's just a bad question, but if you always want vgdata.free_g then why the dynamic access at all?
i want to generate a list of ip addresses (using range of last 8bits so 120-190 translates to x.x.x.120 - x.x.x.190) in defaults/main.yml in my role, and later use it to create new network interfaces and generate a new config file. I tried this approach:
defaults/main.yml:
ip_list: "{%for address_end in range(50,99)%} 192.168.0.{{address_end}}{%endfor%}"
conf_list: "{%for ip in ip_list%}server {{ip}}:6666 {%endfor%}"
and then to use it in template
template.conf.j2:
{% for conf_line in conf_list %}
{{conf_line}}
{% endfor %}
and all i got in generated config file was:
s
e
r
v
e
r
:
6
6
6
6
s
e
r
v
e
r
1
:
6
so my guess is that i'm not generating a list but just a long string and when I use for loop in template.conf.j2 I iterate over single chars. I tried using answer to this problem but all i got was syntax error. Any ideas for what might help me ?
You should format your vars as JSON lists if you want them to be lists.
1.1.1.1 2.2.2.2 3.3.3.3 is a string.
['1.1.1.1', '2.2.2.2', '3.3.3.3'] will be converted to list.
But there is alternative approach for you:
ip_list: "{{ lookup('sequence', 'start=50 count=12 format=192.168.0.%d', wantlist=True) }}"
conf_list: "{{ ip_list | map('regex_replace','(.*)','server \\1:6666') | list }}"
Kostantin answer was of much help, but i found just realized that generating config entries in my case could be solved in an less complex way. Instead of trying to iterate over list or a string variable variable in jinja template file template.conf.j2 like did with :
{% for conf_line in conf_list %}
{{conf_line}}
{% endfor %}
you could just enter insert new line signs while generating string in defaults/main.yml:
conf_list: "{%for ip in ip_list%}server {{ip}}:6666\n{%endfor%}"
and then just insert that whole string into a template.conf.j2 like this:
{{conf_line}}
nevertheless i have no other idea how to generate list of ip addresses other than the one Konstantin proposed.
I have a bunch of pandas dataframes in a list that I need to convert to html tables. The html code for each individual dataframe looks good, however when I append the html to a list I end up with a bunch of \n characters showing on my webpage. Can anyone tell me how to get rid of them?
python code:
dataframe_html = []
table_dic = {}
for df in dataframes:
frame = df.to_html(classes="table table-hover")
dataframe_html.append(frame) #this is the line where all the \n get added
table_dic.update({'dataframe_html':dataframe_html})
return render(request,'InterfaceApp/FileProcessor_results.html',table_dic)
html code:
<div class="table-responsive">
{{ dataframe_html | safe }}
</div>
Shows up like this:
'
Can anyone help me out with this??
To display 3 separate tables, join the list of HTML strings into a single string:
dataframe_html = u''.join(dataframe_html)
for df in dataframes:
frame = df.to_html(classes="table table-hover")
dataframe_html.append(frame)
dataframe_html = u''.join(dataframe_html)
table_dic = {'dataframe_html':dataframe_html}
return render(request,'InterfaceApp/FileProcessor_results.html',table_dic)
FWIW this late in the game:
I had originally had:
response = render_template('table_display.html', query_results=[df_html], query_name='Quality Item Query')
and was getting an entire row of \n characters. Changed to below and the newlines disappeared.
response = render_template('table_display.html', query_results=df_html, query_name='Quality Item Query')
Even later in the game...
I stumbled upon this thread when having the same problem. Hopefully, the below helps someone.
I assigned the results of df.to_html() to a (nested) list and got the new lines when rendering in my Jinja template. The solution inspired by #AlliDeacon was to index the result again when rendering
Python code:
result[0][0] = df.to_html()
Jinja template:
<div>Table: {{ result[0][0][0] }}</div>
Refer output of the following code for illustration of the difference between a (sub-)list and a list element:
df = pd.DataFrame([['a','b']],
columns=['col_A', 'col_B'])
tmp = []
tmp.append(df.to_html(index=False))
print(tmp)
print(tmp[0])
Result:
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th>col_A</th>
<th>col_B</th>
</tr>
</thead>
<tbody>
<tr>
<td>a</td>
<td>b</td>
</tr>
</tbody>
</table>
Even more than late than late to the game. The issue with the newline characters is that the frame is by default in JSON when passed from your app to Jinja. The \n's are being read literally, but the table gets constructed from what follows inside the JSON string. There are two cases to deal with this, depending on the method of passing your dataframe:
Case 1: Passing a dataframe with render_template:
Pass the frame in your app without the "df.to_html". Within your html use the Jinja2 syntax to obtain a clean frame without any newline characters:
{{ df_html.to_html(classes="your-fancy-table-class") | safe }}
Case 2: Passing with json.dumps to be retrieved in JS
In case you send your frame via a response, e.g. post Ajax request, pass the frame with df.to_html() as you did:
#app.route('/foo', methods=['POST']) #load and return the frame route
def foo():
# df = pd.DataFrame...
return json.dumps({"response": df.to_html}
Then in your JS, load the clean frame without the newline characters in HTML from your response with:
JSON.parse(data).response;
$("#your-table-wrapper").html(response);