I have a Mongo database and I'd like to make a script that performs a query and passes the results to an html file.
This rendered html file will be used as the html body of an email I will send to my colleagues.
However the template is not rendered, here is what I've got
My html looks something like this:
<table>
{ %for q in query %}
<tr>
<td>{{ q['containers'] }} </td>
<td>{{ q['cases'] }} </td>
<td>{{ q['gross_weight'] }} </td>
<td>{{ q['volume'] }} </td>
</tr>
{ %endfor% }
</table>
While my script looks like this:
from pymongo import MongoClient, ASCENDING
from jinja2 import Template
def main():
client = MongoClient()
collection = client.supplyChain['commonRegimes']
parameters = {
'delivery_to_warehouse':None,
'regime':{'$in':['10', '91']}
}
query_result = collection.find(parameters).sort('eta_warehouse', ASCENDING)
templatefile = open('D:/myScripts/ccreport/reports/templates/nextArrivals.html').read()
template = Template(templatefile)
message = template.render(query = query_result)
if __name__ == '__main__':
main()
I get the error:
jinja2.exceptions.UndefinedError: 'q' is undefined
I would appreciate any help.
Ok I realized it was a syntax error in the for statement, It should be:
{% for q in query %}
{% endfor %}}
Related
I want to print one table row based on the user input. I am getting the user input (id) via HTML and Python, here:
html file:
<tbody class="table-group-divider">
{% for course in user.courses %}
<tr>
<!-- here an ID gets rendered from the table, and user clicks on it -->
<td>{{ course.course_name }}</td>
<td class="align-middle">
{% for student in course.students %}
<span>{{ student.student_name }}</span><br>
{% endfor %}
</td>
<td>{{ course.course_day }} {{ course.course_time }}</td>
<td>{{ course.course_language }}</td>
</tr>
{% endfor %}
</tbody>
app.py:
#app.route('/course_detail/<id>', methods=["GET", "POST"])
#login_required
def course_detail(id):
return render_template("course_detail.html", user=current_user, id=id)
My logic is to loop through the table, and if id provided by user matches id (primary key) in table, I found what I want to display, and then display it. However, my attempt does not print anything:
<!-- setting the ID from url/html, basically what user clicked -->
{% set id = id %}
{% for course in user.courses %}
{% if course.id == id %}
<p>im working</p>
{% endif %}
{% endfor %}
I get the id from user, but I can't seem to compare it with course.id so I could display the whole row. Is there a problem with my if statement?
Edit: If I hardcode the if statement to be for example {% if course.id == 2 %} (or any other valid course.id from the table), the information gets printed with no issues.
While I'm not sure why the original proposition doesn't work, I managed to reach my goal via querying my database in app.py, not my html file.
#app.route('/course_detail/<id>', methods=["GET", "POST"])
#login_required
def course_detail(id):
# query the id in db
db_id = Course.query.filter_by(id=id).first()
# save all info into variables
db_course_name = db_id.course_name
db_course_language = db_id.course_language
db_course_day = db_id.course_day
db_course_time = db_id.course_time
db_hourly_rate = db_id.hourly_rate
# send the variables and print them in html
return render_template("course_detail.html", user=current_user, pageid=db_id, db_course_name=db_course_name, db_course_language=db_course_language, db_course_day=db_course_day, db_course_time=db_course_time, db_hourly_rate=db_hourly_rate)
Then I simply printed the variables using double curly braces. Not sure if this is the best design, but it certainly feels better than my previous attempt.
I want to display the content of the database from .db file on web framework using flask module. However, only the row title is able to be displayed on the web framework. The content of the database from the .db file couldn't load out on the web framework. Anyone can help me with this? Thanks.
This is my code:
from flask import Flask, render_template
import sqlite3
app = Flask(__name__)
def connect_db(db):
con = sqlite3.connect(db)
return con.cursor()
#app.route('/')
def index():
db ='mcu_aurix_git.db'
cur = connect_db(db)
cur.execute("SELECT * FROM mcu_aurix")
data = cur.fetchall()
return render_template('flask.html', rows=data)
if __name__ == "__main__":
app.run(debug=True)
flask.html:
<table class="table table-hover">
<thead>
<tr>
<th>project</th>
<th>branch</th>
<th>id</th>
<th>number</th>
<th>subject</th>
<th>owner_name</th>
<th>owner_email</th>
<th>owner_username</th>
<th>url</th>
<th>commitMessage</th>
<th>createdOn</th>
<th>lastUpdated</th>
<th>open</th>
<th>status</th>
<th>current_date</th>
</tr>
</thead>
<tbody>
{% for row in rows %}
<tr>
<td>{{row.project_name}}</td>
<td>{{row.branch_id}}</td>
<td>{{row.id_id}}</td>
<td>{{row.num_number}}</td>
<td>{{row.subject_name}}</td>
<td>{{row.owner_name}}</td>
<td>{{row.owner_email}}</td>
<td>{{row.owner_username}}</td>
<td>{{row.url_name}}</td>
<td>{{row.commitMessage_name}}</td>
<td>{{row.num_createdOn}}</td>
<td>{{row.num_lastUpdated}}</td>
<td>{{row.num_open}}</td>
<td>{{row.status_name}}</td>
<td>{{row.current_date}}</td>
</tr>
{% endfor %}
</tbody>
</table>
Is there anything missing in my code? Hopefully anyone can help me on this. Thanks in advance!
You are not passing rows variable to the html page.
return render_template('flask.html', data=data)
You are only passing data variable.
If you want to use rows inside your html page, you need to use
return render_template('flask.html', rows=data)
Also one more thing,
{{row.project_name}}
You cannot get the value of project_name like this, you need to use index value (col. no. starting from 0). Like,
{{row[0]}}
Instead of manually creating <td> for each col value, you can just use the below tbody code.
<tbody>
{% for row in rows %}
<tr>
{% for col in row %}
<td> {{ col }} </td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
Hope it helps!
In my basic web application, when click to "calculate" button there can be two options.
First, there is only one result so I directly show them to the users.
Secondly, there can be more than one result so I need to use table to show my results.
For the first option, I can show my result like below:
<p>Result {{result}}</p>
But I cannot figure out if my "result" parameter is array and how can I show all values of array in the table in my html file.
Any help is appreciated.
You can iterate over your iterable in your template:
Python script:
users = [{"name": "123", "hash": "qwe"},]
#app.route('/index/')
def index_page():
return render_template('index.html', users=users)
Template:
<table>
<thead>
<tr>
<th><span>Hash - Name</span></th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td>
<span>{{user['hash']}} - {{user['name']}}</span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
See here for more details about iterating over a loop in jinja2 templater.
You can send your result to render in python script:
#app.route('/')
def index():
return render_template('index.html', result='yes')
And in tempalte:
<p>Result {{ result }}</p>
In browser:
<p>Result yes</p>
There is a char field named json_field in Django Model. I am trying to iterate it from the view but it returns only one result as the return statement does. I am trying to figure it out how I can iterate json_field using yield.
the result that Model Object returns like:
id : 1
title : "Some Title"
json_field : [{"key":"value","key2":"value2"},{"key":"value","key2":"value2"}]
created : "Sat Oct 21 2017 14:00:53 GMT+0300 (+03)"
view.py
import json
def MyView(request):
model_query = MyModel.objects.all() or MyModel.objects.filter or exclude...
for item in model_query:
data_item = json.loads(item.json_field)
template = "template.html"
context = {"title":title, "data_item":data_item}
return render(request, template, context)
in template.html
{% for query_item in model_query %}
<table>
<thead>
<tr>
<th>{{ query_item.title }} - {{ query_item.created }}</th>
</tr>
</thead>
<tbody>
<tr>
<th>Some Heading </th>
<th>Some Heading </th>
</tr>
<!-- json data -->
{% for item in data_item %}
<tr>
<th>{{ item.key }}</th>
<td>{{ item.key2|floatformat:2 }}</td>
</tr>
{% endfor %}
<!-- json data -->
</thead>
</table><
{% endfor %}
Any help will be appreciated.
You can prepare dataset for you template.
# Fetch data from db as queryset of dicts
items = list(MyModel.objects.filter().values('title', 'created', 'json_field'))
# Decode json in-place
for item in items:
item['json_field'] = json.loads(item['json_field'])
context = {"title":title, "items": items}
Then interate through items inside your template:
{% for item in items %}
<table>
<thead>
<tr>
<th>{{ item.title }} - {{ item.created }}</th>
</tr>
</thead>
<tbody>
<tr>
<th>Some Heading </th>
<th>Some Heading </th>
</tr>
<!-- json data -->
{% for entry in item.json_field %}
<tr>
<th>{{ entry.key }}</th>
<td>{{ entry.key2|floatformat:2 }}</td>
</tr>
{% endfor %}
<!-- json data -->
</thead>
</table><
{% endfor %}
If you're using PostgreSQL, you can using JSONField. It uses the postgres's jsonb type, which is optimized for keeping a json serializable text.
If not, you still can use django-jsonfield. It almost gives the same functionality, even though some of the cool features of django's JSONField are not available (like this kind of lookups).
If none of these work for you, you can also implement your own JSONField by inheriting from CharField or TextField, and overriding some of the functions. This way, you won't need any of the logics of your field in your views.
Edit:
If you find changing your field hard or don't wanna do it for whatever reason, you can do this in your view:
for item in model_query:
item.loaded_json = json.loads(item.json_field)
then you can use it like a normal field in your template:
{% for query_item in model_query %}
{% for item in query_item.loaded_json %}
<span>{{ item.key }}</spam>
{% endfor %}
{% endfor %}
Hello!
The solution depends on your purposes.
Use comprehensions if you want to construct a list of json arrays:
data_items = [json.loads(item.json_field) for item in model_query]
... or generator of json array:
data_items = (json.loads(item.json_field) for item in model_query)
If you want to have a single array of json objects try this:
data_items = []
for item in model_query:
data_items.extend(json.loads(item.json_field))
Then you can use data_items as a template context.
A little tip: You can utilize JSONField at ORM level if you use PostgreSQL or MySQL. Consider this approach if you plan to make any filter queries on this field. As additional benefit JSON encoding/decoding will be out of box.
Thanks for updating your code!
Now I would restructure the json.load() list of dicts so you can use it. That is better style than mangling in the template.
concatenation is done by:
my_dict = dict()
for d in data_item
my_dict.update( d )
if you want to merge, check this thread:
How to merge two dictionaries in a single expression?
My Template is outputting the below. It doesnt pull in any of the queried values, but the page loads fine and doesnt fail, but it doesnt show any of the values.
I double checked the query in a mysqlmonitor, and it pulls 3 records as it should.
<li></li>
In the templates/index.html I have:
{% for blogpost in blogposts %}
<li>{{blogpost[0]}}</li>
{% else %}
<li>no blog posts right now...</li>
{% endfor %}
app.py has this:
import pymysql.cursors
app = Flask(__name__)
connection = pymysql.connect(host='localhost', user='myuser', port=3306, password='mypass', db='mydb', charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor)
#app.route('/', methods=('GET', 'POST'))
def email():
form = EmailForm()
curs = connection.cursor()
curs.execute("SELECT post_title, post_name, YEAR(post_date) as YEAR, MONTH(post_date) as MONTH FROM mydb.wp_posts WHERE post_status='publish' ORDER BY RAND() LIMIT 3")
blogposts = curs.fetchall()
if request.method == 'POST':
return render_template('index.html', form=form, blogposts=blogposts)
if __name__ == '__main__':
app.run()
UPDATE I think my for() is not working correctly, because when i update in the template i get all the data like:
[{u'MONTH': 12, u'YEAR': 2016, u'post_name': u'data is here', u'post_title': u'data is here'},
{u'MONTH': 12, u'YEAR': 2016, u'post_name': u'data is here', u'post_title': u"data is here"}]
How can i access this data in my flask template ?
Thank you so much!
Try finding out what is being sent to the template. Add print(blogposts) to the email function - just below the if request.method == 'POST': line and see what information it gives you.
If blogposts is a list of dictionaries, then you cannot access them by number. You need to use the name of the key. For example, you will need to change blogpost[0] to blogpost['name']. With Flask's templates you can also use the dot notation, so the blogpost name would become blogpost.name.
#app.route('/get', methods=['POST','GET'])
def requestCustomerDataFromTestForm():
data={'id':1, 'name':'Josh'}
return render_template("index.html", data = data)
In index.html
{% if data %}
<h1>{{data['id']}}</h1>
<h1>{{data['name']}}</h1>
{% endif%}
Or.. you can also iterate
<table class="table table-striped" >
<thead>
<tr>
<th scope="col">id</th>
<th scope="col">name</th>
</tr>
</thead>
<tbody>
{% for key, value in data.items() %}
<tr>
<th scope="row">{{ key }}</th>
<td>{{ value }}</td>
</tr>
{% endfor %}
</tbody>
</table>
Or, to display all data with their index
{% if data %}
<p>{{data}}</p>
{% endif %}