Is it possible to send two dataframes to my html (flask)? - python

So my html page receives a pandas dataframe.
return render_template('example.html', tables=[data_frame.to_html(classes='data')], titles=dataframe.columns.values)
and my html page displays it:
{% for table in tables %}
{{titles[loop.index]}}
{{ table|safe }}
{% endfor %}
What I want to do is display two separate dataframes in my html page. How can I do this?
For example:
If I have dataframes df1 and df2,
in the html page I want to display them after some text.
show df1
<h2> some text </h2>
show df2

Since render_template accepts dictionaries, you can pass a Dict object named context or whatever to the "render_template" function with "table" and "title" keys.
And then in your Jinja you can access these keys by context.table and context.title.
Example:
def my_function(request):
...
get your dataframe
...
context = {"tables":[data_frame.to_html(classes='data')],
"titles" : dataframe.columns.values,
}
return render_template('template.html', context=context)

This can be done easily in render_template
Your code can be changed like this:
return render_template('example.html',tables= [data_frame1.to_html(classes='data'),data_frame2.to_html(classes='data')],
titles=['na','FirstTable','SecondTable'])
As you can see , you can add more than one dataframe in tables.
Now in Jinja, you can simply loop through each table(dataframe) and display
{% for table in tables %}
{{ titles[loop.index] }}
{{ table|safe }}
{% endfor %}
Refer the below image for your reference:

Related

Iterating through a python dictionary in flask jinja

I have a dictionary which has all the country codes and the corresponding country names, a sample of it looks like this:
{'AF': 'Afghanistan'}
{'AL': 'Albania'}
{'DZ': 'Algeria'}
{'AD': 'Andorra'}
{'AO': 'Angola'}
When i followed this stack overflow question: How to iterate through a list of dictionaries in Jinja template? to try and iterate through the countries I had an issue as it's not adding any elements.
This is my code:
{% extends "base.html" %} {% block title %}Test{% endblock %}
{% block content %}
<div class="container pt-5">
<h1 align="center">TEST PAGE</h1>
</div>
{% for dict_item in countries %}
{% for key,value in dict_item.items %}
<h1>Key: {{ key }}</h1>
<h2>Value: {{ value }}</h2>
{% endfor %}
{% endfor %}
{% endblock %}
It's not adding any headings and when i tried dict_items.items() (with brackets after items), I got an error of: jinja2.exceptions.UndefinedError: 'str object' has no attribute 'items'
I'm not too sure what's going wrong. Any help would be much appreciated.
(Just incase it's useful, this is my views.py:)
#views.route("/test", methods=["GET"])
#login_required
def test():
countries = Country.query.all()
for country in countries:
countriess = {}
countriess[country.country_code] = country.country_name
print(countriess)
return render_template("TEST.html", user=current_user, countries=countriess)
Try changing views.py to:
#views.route("/test", methods=["GET"])
#login_required
def test():
countries = Country.query.all()
countriess = []
for country in countries:
countriess.append({country.country_code: country.country_name})
return render_template("TEST.html", user=current_user, countries=countriess)
This code will create a list of dictionaries countries, there is not need to change the templating code.
in views.py, you set countries=countriess for template rendering. countriess is re-initialised in the for loop in the test function (countriess = {}), so the countriess passed along to the template is actually a {country_code: country_name} pair for the last country from the countries list.
Going back to the actual error though: when you iterate over countries dictionary within the template ({% for dict_item in countries %}), you actually iterate over keys of countries, which, as I said before, is countriess from the views.py, so basically you just retrieve the country_code of the last country from countries. So the dict_item is actually a string (country code), hence you get the error for {% for key,value in dict_item.items %}, thinking that it is actually a dictionary and not a string.
TL;DR I think that you meant to do countries=countries rather than countries=countriess in views.py. Then the rest of the code would make sense. (I assume the for loop with countriess was just for debugging?)

WTF Bootstrap Quick Form how to render HTML

Hi there I have to use one unique HTML page to display a few fields that will be populated with some data retrieved from a csv file.
I want to use the WTF quick form to pass all the fields together to the HTML page, since I won't know the field names, because they can be retrieved from different csv files(they will be equivalent to the column header of the csv).
The only problem is that I want them to be displayed in two columns (div), so half fields in one colums, half in the other, while quick form will show them in a single vertical list.
How can I sort this out in the easiest way? any attribute to add to the quick form for the layout?
I have tried the following using wtf.form_field, but in this way I must know the name of each field, and I will have to create one HTML page for each CSV file, while I want to have 1 HTML page with quick form, but I can't have the fields displayed in two columns that way.
<div class="row">
<div class="col-md-6">
{{ wtf.form_field(form.COD_SPORTELLO) }}
{{ wtf.form_field(form.QU_CAP) }}
{{ wtf.form_field(form.QU_CAP_INTER) }}
{{ wtf.form_field(form.CAUSALE) }}
{{ wtf.form_field(form.ONERI_RATE_VAL) }}
{{ wtf.form_field(form.FLAG_ANTIRIC) }}
{{ wtf.form_field(form.FLAG_VIG) }}
</div>
<div class="col-md-6">
{{ wtf.form_field(form.COD_RAPPORTO) }}
{{ wtf.form_field(form.QU_CAP_VALUTA) }}
{{ wtf.form_field(form.DATA_SCADENZA) }}
{{ wtf.form_field(form.ONERI_RATE) }}
{{ wtf.form_field(form.QU_INTER_VALUTA) }}
{{ wtf.form_field(form.FLAG_AR) }}
</div>
</div>
I think it's a bit tricky because even if I pass some parameter to the quick form like horizontal_columns for instance ( Must be a 3-tuple of column-type, left-column-size, right-column-size), it will create a second column, but it will display the fields only one column still, so somehow I have to tell him that I want half of the fields on one column and half on the other column (div).
I can't use form_field and list each fileld name cause I won't know the field names.
The fields can be assigned a class directly from the template. If you know what bootstrap classes you need then you call it with the field with a keyword argument class
As explained in this answer
Add a css class to a field in wtform

Flask redirect on select onchange

I'm a beginner to flask and I'm making a small web scraper app. What I've done so far has created a dropdown with a list of elements. Now I want to be able to render another page when the user selects a value from the list and I want to pass that value to the next page as well.
{% extends "base.html" %}
{% block content %}
<select id = "foo" onchange="">
{% for item in Citydata %}
<option value = {{ item.link }}> {{ item.name }} </option>
{% endfor %}
</select>
{% endblock %}
This makes the list and adds in all the links and values. I know that what should happen is that when an option is selected a new route is selected/used and a new template file is loaded. But I don't know how to do it.
If you are trying to do a form submission, follow colidyre's suggestion.
It seems to me, however, that you're looking to add a variable in your path, so you will need to use Flask's Variable Rules
It is unclear what item.link is, however if you have formatted that to be associated with an item's id such as /item/1, you could create an <a> tag like so:
{% for item in Citydata %}
{{ item.name }}
{% endfor %}
That would handle populating the href properly on the front-end, next you will need to set up the proper route on the server to handle the path:
#app.route('/item/<int:item_id>')
def item_route(item_id):
# do some stuff
NOTE: you don't have to create <a> tags, but it is a bit more straight forward than <option>. To stick with <option> you would just need to add some JavaScript client-side to call the back-end service based on the selected <option>'s value attribute instead.

display list value in template page using django

I need to display the value of list in template page using django. I have a variable like
data = [('dic1',),('dic2',)]
I pass the value to the template this way:
return render(request,'success.html',{'details':data})
Then in the template I need to show the value. I have used the for loop in the template like:
{% for a in data %}
{{a}}
{% endfor %}
But it displays as
('dic1',)
('dic2',)
when I need to display only the value like below
dic1
dic2
Canyone help me to find out which mistake I did ?
Thanks for your response. I jus to use like below
{% for a in data %}
{{ a.0 }}
{% endfor %}
Now it's working correctly.

Return items from RSS feed in Django Templatetags

Django noob here.
I'm trying to add RSS feed items into a django template using templatetags (with classytags).
Here's my code:
from django import template
from classytags.core import Tag
import feedparser
register = template.Library()
class ExampleTag(Tag):
name = 'exampletag'
def render_tag(self, context):
raw_feed = "example.com/feed.rss"
feed = feedparser.parse(raw_feed)
entrylist = {}
for entry in feed.entries:
entrylist[entry.title]
return entrylist
register.tag(ExampleTag)
Then, in the template I can call the ExampleTag with:
{% load my_tag %}
{% exampletag %}
This results in a KeyError at / u'The First Entry In The Feed'
If I change my code to append to a list, the template renders without error and the entire structured list is output in a single string.
This is what I'd like to do:
{% load my_tag %}
{% for item in exampletag %}
<p> {{ item }} </p>
{% endfor %}
However this just fails silently (obviously I'm not passing an interable object to the template)
Any ideas? Is this even a good way to go about doing this?
Thanks in advance.
This code looks highly suspect:
for entry in feed.entries:
entrylist[entry.title]
Shouldn't it be something like this?
for entry in feed.entries:
entrylist[entry.title] = entry # or some value
As it is right now you are trying to index into an empty dictionary and are thus getting a KeyError exception.
But I'm still not sure what you are trying to do. Here are 2 ideas that come to mind that may get you started.
Idea one: it sort of looks like you should write an inclusion tag.
Something like (untested):
#register.inclusion_tag('feed_entries.html'):
def feed_entries():
feed = feedparser.parse('example.rss')
return {'items': feed}
And in feed_entries.html
{% for item in items %}
<p> {{ item }} </p>
{% endfor %}
Then, in some random template where you want the list of items displayed:
{% load feed_tags %}
...
<p>Here are the latest entries:</p>
{% feed_entries %}
...
This is assuming feed contains a list of items you want to render somehow. Thus, whenever you use {% feed_entries %} in a template, your snippet of Python is called, it takes the returned dictionary and renders the feed_entries.html template, and the resulting HTML is placed wherever you wrote {% feed_entries %}.
Idea two: If you really want your tag to return a list of items, you could use an assignment tag:
#register.assignment_tag
def feed_entries():
return feedparser.parse('example.rss')
Then in your template you have to "catch" the result of this tag (the list of items):
{% feed_entries as items %}
{% for item in items %}
<p>{{ item }}</p>
{% endfor %}
But that means you'll have to duplicate the "as" and for-loop stuff in every template. The inclusion tag may save you typing and maintenance if you use it in many templates. But if you wanted to render the list differently in each template it would be more flexible. Say you want it in a list of <p> tags in one, but in a <ul> in another.

Categories