I'm newbie in flask,I want to get mysql data to show in web.But it's unicode,so I try use two for to solve it .But now I want to know the reason why I can use two for loops to encode unicode to utf-8
flask code
#coding=utf-8
from flask import Flask, request, render_template
from flaskext.mysql import MySQL
mysql = MySQL()
app = Flask(__name__)
app.config['MYSQL_DATABASE_USER'] = 'root'
app.config['MYSQL_DATABASE_PASSWORD'] = ''
app.config['MYSQL_DATABASE_DB'] = 'test'
app.config['MYSQL_DATABASE_HOST'] = 'localhost'
mysql.init_app(app)
#app.route('/')
def showbookname():
cursor = mysql.get_db().cursor()
cursor.execute("SELECT * FROM manager ")
bookname = cursor.fetchall()
return render_template('book.html', bookname = bookname)
if __name__ == '__main__':
app.run( debug = True)
the incorrect HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ bookname }}
</body>
</html>
the result((u'Tom',123'), (u'Mark', u'123')),my expected result is ((Tom,123),(Mark,123))
the correct HTML(although I didn't achieve my goal.)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% for items in bookname %}
{% for item in items %}
{{ item }}
{% endfor %}
{% endfor %}
</body>
</html>
the reasult is Tom 123 Mark 123 .It's like two for loops iterate over the table and print all data
Your expectation is incorrect unfortunately. The original output is correct - you're printing out the list of rows itself and it's not an unicode issue. That means the rows have to be serialised in some way that's possible to display. In this case that's ((column, column, ...), (column, column, ...), ...). It comes from python's repr(bookname) and you shouldn't rely on it to look in any specific way. It just happens to show which strings are unicode by prepending the u.
If you want the output you expected, you have to construct it yourself:
(
{% for items in bookname %}
(
{% for item in items %}
{{ item }}
{% if not loop.last %}
,
{% endif %}
{% endfor %}
)
{% if not loop.last %}
,
{% endif %}
{% endfor %}
)
You'll have to remove the whitespace from the template if you don't want it in the output. But I expect that in reality you want a different output format - you just need to adjust your template for it.
Related
I have 4 files:
flask_blog.py
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
#app.route("/home")
def home_page():
return render_template("home.html")
#app.route("/about")
def about():
return render_template("about.html", title = "About")
layout.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
{% if title %}
<title>Flask Blog - {{ title }}</title>
{% else %}
<title>Flask Blog</title>
{% endif %}
</head>
<body>
{% block content %}{% endblock content %}
</body>
</html>
home.html
{% extends "layout.html" %}
{% block content %}{% endblock content %}
about.html
{% extends "layout.html" %}
{% block content %}{% endblock content %}
On my about page, the title is "Flask Blog - About", and in my home page, the title is "Flask blog". Now, this is happening due to the if/else statements in the layout.html file. The if/else statements are:
{% if title %}
<title>Flask Blog - {{ title }}</title>
{% else %}
<title>Flask Blog</title>
{% endif %}
Now, the value of the 'title' variable must be 0 or None, since we are going to the else statement for the home page. Now, my question is, we didn't assign a value to the 'title' variable beforehand. Better yet, we haven't even created the 'title' variable in the flask_blog.py file. How are we not getting a NameError? Shouldn't we get NameError: name 'title' is not defined?
Related
The templating language used by default in flask is Jinja. Jinja is not Python, and as such it works a little differently sometimes.
When a variable is not defined, if statements in Jinja template evaluate to False. As a result it doesn't throw an exception but instead it just goes to the next else block.
More specifically, an undefined variable becomes of type Undefined, which has it's own documentation page: https://jinja.palletsprojects.com/en/3.1.x/api/#undefined-types
This is useful in a templating language, because it makes it easier to re-use complex templates without having to specify every parameter every time you render it. If a parameter (and corresponding if block) is not relevant for a call to render_template, you can just omit it and don't worry about it.
I am completely new to App building with Flask and Python.
I am trying to create Google column charts, which change dynamically, when i change the data in my Phython file.
I tried a lot of different way, which are described on stackoverflow, but they dont fit to my demand.
I have no knowledge about Javascript.
My data look like this list:
Status = [('active', '106297'), ('inactive', '236'), ('planned', '27453')]
#app.route('/test03')
def test03():
return render_template('chart.html', **globals())
I already tried to convert this list into JSON, but i wasn't able to find the right format.
Would be really nice, if you can help me. :)
Update:
from flask import Flask, render_template, request, jsonify, url_for
import gviz_api
# Creating the data
description = {"name": ("string", "Name"),
"salary": ("number", "Salary")}
data = [{"name": "Mike", "salary": 10000},
{"name": "Jim", "salary": 800},
{"name": "Alice", "salary": 12500},
{"name": "Bob", "salary": 7000}]
# Loading it into gviz_api.DataTable
data_table = gviz_api.DataTable(description)
data_table.LoadData(data)
# Create a JavaScript code string.
jscode = data_table.ToJSCode("jscode_data",
columns_order=("name", "salary"),
order_by="salary")
# Create a JSON string.
jsonData = data_table.ToJSon(columns_order=("name", "salary"),
order_by="salary")
print("Finish")
app = Flask(__name__)
# charts = GoogleCharts(app)
#app.route('/')
def test():
return render_template('chart.html', **globals())
if __name__ == '__main__':
# app.run(debug=True, host='192.168.43.183', port=800) # Home
and the chart.html file:
{% extends 'base.html' %}
{% block head %}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<script>
google.charts.load('current', {packages: ['corechart']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
// Define the chart to be drawn.
var data = new google.visualization.DataTable(jsonData);
// Instantiate and draw the chart.
var chart = new google.visualization.ColumnChart(document.getElementById('myPieChart'));
chart.draw(data, null);
}
</script>
{% endblock %}
{% block body %}
<h1>Hello, this is my Columnchart-Test</h1>
<!-- Identify where the chart should be drawn. -->
<div id="myPieChart"></div>
{% endblock %}
and the base.html file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link href="{{ url_for('static', filename='css/main.css') }}" type="text/css" rel="stylesheet">
{% block head %}{% endblock %}
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>
But it still doesn't work. - I think there is a problem with the transfer of jsonData to JS.
I recently ran into the same exact problem when I was trying to create a chart for a web app I was making and even considered using chart.js because I suspected it would be easier but I found a solution. What you need to do is pass in the data to be graphed as a dictionary then loop through it using jinja formatting in the html file. i.e.
from flask import Flask, render_template, request, jsonify, url_for
import gviz_api
#app.route('/')
def test():
return render_template('chart.html', data={"Name":"Salary", "Mike":10000, "Jim":800, "Alice":12500,"Bob":7000})
if __name__ == '__main__':
app.run(debug=True)
And the chart.html should be something like this
{% extends 'base.html' %}
{% block head %}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<script>
google.charts.load('current', {packages: ['corechart']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
// Define the chart to be drawn.
var data = new google.visualization.arrayToDataTable([
{% for k, v in data.items() %}
{% if v is string %}
['{{ k }}', '{{ v }}'],
{% else %}
['{{ k }}', {{ v }}],
{% endif %}
{% endfor %}
]);
// Instantiate and draw the chart.
var chart = new google.visualization.ColumnChart(document.getElementById('myPieChart'));
chart.draw(data, null);
}
</script>
{% endblock %}
{% block body %}
<h1>Hello, this is my Columnchart-Test</h1>
<!-- Identify where the chart should be drawn. -->
<div id="myPieChart"></div>
{% endblock %}
I dont think any changes need to be made to the base.html file. This worked for me so I think it should work for you too.
You need to add {{ jsonData || safe }} in the template part and you just need to put the jinja bit.
I'm not sure about globals but jsonData=jsonData in the app.py returns template bit.
Template:
var data = new google.visualization.DataTable( {{ jsonData|safe }} );
app.py:
return render_template('chart.html', jscode=jscode, jsonData=jsonData)
I am trying to create map in Django using folium. There is no error message, but instead of the map it displays the word 'None'.
I have a django web app that reads from a postgressql database and displays the records. That is working. I want to add a map with markers, and the markers will get coordinates from the postgresql data. When I try to create a map using iframe, I get the word 'None'. I have tried just hard coding a starting location to just create the map. I still get the word 'None'.
I also typed the hard coded coordinates into google maps, and made a flask app that creates the map. They show up fine.
views.py:
from django.shortcuts import render
from django.http import HttpResponse
from .models import PhotoInfo
import folium
import pandas
# Create your views here.
def index(request):
VarPhotoInfo = PhotoInfo.objects.order_by('DateTaken')
context = {'PhotoInfo': VarPhotoInfo }
return render(request,'natureapp/index.html',context)
def show_map(request):
#creation of map comes here + business logic
#PhotoInfo1 = PhotoInfo.objects.order_by('DateTaken')
map = folium.Map(location=[33.57137166666667, -117.76325])
map.save("natureapp/map.html")
context = {'my_map': map }
return render(request, 'natureapp/map.html', context)
map.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>NatureMapper</title>
</head>
<h1>Map goes here </h1>
{{ my_map.render }}
</html>
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>NatureMapper</title>
</head>
<h1>Here it is! </h1>
{% if PhotoInfo %}
{% for Photo in PhotoInfo %}
<p>there is info.</p>
<p> {{ Photo.PhotoName }}</p>
<p> {{ Photo.Lat }}</p>
<p> {{ Photo.Long }}</p>
<p> <img src="{{ Photo.PhotoImage.url }}" width = "240" alt=""></p>
{% endfor %}
{% else %}
<p>there is no info.</p>
{% endif %}
<iframe id="encoder_iframe" height=95% width="90%" src="{% url 'show_map' %}">
</iframe>
</html>
There is no error message. Just the word 'None'
I'm new to programming. I decided to try to create a web app using flask, python, and HTML. I set up three files; two HTML and one python:
This is the HTML file that should have information replaced (didntwork.html):
<!doctype html>
<html>
<head>
<title>My Webpage</title>
</head>
<body>
<h3>Information:</h3>
{% block body %}{% endblock %}
</body>
</html>
.
This is the file that should input information to the first (connection.html):
{% extends 'didntwork.html' %}
{% block body %}
<h4>information content</h4>
{% endblock %}
.
Finally, this is the logic for the flask app in python (main.py):
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/')
def index():
return render_template('didntwork.html')
if __name__ == '__main__':
app.run(debug=True)
Unfortunately, the extends in the second HTML file does not seem to be recognized, and the information in its block will not be replaced in the first HTML file (didntwork.html).
This is the output:
The expected outcome should append an h4 tag to the body with the phrase 'information content'.
Any help would be appreciated, thanks.
The problem is the {% extends 'didntwork.html' %}. From what I can tell the file that contains this code:
<!doctype html>
<html>
<head>
<title>My Webpage</title>
</head>
<body>
<h3>Information:</h3>
{% block body %}{% endblock %}
</body>
</html>
is your connection.html file.
You are extending to the same file you're rendering (didntwork.html). You have to change the extends line to extend your base html, connection.html in this case.
Use this code in your didntwork.html:
{% extends 'connection.html' %}
{% block body %}
<h4>information content</h4>
{% endblock %}
You can find more information in Template Inheritance
UPDATE BASE ON CLARIFICATION
You're rendering the wrong file in your route.
You should render the connection.html and this will extends your didntwork.html file.
In jinja2, I am trying to dynamically create a html document using the template more than once.
My python script looks like this:
# In my python script
env = Environment()
env.loader = FileSystemLoader('.')
base_template = env.get_template('base_template.html')
# each has the actual content and its associated template
content1 = ("Hello World", 'content_template.html')
content2 = ("Foo bar", 'content_template.html')
html_to_present = [content1[1], content2[1]]
# and render. I know this is wrong
# as I am not passing the actual content,
# but this is the part I am struggling with. More below
base_template.render(include_these=html_to_present, ).encode("utf-8"))
And my base template looks like this:
#################
# base_template.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
{% for include_this in include_these %}
{% include include_this %}
{% endfor %}
</body>
</html>
and content_template.html looks like this
# content_template.html
<div>
{{ content }}
</div>
Now my question is how do you dynamically set content variable in the content_template.html based on the value associated with it?
Use Jinja2 macros to parameterise your templates.
A macro is like a Python function; you define a template snippet, plus the arguments it takes, and then you can call the macro just like you would a function.
I'd put the macros together into one macro template and import that template into your base template. Pass in the names of the macros you want to use to the base template:
# content and macro name
content1 = ("Hello World", 'content_template')
content2 = ("Foo bar", 'content_template')
base_template.render(include_these=[content1, content2]).encode("utf-8"))
This adds the macro context filter to the environment as well.
and in your base_template.html have:
{% import "macros.html" as macros %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
{% for content, macroname in include_these %}
{% macros[macroname](content) %}
{% endfor %}
</body>
</html>
and the macros.html template:
{% macro content_template(content) -%}
<div>
{{ content }}
</div>
{%- endmacro %}