Search function in Flask - python

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>

Related

switch/toogle results in BadRequestKeyError: 400 Bad Request

I have an index.html generated with python & flask that shows a list. I want to filter this list by a bootstrap switch. Now I have the following code and it works to show my index.html list by GET request. enabling the switch also works and shows the filtered list. But when switching back to unfiltered/off I receive a bad request. the problem is with switchvalue = request.form['switch'] but I dont understand why this is.
Python code:
#app.route('/', methods=['POST', 'GET'])
def index():
conn = get_db_connection()
if request.method == 'POST':
switchvalue = request.form['switch']
flash(switchvalue)
if switchvalue == '1':
rows = conn.execute('SELECT Name, CAST (Points AS int) as Points, isActive FROM table WHERE isActive = "Active"').fetchall()
conn.close()
return render_template('index.html', rows=rows, switchcheck=1)
rows = conn.execute('SELECT Name, CAST (Points AS int) as Points, isActive FROM table').fetchall()
conn.close()
return render_template('index.html', rows=rows, switchcheck=0)
HTML:
...
{% block content %}
<h1>{% block title %} Title {% endblock %}</h1>
<form method="POST" action="{{ url_for('index') }}">
<div class="custom-control custom-switch">
{% if switchcheck == 0 %}
<input type="checkbox" name="switch" onclick=this.form.submit() value="1" class="custom-control-input" id="customSwitch1">
{% else %}
<input type="checkbox" name="switch" onclick=this.form.submit() value="0" class="custom-control-input" id="customSwitch1" checked>
{% endif %}
<label class="custom-control-label" for="customSwitch1">Active</label>
</div>
</form>
{% for row in rows %}
...
So it seems like the value of switch does not get POSTed because switches are handled as checkboxes and when they are not checked they dont submit value. therefore submit.form(switch) doesnt see data.
I found my hint here: How to utilize Bootstrap Ti Ta Toggle Checkbox with Flask
Also there is mentioned to use hidden form with name=switch to handle this problem but was no success for me. My workaround looks as follows:
try:
switchvalue = request.form['vrswitch']
except:
switchvalue = 0
I bet there are more elegant ways to do this but it works!

How can I generate buttons or fields (forms) in Flask according to a list of strings?

Well, suppose we have a list of strings (objects with a toString() method respectively) and a jinja2 template that shall have selection forms (buttons or something alike) that agree in number and label to the list. This list may alter during the session. So far, I tried to work with submit buttons and radio buttons. Problems are: submit buttons vary in size because of different string length and I dislike that radio buttons force the user to first make a choice and then submit it.
The jinja2 markup looks like this:
<form method = 'post' action= "{{ url_for('add_dialogue_turn') }}">
{% if questions %}
{% for q in questions %}
<input type="radio" name="question" value={{q}}> {{q}} <br>
{% endfor %}
{% endif %}
<input type="submit" /><br /><br />
</form>
The flask function looks like this:
#app.route("/turn", methods=['POST'])
def add_dialogue_turn():
label = request.form["question"]
print(label)
return render_template("sometemplate.html", questions=aListOfQuestions, answers = aListOfAnswers)
Can I make the radio buttons submit the value directly after ticking off the circle? Or can I define some field that returns the string when clicking on it?
Thank you for your help in advance!
This is a Front end problem. You would need either JavaScript to submit your form when a button/radio is ticked. And it also depends on how you submit your form but if you want just the data to be passed into the server without page reloading, I'd suggest Ajax. And if you just want to pass the input value into the server, you do not have to use post.
A simple example would be,
-HTML
<input type="radio" name="question" value={{q}} id="{{something_unique_for_each_iterable}}" onclick="submitFunction(this)">
-JavaScript
function submitFunction(event){
id_of_radio_ticked = '#' + event.id;
$.ajax({
url: "{{url_for('to_your_flask_view_function')}}",
type: 'GET',
data: {'radio_value':$(id_of_radio_ticked).val()},
success: function(resp){
alert('do something with returned data')
}
});
}
I found another solution within the jinja template:
<nav>
<ul>
<div class="sideMenuL">
<form method = 'post' action= "{{ url_for('add_dialogue_turn') }}">
{% if questions %}
{% for q in questions %}
{% autoescape false %}
<input type="submit" name="question" value="{{q}}"><br>
{% endautoescape %}
{% endfor %}
{% endif %}
</form>
</div>
</ul>
</nav>

Display form input with Django

So basically I want to make a simple form I can enter text and the after I hit submit, see the text.
Here is my forms.py:
class Search(forms.Form):
search = forms.CharField()
Here is my views.py:
def search(request):
context = RequestContext(request)
if request.method == 'POST':
search = Search(data=request.POST)
if search.is_valid():
ticker = search.save()
ticker.save()
success = True
else:
print search.errors
else:
search = Search()
return render_to_response('ui/search.html', {"search":search}, context)
Here is the html form that you use to type in (I'm using bootstrap for styling purposes):
<form class="navbar-form navbar-right" role="search" action="/search/" method="post" name="tick">
{% csrf_token %}
<div class="form-group">
<input type="text" class="form-control" placeholder="Enter stock symbol">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
And finally, I want the text entered in the form to be displayed on "search.html" which looks like this currently:
{% extends 'ui/base.html' %}
{% block title %} search {% endblock %}
{% block body_block %}
<br>
<p>test</p>
{{ form.search.data }} <!--I'm pretty sure this is not correct -->
{% endblock %}
Anyone know how I can do this? Thanks.
Your form name is search.
To render the value with modern django, you need to call the value method of the field, therefore your template should look like the following:
{{ search.search.value }}
Your template is wrong, as you suspect.
It is looking for a context variable named "form", but you have given it a context dictionary with a key named "search".
Also, "data" is the argument that you use to build up your Search object (correctly), but when you want to extract the user's input from it, you should use the field names instead, and you need to call value() on them in order to get the bound value. So, to get the contents of the text field called search, you should use search.search.value.
Try changing the line
{{ form.search.data }}
to
{{ search.search.value }}

Submitting multiple forms in Django

I'm not sure if i'm going about this completely the wrong way, but in my html template i have a for loop that i want to present multiple forms, and one submit button to submit the data from all forms:
{% for i in Attribute_list %}
<form action="/Project/create/" method=post>{% csrf_token %}
{{ i }}:
<input type=text name={{ i }}><br>
<hr>
{% endfor %}
<input type=submit>
The problem with this is it only submits the last form.
The other problem i'm running into is getting the data back from the view. Since i'm naming the form the variable "i", i don't know how to "get" this data in my views.py:
def create_config(request):
if request.method == 'POST':
data_list = []
for data in request.POST.getlist():
data_list.append(data)
can You check this?
<form action="/Project/create/" method="post">
{% csrf_token %}
{% for i in Attribute_list %}
{{ i }}: <input type="text" name="{{ i }}"><br>
<hr>
{% endfor %}
<input type="submit">
</form>
As I understand without JS regardless how many forms You create only one POST request will be made.
In oyur example HTML is not valid so It can behave different ways in different browsers. But as soon as You have not closed form last one should be submitted.
As for second part
def create_config(request):
if request.method == 'POST':
data_list = []
for data in request.POST.getlist():
data_list.append(data)
I think You should use your Attribute_list. Or You can just iterate over all `POST' variables obtained.
def create_config(request):
if request.method == 'POST':
data_list = []
for key in request.POST:
data_list.append(request.POST[key]) # or .extend(request.POST.getlist(key)

Using Django templates to set default values

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.

Categories