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 %}
The Problem is that your HTML form does not have a name.
request.args.get("som") needs an HTML form input with the name "som"
<select name="som" id="som" size="20">
Just change that line and add a name. The form is not interested in the id attribute.
You don't specified the method of the form, you have to do it! For example use this<form method="POST action"/pop">
Your form action is /pop. That means that if you submit the form it will do a POST request to the address /pop. Your code does only return a value for a GET request, therefore Flask complains you do not return anything. Write some code to process a POST request and return a text or rendered template.
BTW, in the code for GET you refer to request.args.get('som'); this gives you request arguments (i.e. in the URL), not from the form. som is in the form, so you cannot refer to it this way.
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 am trying to delete an object from database using simple html button. Also, trying to implement "are you sure" message? BUt I am getting this error everytime and I am not able to crack.
This is my view function.
def customerdel(request,pk):
objs = Customer.objects.filter(id=pk)
if request.method == 'POST':
objs.delete()
# messages.success(request, 'Successfully deleted')
return render(request,'records.html')
else:
content ={
'items':Customer.objects.all
}
return render(request,'delete.html', content)
This is record.html page
<h1>Record's page</h1>
{% for abc in Customerdata %}
{{abc.name}}
{{abc.pk}}
<form >
<button class="btn btn-danger btn-sm">
Delete</button>
</form>
{% endfor %}
This is delete.html page
<h1>Welcome to Delete page</h1>
<p>Are you sure want to del {{items.name}} ??</p>
<form action="{% url 'customerdel' items.pk %}" method="post">
{% csrf_token %}
Cancel
<input name="confirm" type="submit" >
</form>
This is my URL.
path('dashboard/records/customerdel/<int:pk>', views.customerdel, name='customerdel'),
You are doing wrong while template rendering as you are not sending any data to the template.But inside the record.html you are trying to iterate over CustomerData which is not defined.So send it to the template or another way is to simply redirect to the route which is made for rendering record.html.
Here is the full code which you should apply in your django project to make it work.
from django.http import HttpresponseRedirect
from django.urls import reverse #these two lines are required for redirecting to a previous route(url)
As you must have set a url which takes to the records function something like this;
path('records', views.records, name='records')
If you haven't added the name, add it.
Then in views.py, in customerdel function;
if request.method == 'POST':
#write your code which you already wrote and instead of return render(...) write this;
return HttpResponseRedirect(reverse('records')) #where records is the name of the url which takes us to the records page.
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.
I have created a dropdown menu to search for parts by project number from an SQL database. The first page loads with the correct parts but any pages subsequent give the error of:
TypeError: show_compound() missing 1 required positional argument: 'search_string'
From what I've seen online it seems I may need to use *args or pass the search_string to the template but I am unsure of how to use *args or where to insert the search_string value on the template.
#parts_database.route('/searchcompound', methods=['GET', 'POST'])
#login_required
def compounds_search():
form = ProjectSearch(request.form)
if form.validate_on_submit():
search_string = form.select.data.project_number
return show_compound(search_string)
return render_template('parts_database/search_compounds.html', form=form)
#parts_database.route('/showcompound', methods=['GET'])
#login_required
def show_compound(search_string):
page = request.args.get('page', 1, type=int)
pagination = PartsTable.query.filter_by(project_number=search_string).order_by(PartsTable.part_number).paginate(page, per_page=15, error_out=False)
compound = pagination.items
page_10 = pagination.next_num+9
if page_10 > pagination.pages:
pageincrement = pagination.pages
else:
pageincrement = page_10
page_decrement = page - 10
if page_decrement < 1:
page_decrement = 1
return render_template('parts_database/showpartstable.html', compound=compound, pagination=pagination, pageincrement=pageincrement, page_decrement=page_decrement)
template :
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% import "_macros.html" as macros %}
{% block title %}Amos{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>Parts</h1>
{% include 'parts_database/_showpartstable.html' %}
{% if pagination %}
<div class="pagination">
{{ macros.pagination_widget(page_decrement, pageincrement, pagination, '.show_compound') }}
</div>
{% endif %}
</div>
{% endblock %}
If a view takes an argument, you must include that variable in the route.
In your case, you are missing search_string in your show_compound route definition. Try something like this:
#parts_database.route('/showcompound/<search_string>', methods=['GET'])
#login_required
def show_compound(search_string):
(...)
EDIT:
Also, I'd sugest to redirect instead of calling another view's function.
Replace this:
if form.validate_on_submit():
search_string = form.select.data.project_number
return show_compound(search_string)
with this:
You'll have to import redirect before that:
from flask import redirect # (Add this at the top)
(...)
if form.validate_on_submit():
search_string = form.select.data.project_number
return redirect(url_for('parts_database.show_compound', search_string=search_string))
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.