Python FastApi. Data not displayed when using templates - python

Just created my first fast api interface. Quite simple. I want to display a list of rows on the page.
python code is:
## ----------------------------------------------------------------------------------
## Collect data
## ----------------------------------------------------------------------------------
idb = sqle.db_engine(tg_db_name, data_path)
idb.connect()
rows = idb.ticker_list()
idb.close_db()
## ----------------------------------------------------------------------------------
## Main
## ----------------------------------------------------------------------------------
templates = Jinja2Templates(directory="templates")
app = FastAPI()
#app.get("/")
def index(request: Request):
# print(dir(request))
# return{"Hello":"DashBoard", "Stocks" : rows}
return templates.TemplateResponse("index.html", {"request": request, "Stocks": rows})
when not commented, the following line displays the rows information information
return{"Hello":"DashBoard", "Stocks" : rows}
rows displayed
when not commented, this one just returns an empty page. Just "Stocks" is displayed at the top.
return templates.TemplateResponse("index.html", {"request": request, "Stocks": rows})
Not displayed
here below the index.html template
<html>
<head>
<tile>Stocks</title>
</head>
<body>
<table>
{% for row in rows %}
{{ rows.id }}
{% endfor %}
</table>
</body>
</html>
also, row type is <class 'list'>
and it is the retreival of an sqllite query.
mySql = ('''SELECT id_ticker, tx_ticker_symbol, tx_ticker_code,
tx_ticker_name, tx_ticker_fullname
FROM Ticker''')
self.cursor.execute(mySql)
rows = self.cursor.fetchall()
return rows
I would expect the following line to display the rows information.
return templates.TemplateResponse("index.html", {"request": request, "Stocks": rows})
Also, I don't understand why rows is return as a list and not a dictionary.

Related

How to load chart in Django Template

I have an Altair chart which I want to render in a Django Template. The chart is converted into a json object in the views. Here is the code
views.py
def home(request):
if request.method=='POST':
year = request.POST['year']
df, cus_dict = generate_df(year)
bar_obj = barGraphAltair(year, df)
bar_obj = json.loads(bar_obj.to_json())
print(bar_obj)
context = {'bar': bar_obj}
return render(request, 'index.html', context=context)
return render(request, 'index.html')
template
<div id='altair-viz'>
{% if bar %}
{{ bar|safe }}
{% endif %}
</div>
This just prints the json in the template. I know I have to use Vega to render the graph but I am not sure how to do that in jinja syntax
A temp solution
One way I got this to work, is by creating a different view and calling that view in the template as follows
views.py
def renderAltair(request):
df, cus_dict = generate_df('2017')
bar_obj = barGraphAltair('2017', df)
bar_obj = json.loads(bar_obj.to_json())
return JsonResponse(bar_obj)
template
<script>
vegaEmbed('#altair-viz', "{% url 'altair' %}")
</script>
This works, but as you can see from the original code, I get the year by submitting a form and passing that to the function for generating the graph. So I need the graph to be created in the home view
You can try this way.
def home(request):
if request.method=='POST':
year = request.POST['year']
context = {'year': year}
return render(request, 'index.html', context=context)
return render(request, 'index.html', {})
Not passing data in home view, will get that using json view.
template
<div id='altair-viz' data-url="{% url 'altair' %}?year={{year}}"></div>
<script>
var data_url = $('#altair-viz').attr('data-url');
vegaEmbed('#altair-viz', data_url)
</script>
and get data function
def renderAltair(request):
year = request.GET.get('year')
df, cus_dict = generate_df(year)
bar_obj = barGraphAltair(year, df)
bar_obj = json.loads(bar_obj.to_json())
return JsonResponse(bar_obj)

Sqlite format output in python

I've got a simple flask web-app set up where the user can add and delete tasks from a database. All the entries in the database are displayed in a template, sorted by the type they're assigned. I can't format the output to be at least somewhat readable, though. How do i do that?
The actual database uses different values and whatnot, so not all of them may make sense right now.
This is the function that gets all the entries from my sqlite database:
def get_tsk_by_type(type):
c.execute("SELECT * FROM tasks WHERE type=:type", {'type': type})
result = c.fetchall()
return result
The database:
c.execute("""CREATE TABLE IF NOT EXISTS tasks (
type text,
description text,
amount integer,
id integer
)""")
And here's how i'm returning all the entries that are then displayed in in a template. There is also a function to delete tasks if you input their id.
#app.route('/', methods = ['GET', 'POST'])
def index():
form = DeleteForm()
curr_homework = str(get_tsk_by_type("homework"))
curr_cleaning = str(get_tsk_by_type("cleaning"))
curr_cooking = str(get_tsk_by_type("cooking"))
if form.validate_on_submit():
try:
conn = sqlite3.connect('tasks.db', check_same_thread=False)
c = conn.cursor()
delete = request.form['delete']
if (delete):
remove_tsk(delete)
return redirect('/')
conn.close()
except:
return "Something went wrong while submitting the form"
return render_template('index.html', curr_homework = curr_homwork, curr_cleaning = curr_cleaning, curr_cooking = curr_cooking, form = form)
The relevant parts of my index.html look like this:
{% block content %}
<div>
<p>
<span>Currently registered homework: {{ curr_homework }}</span><br />
<span>Currently registered cleaning tasks: {{ curr_cleaning }}</span><br />
<span>Currently registered cooking tasks {{ curr_cooking }}</span>
</p>
</div>
{% endblock content %}
However, the output i'm getting looks like this:
Currently registered homework: [('homework', 'math', 1, 'df19c0b1-a2128-431274-2e32-3a2f901b1b26')]
Currently registered cleaning tasks: [('cleaning', 'kitchen', 1, 'df19c0b1-aa18-4874-9e32-3a2f901b1b26')]
Currently registered cooking tasks: [('cooking', 'lunch', 1, '0697c139-0299-4c93-88ac-c07d77377796')]
I've tried for-loops and that kinda thing but it only ever returns the first tuple inside the list that get_tsk_by_type() returns. I also tried panda but i couldn't get that to output the way i want it to, either. How do i prettify it to the point that it's easily readable? Without brackets etc.? I later want to display each individual task separately, preferably in divs.
I recommend using a dict cursor so you can access the result elements by name.
You can do that like this (from: https://stackoverflow.com/a/3300514/42346):
def dict_factory(cursor, row):
d = {}
for idx, col in enumerate(cursor.description):
d[col[0]] = row[idx]
return d
conn.row_factory = dict_factory
Then you will get this kind of result:
result = c.fetchall()
result
# [{'type':'homework','description':'math',
# 'amount':1,'id':'df19c0b1-a2128-431274-2e32-3a2f901b1b26'}]
Then in your template you can do something like:
{% for homework in curr_homework %}
<div>
<h6>{{ homework['type'] }}</h6>
<div>{{ homework['description'] }}</div>
</div>
{% if not loop.last %}
<hr>
{% endif %}
{% endfor %}
You may benefit from a little bit of re-organization of the database-specific code.
You can do this:
from flask import g
def dict_factory(cursor, row):
d = {}
for idx, col in enumerate(cursor.description):
d[col[0]] = row[idx]
return d
def get_db():
if 'db' not in g:
conn = sqlite3.connect('tasks.db', check_same_thread=False)
conn.row_factory = dict_factory
g.db = conn.cursor()
return g.db
And then in your view do this:
db = get_db()
db.execute('your query here')

how to get nearby places using google places with python and flask

i am trying to get nearby places using googleplaces with python and flask
i am getting this error: (UnboundLocalError: local variable 'place_name' referenced before assignment)
here is my code:
#app.route('/Search', methods=['POST', 'GET'])
#login_required
def Search():
if request.method == 'POST':
query_result = google_places.nearby_search(
lat_lng={'lat':31.7917, 'lng' : 7.0926},
radius=500,
types=[types.TYPE_SHOPPING_MALL] or [types.TYPE_STORE])`
if query_result.has_attributions:
print(query_result.html_attributions)
for place in query_result.places:
place.get_details()
place_name = place.name
print(place.name)
place_rating = place.rating
print(place.rating)
place_location = place.get_location
print(place.get_location)
for photo in place.photos:
photo.get(maxheight=500, maxwidth=500)
photo.mimetype
photo.url
photo.filename
photo.data
return render_template('Search.html', place_name, place_rating, place_location)
else:
return render_template('Search.html')```
#Note: i am new to python in general
return render_template('Search.html', place_name, place_rating, place_location)
The above isn't valid syntax. When you pass the details to the template, you need to do it as:
return render_template('Search.html', name = place_name,
rating = place_rating, location = place_location)
The variables name, rating and location will then be accessible in the template as {{name}}, {{rating}} and {{location}}.
However, the way you have the for loops laid out means the first time the return statement is reached, it will stop the loop and return the template with these variables.
Perhaps this is what you want, but you may wish to pass query_result to the template, and implement a Jinja2 for loop in the template to print out the various place details. You would remove the for loops and replace that whole block with:
return render_template('Search.html', all_places = query_result)
Then in the template something like:
{% if all_places %}
{% for place in all_places %}
<p><b>{{place.name}}</b> has a rating of <u>{{place.rating}}</u></p>
{% endfor %}
{% else %}
<p>No places found.</p>
{% endif %}

Unable to Render Django Template using Method

I created a function called getData in effort to cut down 4 nested "if" statement inside my userInfo method. The result was devastating. I'm being humiliated by the fact that the page didn't proceed to my successful.html template. If I move everything inside getData method back to the userInfo function, everything return to normal. Is there a trick to making it work so I can restore my shame?
views.py
def userInfo (request):
# Set maximum to avoid default of 1000 forms.
UserFormSet = formset_factory (UserForm, formset = BaseUserFormSet, extra = 2, max_num = 5)
if request.method == 'POST':
formset = UserFormSet (request.POST)
if formset.is_valid ():
location = request.POST ['site']
data = formset.cleaned_data
getData (request, data, location) # ====> Created a function to cut down nested if statement
else:
formset = UserFormSet ()
...
def getData (request, data, location):
validUser = []
for form in data:
username = form.get ('user_name')
userID = form.get ('user_ID')
if username and userID:
n = register (username, userID, location)
if n.checkDataBase ():
validUser.append (username)
if validUser:
context = {'validUser': validUser}
return render (request, 'userform/success.html', context)
HTML
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>Successfully Added</title>
</head>
<body>
<h1>User Information:</h1>
<ul>
{% for user in validUser %}
<li>{{ user }}</li>
{% endfor %}
</ul>
Add more users
</body>
</html>
Does it work if you change your getData() to:
if validUser:
context = {'validUser': validUser}
return request, 'userform/success.html', context
and your userInfo() to:
if formset.is_valid ():
location = request.POST ['site']
data = formset.cleaned_data
request, template, context = getData (request, data, location) # ====> Created a function to cut down nested if statement
return render (request, template, context)
try
return getData (request, data, location)
(add return statement).

How to use nested Python dictionaries and D3.js?

I have a Python/Flask app that gathers data from third-party APIs and stores them in a JSON-like structure (nested Python dictionaries called 'results').
I'm sending this to my template using:
def format_results():
item_data = {'name':name, 'age':age, 'address':address}
results = {'title':item_title, 'item_data':item_data}
return jsonify(results)
#app.route('/')
def display_results():
data = format_results()
return render_template('index.html', data = data)
I would like to use d3.js in my template to plot the results on a graph.
What's the recommended way for doing so? (disclaimer: this is my first time using D3.js)
Figured out a way to make this work!
def format_results():
item_data = {'name':name, 'age':age, 'address':address}
results = {'title':item_title, 'item_data':item_data}
return results
#app.route('/')
def display_results():
data = format_results()
return render_template('index.html', data = data)
Removed 'jsonify' and disabled escaping for {{data}}
de = {% autoescape false %} {{data}} {% endautoescape %}

Categories

Resources