I am trying to call a function from another python file. I have imported that function. When i call the function externally it works as expected.
But when i try to call the function before returning a render_template or a redirect , i get a 500 error.
I know i am doing something wrong but i am not sure what. Any kind of help will be highly appreciated.
from flask import Flask, render_template, request, redirect, url_for
from content_man import Content,Page_Content
from url_trigger import trigger
TEST_TOPIC = Content()
PAGE_TOPIC = Page_Content()
app = Flask(__name__)
#app.route('/',methods=["GET","POST"])
def homepage():
return render_template("main.html")
#app.route('/dashboard/',methods=["GET","POST"])
def dashboard():
return render_template("dashboard.html", TEST_TOPIC=TEST_TOPIC)
#app.route('/test/', methods=["GET","POST"])
def test():
if request.method == "POST":
selected_list = request.form.getlist("to_run")
print (selected_list)
return redirect(url_for('trigger',selected_list=selected_list))
else:
return render_template("test.html", PAGE_TOPIC=PAGE_TOPIC)
#app.route('/trigger/', methods=["GET","POST"])
def trigger():
data = request.args.getlist('selected_list')
t = trigger(data)
return "hey"
if __name__ == "__main__":
app.run()
The error is in #app.route('/trigger/', methods=["GET","POST"]) where i am trying to call the function trigger.
My url_trigger python file contains the below simple definition:
def trigger(my_list=[], *args):
for i in my_list:
print (i)
The HTML file for the page test is as:
<div class="container">
<form method="post" action = "{{ url_for('test') }}">
{% for row_index in range(PAGE_TOPIC['Critical BP']|count) %}
<div class="checkbox">
<label><input type="checkbox" name="to_run" value="{{ PAGE_TOPIC['Critical BP'][row_index] }}">{{ PAGE_TOPIC['Critical BP'][row_index] }}</label>
</div>
{% endfor %}
<div>
<label><input type="submit" /></label>
</div>
</form>
</div>
You import a function named trigger, but you also a define a function named trigger in the module where you do the import. When trigger calls trigger, it is calling itself, and it accepts no arguments. You need to rename one of the functions, or do the import as import url_trigger and then refer to the imported function as url_trigger.trigger.
Related
I am writing a web application which accepts user input in an HTML form written in Jinja2.
Based on the input, I set variables defined in Jinja2 which I then want to pass as positional arguments to another function defined in either my __init__.py file or main.py file.
Python version==3.6.8
Flask==2.0.1
Jinja2==3.0.1
I attempted many ways to achieve this but could not so (got an undefined error when trying to call the function), including following the suggestions in this thread: Call a python function from jinja2
The file structure of my web app looks like so:
https://prntscr.com/1rlt3cl (I can't post images because I don't have enough reputation points so I uploaded it here).
I am receiving user input in my form.html file which I pass to the data.html file.
<form action="/data" method = "POST">
<p>Various inputs<input type = "number" name = "random" /></p>
<p><input type = "submit" value = "Submit" /></p>
</form>
From the data.html file, I want to accept the values inputted by the user, and call a function which sits in all of my __init__.py files (wasn't sure which one Flask actually looks at):
{% set ns1 = namespace(random=None) %}
{% for key,value in form_data.items() %}
{% if key == "iterations" %}
{%- set ns1.iterations = value -%}
{% endif %}
{% endfor %}
{{ clever_function(random) }}
clever_function is defined in the __init__.py file as so:
from jinja2 import Template
def clever_function():
return "Hello"
template = Template("{{ clever_function() }}")
template.globals['clever_function'] = clever_function
When running my application from webapp/main.py which renders the form / data templates like so:
#app.route('/form')
def form():
return render_template('form.html')
#app.route('/data', methods = ['POST', 'GET'])
def data():
if request.method == 'GET':
return f"The URL /data is accessed directly. Try going to '/form' to submit form"
if request.method == 'POST':
form_data = request.form
return render_template('data.html',form_data = form_data)
I receive the following exception:
jinja2.exceptions.UndefinedError: 'clever_function' is undefined
The code you use is a brief description of the exclusive use within a directly defined template.
To use a custom function within a template used by render_template, you have to add it to the dictionary globals of the jinja environment.
from flask import Flask
from flask import render_template, request
def clever_function(value):
return value**2
app = Flask(__name__)
app.jinja_env.globals.update(clever_function=clever_function)
#app.route('/form')
def form():
return render_template('form.html')
#app.route('/data', methods=['POST'])
def data():
return render_template('data.html', form_data=request.form)
From now on, this function can be called in every template which is loaded and called up with this environment.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<p>Result: {{ clever_function(form_data.get('random', 0) | int) }}</p>
</body>
</html>
Please keep in mind that the defined function must accept parameters if you want to call it up with any.
Errors have also crept in when using the namespace object. You should take another look at the documentation for the assignments in jinja2.
Here is a small example based on your code.
{% set ns1 = namespace(random=0) %}
{% for k,v in form_data.items() %}
{% if k == 'random' %}
{% set ns1.random = v | int %}
{% endif %}
{% endfor %}
<p>Value is {{ns1.random}}</p>
I'm trying to get information from a form to my python file and then put into a template. Thing is, i know the form is working but i couldn't show it into the template.
Form here:
<div class="container" id="cont1">
<form action="http://127.0.0.1:5000/areas" method="POST" enctype="multipart/form-data">
<label for="author">Autor</label>
<input type="text" id="author" name="author"><br><br>
<label for="intro">Introdução</label>
<input type="text" id="intro" name="intro"><br><br>
<label for="content">Conteúdo</label>
<input type="text" id="content" name="content"><br><br>
<input type="file" id="planilha" name="planilha" accept=".csv"><br><br>
<input type="submit" value="Enviar">
</form>
</div>
then i try to get the data in app.py:
#app.route('/areas', methods=['GET', 'POST'])
def areas():
if request.method == "POST":
#app.context_processor
def f1():
aut = request.form.get['author']
intr = request.form['intro']
cont = request.form['content']
return dict(a=aut, i=intr, c=cont)
return render_template("areas.html")
else:
return render_template("areas.html")
I know it's working because i tried it out of the route and it showed what the form had. Now when i try into the route:
AssertionError
AssertionError: A setup function was called after the first request was handled. This usually indicates a bug in the application where a module was not imported and decorators or other functionality was called too late.
To fix this make sure to import all your view modules, database models and everything related at a central place before the application starts serving requests.
The decorator was the solution i found to get the data so i could place into templates like this:
<text>{{a}}</text>
The error is caused by the incorrect usage of the decorator. You don't need a decorator to pass variables to templates. render_template also accepts arguments which you can directly pass into your HTML file.
The following should work:
#app.route('/areas', methods=['GET', 'POST'])
def areas():
if request.method == "POST":
aut = request.form['author']
intr = request.form['intro']
cont = request.form['content']
return render_template("areas.html", a=aut, i=intr, c=cont)
else:
return render_template("areas.html")
I have just started to learn flask but I am stuck with this 405 error
# Weather App using Flask
## imports
import main
from flask import Flask
from flask import render_template
from flask import request
app = Flask(__name__)
## initalisation
#app.route('/')
def main_page(methods=["GET", "POST"]):
if request.method == "POST":
city = request.form("city")
print(city)
return render_template("main.html")
if __name__ == "__main__":
app.run(debug=True)
the main.html is
{% extends "base.html" %}
{% block content %}
<form method="POST">
<p><input type="text" name="city"></p>
<p><input type="submit" value="Submit"></p>
</form>
{% endblock %}
the POST is in the methods argument, but I cannot pinpoint where the error is
thanks in advance
Instead of having the methods list in the view function's parameters, you should have it in the brackets that follow your decorator, like so:
#app.route('/',methods=["GET","POST"])
def main_page():
# your view function
This will allow this route to be accessed through both GET and POST requests.
Im having trouble getting anything from the shown HTML form
I always get "ValueError: View function did not return a response"
Can somebody help me out here please? I have tried every variation of request.get that I can find on the web. Also if I specify my form should use post it uses get anyway - anybody know why this is?
Im new to flask so forgive my ignorance!
Thanks in advance.
The python file (routes.py)
from flask import Flask, render_template, request
import os
app = Flask(__name__)
musicpath = os.listdir(r"C:\Users\Oscar\Music\iTunes\iTunes Media\Music")
lsize = str(len(musicpath))
looper = len(musicpath)
#app.route('/')
def home():
return render_template('home.html', lsize=20, looper=looper, musicpath=musicpath)
#app.route('/pop', methods=['POST', 'GET'])
def pop():
if request.method == "GET":
text = request.args.get('som')
return text
#Have tried every variation of request.get
#app.route('/about')
def about():
name = "Hello!"
return render_template('about.html', name=name)
if __name__ == '__main__':
app.run(debug=True)
The html file (home.html)
{% extends "layout.html" %}
{% block content %}
<div class="jumbo">
<h2>A Music app!<h2>
</div>
<div>
{% if lsize %}
<form action="/pop">
<select id="som" size="20">
{% for i in range(looper):%}
<option value="{{i}}">{{ musicpath[i] }}</option>
{% endfor %}
</select>
</form>
{% endif %}
</div>
Select,
{% endblock %}
You don't have a name attribute on your select element. That is the attribute that browsers use to send information in forms; without it no data will be sent.
Note also that your pop handler does not do anything if the method is POST, even though you explicitly say you accept that method.
I I am getting a 500 error when I click submit for the following view. Why am I getting this error and how do I fix it?
from flask import Flask, render_template
from flask import request, jsonify
app = Flask(__name__)
#app.route('/', methods=['GET', 'POST'])
def homepage():
if request.method == 'POST':
f1 = request.form['firstVerb']
f2 = request.form['secondVerb']
return render_template('index.html', f1, f2)
return render_template('index.html')
if __name__ == "__main__":
app.run();
<form class="form-inline" method="post" action="">
<div class="form-group">
<label for="first">First word</label>
<input type="text" class="form-control" id="first" name="firstVerb">
</div>
<div class="form-group">
<label for="second">Second Word</label>
<input type="text" class="form-control" id="second" name="secondVerb" >
</div>
<button type="submit" class="btn btn-primary">Run it</button>
</form>
{{ f1 }}
{{ f2 }}
First off when you are getting a 500 error you should consider running the app with debug mode. You are building this app and while you are debugging, it is very useful to have this on to show you what happens when an error happens.
if __name__ == "__main__":
app.run(debug=True)
Now this gets you something more exciting:
127.0.0.1 - - [08/Jul/2015 14:15:04] "POST / HTTP/1.1" 500 -
Traceback (most recent call last):
...
File "/tmp/demo.py", line 11, in homepage
return render_template('index.html', f1, f2)
TypeError: render_template() takes exactly 1 argument (3 given)
There is your problem. You should refer to the documentation for render_template and see that it really only accepts one positional argument (the template name), but the rest of the arguments (in **context) msut be provided as keyword arguments. Otherwise there would be no references to the variables that were being referred to in the template, so fixing that call to:
return render_template('index.html', f1=f1, f2=f2)
Would provide the correct f1 and f2 to the template, thus solving the problem at hand.
For future reference, problems like these can be solved by reading the Flask documentation. Also, please go through this entire Flask tutorial to help you grasp the basics of this framework.