Here's my problem, in short:
I have an URL that looks like this: domain.tld/results?search_for=music
On that page, I have a form with a select field, which I then submit to Flask to do some SQL with.
Basically, the form looks like this:
<form action="/filter" method="POST">
<select name="sel_store">
{% for store in stores %}
<option value="{{ store }}">{{ store }}</option>
{% endfor %}
</select>
<button type="submit">SEND</button>
</form>
And in the back, it looks like this:
#app.route("/filter", methods=["POST", "GET"])
def filter():
search_for = request.args.get("search_for")
store = request.form["sel_store"]
return redirect(url_for("results", search_for=search_for, store=store))
(the results function does some SQL work with search_for and store, btw)
However, it doesn't seem to actually get any args from the URL, because it keeps giving me a NoneType object error.
What am I doing wrong here?
Thank you!
Not sure if this is the proper way to do it, but I managed to get it working by doing this:
<form action="{{ url_for('filtrare', search_for=request.args.get('search_for')) }}" method="POST">
Related
I am using Flask to create an HTML form (dropdown menu), where the values are being populated from a list values (which is output from a python function). The variable in the python app.py code is "two_dimensional_list" The sample values are:
[['001','Source1'],['342','Source2'],['968','Source5']]
(essentially the data is "IDs" and "Data Source Names"). The app.py code looks like this:
app.py
#app.route('/')
def index():
#drop down list (call Paxata to get a list of projects)
two_dimensional_list = PaxMatch.get_datasource_configs(authorization_token,paxata_url)
return render_template('index.html', datasources1=two_dimensional_list, datasources2=two_dimensional_list)
index.html
<select name= datasource1 method="POST" action="/">
{% for datasource1 in datasources1 %}
<option value= "{{datasource1[0]}}">{{datasource1[1]}</option>"
{% endfor %}
</select>
This is working fine, and the HTML page is being built correctly, ie:
<option value="001">Data Source 1</option>"
<option value="342">Data Source 2</option>"
<option value="968">Data Source 5</option>"
The challenge I am facing is that when I click the submit button, the only thing that is being passed to "Step2.html" (the next page) is the "value" (which is the "ID") and not the "Description". I need both.
It's an embarrassingly simple problem to solve I am sure, but can't seem to work out how to do it without calling my python function again which is incredibly inefficient.
Appreciate your help, thanks!
Here's a possible workaround.
Define your two-dimensional list variable outside of the function:
two_dimensional_list = [['001','Source1'],['342','Source2'],['968','Source5']]
Define your render_template() function:
#app.route('/')
def index():
return render_template('index.html', two_dimensional_list=two_dimensional_list)
Setup your form template:
<form method="POST" action="{{ url_for('data') }}">
<select name="datasource" method="POST" action="/post">
{% for datasource1 in two_dimensional_list %}
<option value= "{{datasource1[0]}}">{{datasource1[1]}}</option>"
{% endfor %}
</select>
<button type="submit">Submit</button>
</form>
Last but not least:
Get the selected ID value with request.form.get
Access the Description value with description_value(select)
Print out the result
#app.route('/data', methods=['GET', 'POST'])
def data():
id_value = request.form.get('datasource')
def description_value(select):
for data in two_dimensional_list:
if data[0] == select:
return data[1]
return description_value(id_value)
That's just how the select input works so you have to call the function again. You can make it more efficient and more semantic by using a dictionary with the ID as key and descriptions as values. :)
I have been trying to figure out why my Flask form will not properly validate my select field choices even though the choices are coming from the select field options.
My assumption is that the select option when passed back from the server is unicode and is being compared to the choice which is a string, however, I thought coerce=str would fix that. I printed out the form data and request data which is the output below. Why isn't it working?
My code is attached below, removed csrf token key from the output dict. It seems like a very simple thing, but I can't figure it out.
forms.py
class PlatformForm(FlaskForm):
platform_options = [('test', 'Test'), ('test2','Test2')]
platforms = wtforms.SelectField('Platforms', choices=platform_options, coerce=str, validators=[DataRequired()])
views.py
#app.route('/', methods=['POST', 'GET'])
def index():
form = forms.PlatformForm()
if form.is_submitted():
print form.data
print request.form
if form.errors:
print form.errors
return render_template('home.html', form=form)
index.html
{% extends "base.html" %}
{% block content %}
<h4>Select a Platform</h4>
<form method="POST">
{{ form.csrf_token }}
<select class="custom-select" name="platform">
{% for value, text in form.platforms.choices %}<br>
<option value="{{ value }}">{{ text }}</option>
{% endfor %}
</select>
<button id="submit_inputs" type="submit" class="btn btn-default">Submit</button>
</form>
{% endblock %}
output
{'platforms': 'None'}
ImmutableMultiDict([('platform', u'test')])
{'platforms': [u'Not a valid choice']}
EDIT:
I figured out the problem. It's the way I'm creating the Select drop down through HTML and Jinja. Iterating through the choices and creating option tags doesn't seem to instantiate anything in the form data itself when passed back into Python. Changing that whole for loop to just
{{form.platforms}}
created a select drop down field that actually works.
You have a name mismatch. In the form, you named your select field platforms (plural). In the HTML, you use platform (singular).
I recommend that instead of manually rendering the fields in your template, you let WTForms generate the HTML for you. For the form label, you can use {{ form.platforms.label }}, and for the actual field {{ form.platforms() }}. You can pass any attributes you want to field to have as keyword arguments.
I think something might be going wrong because of the way you are rendering the form in your html file. If my hunch is right, try this:
{% extends "base.html" %}
{% block content %}
<h4>Select a Platform</h4>
<form method="POST">
{{ form.hidden_tag() }}
Select: {{ form.plaforms}}
{{ form.submit(class="btn btn-default") }}
</form>
{% endblock %}
and then try if form.validate_on_submit() in your views.py file
taken from this stack overflow answer by pjcunningham:
"validate_on_submit() is a shortcut for is_submitted() and validate().
From the source code, line 89, is_submitted() returns True if the form
submitted is an active request and the method is POST, PUT, PATCH, or
DELETE.
Generally speaking, it is used when a route can accept both GET and
POST methods and you want to validate only on a POST request."
I have a problem with my search. At the moment i am trying to write a small receipe portal and i am trying to search words in tables user,category and recipe. When i write some word, i receive an error message:
Bad request. The browser (or proxy) sent a request that this server
could not understand.
I suppose, that problem stays in my function search, but i dont see it.
#app.route("/search", methods=['GET', 'POST'])
def search():
cursor = g.con.cursor()
cursor.execute('SELECT * FROM nutzer, kategorien, rezepte WHERE Nutzername OR Titel = %s', (request.form["search"],))
result = cursor.fetchall()
cursor.close()
return render_template('Results.html', result = result)
{% extends "layout.html" %}
{% block body %}
<table border="1">
{% for i in result %}
<tr><td>{{ i.1 }}</td></tr>
{% endfor %}
</table>
{% endblock %}
HTML Code of the searchbar
<form action="search">
<input name="search" type="text" placeholder="suchen" value="{{ request.form.search}}" required />
<button>finden</button>
</form>
request.form() implies the POST method, while the default one is GET. You should either check request.method and use request.args() in the case of GET, or add the argument method="POST" to the <form> (and leave POST as the only accepted method in #app.route().
I think your form action has to point to your search endpoint.
<form action="{{ url_for(search) }}">
<input name="search" type="text" placeholder="suchen" value="" required />
<button>finden</button>
</form>
I am trying to pass some dynamic values from my form, but so far I am only getting empty values.
I have an autocomplete plugin, where I search for "names" from a JSON object, each time I select one they will pass into a list with value="the ID".
I couldn't find a unordered list in WTForms, so I am using SelectMultipleField instead, since it is able to pass many values as an array/list
my form class is looking like this:
class ClassForm(Form):
function_name = StringField('names')
studentid = SelectMultipleField('studentid')
submit = SubmitField('submit')
then in my template I am using it like this
<form id="function_search_form" method="post" action="">
{{ form.csrf_token }}
{{form.function_name.label()}}
{{form.function_name()}}
<!-- then I am not using studentid directly,
but just normal html, so each time you pass
in a name from the json object it will come in like this.
-->
<ol class='student-list'>
<li value="1" name="studentid" id="studentid">test</li>
</ol>
{{ form.submit()}}
</form>
My problem is that it wont get the value from the list, even if I hard code the values directly, instead from the jquery script.
Here is how my view looks like
#app.route('/index', methods=['GET', 'POST'])
def index():
form = ClassForm()
if request.method == 'POST' and form.validate_on_submit():
flash('valid form')
st = form.studentid.data
print(st)#debug
return render_template('index.html', form=form)
Everytime I submit I am printing form.studentid.data I am getting [], which is an empty list.
Even when I try to pass single values and make studentid to a StringField I am still getting an empty value.
I have also tried the request.form['studentid'] but then I am getting Bad Request What am I doing wrong and is there another way to pass "custom" values ?
The reason its not working is because <li> is not a form control, so its data is not sent back with the form request.
You are never rendering the studentid field from your form class, so the form control is never rendered. It would be like expecting the following to work:
<form>
<p name="foo" data="hello">This should be sent</p>
<input type="submit">
</form>
To get the data back to your view method, you need to use a form control - you can test it out like this:
<form id="function_search_form" method="post" action="">
{{ form.csrf_token }}
{{form.function_name.label()}}
{{form.function_name()}}
<select name="studentid" class='student-list'>
<option value="1">test</option>
</select>
{{ form.submit()}}
</form>
Or, simply render the field correctly:
<form id="function_search_form" method="post" action="">
{{ form.csrf_token }}
{{form.function_name.label()}}
{{form.function_name()}}
{{form.studentid.label()}}
{{form.studentid}}
{{ form.submit()}}
</form>
So, I'm making a search function and I would like the previously entered query to remain in the search box when the search results are rendered. Currently the way that I'm doing this is by sending a POST request, grabbing the query and sending that back to the template as a variable. For some reason though, it will only work for the first word of the query, and all subsequent words get dropped. When I render the same variable within a tag however it comes out just as I would expect. Is there something there I'm not doing quite right?
<div id="searchwrapper">
<form action="/search" method="post"> {% csrf_token %}
{% if old_query %}
<input type="text" class="searchbox" name="s" value={{old_query}} />
{% else %}
<input type="text" class="searchbox" name="s" value="" />
{% endif %}
<input type="image" src="static/images/search-icon.svg" class="searchbox_submit" value="" />
</form>
</div>
def search(request):
context = {}
context.update((csrf(request)))
results_string = ""
if request.POST:
results_string = find(request)
old_query = request.POST['s']
context.update({"old_query": old_query})
search_bar = render_to_string("search.html", Context(context))
return HttpResponse(search_bar + results_string)
I don't think that the find method is relevant, but let me know if you think it would be useful and I can post it. The template is the relevant part of "search.html" Like I said, if I add the line <p>{{ old_query }}</p> to the {% if old_query %} section, the right value shows up, but at present if I used a query like hello stackoverflow! I would only get "hello" in as the value for the search field.
This is probably something silly, but I'm fairly new to web dev, so any help is appreciated.
Fix this line to wrap {{old_query}} between quotes:
<input type="text" class="searchbox" name="s" value="{{old_query}}" />
That should give you the whole search instead of the first word.