Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flask - Use the same view to render a search form and then search results

I want to have a search form to query the database and display the results from the search below it. I don't want any confirmation warning to appear when refreshing the page. Also I want to know if this can be done with a single view function as all the tutorials I've seen use more than one. Like this one and this one.

This is working but it shows a warning that asks for confirmation when clicking the refresh button on the browser:

main.py

@app.route('/', methods=['GET', 'POST'])
@app.route('/index', methods=['GET', 'POST'])
def index():
    form = SearchForm()
    query = form.data['search']
    if query != '':
        results = Foo.query.filter(Foo.name.like('%'+query+'%')).all()
        return render_template('index.html', form=form, query=query, results=results)
    return render_template('index.html', form=form)

forms.py

from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms.validators import DataRequired

class SearchForm(FlaskForm):
    search = StringField('search', validators=[DataRequired()])

templates/index.html

{% block page_content %}
<div class="page-header">
  <form style="display: inline;" action="{{ url_for('index') }}" method="post" name="search">
    {{ form.search(size=20) }}
    <input type="submit" value="Search">
  </form>

  {% if results %}
    <h1>Search results for "{{ query }}":</h1>
    {{ results }}
  {% endif %}
</div>
{% endblock page_content %}

This is what I would like but it gives a page not redirecting properly error:

    @app.route('/', methods=['GET', 'POST'])
def index():
    form = SearchForm(request.form)
    if form.validate:
        session['query'] = form.data['search']
        return redirect(url_for('index'))

    if 'query' in session:
        results = Foo.query.filter(Foo.name.like('%'+session.get('query')+'%')).all()
        return render_template('index.html', form=form, query=session.get('query'), results=results)
    else:
        return render_template('index.html', form=form)

1 Answers

You can have a single function to render the search page and then after form.validate_on_submit() query the database and return the results. For the search results add an if statetment to display them on the same template as the search form.

@app.route('/search', methods=['GET', 'POST'])
def search():
    form = SearchForm()
    if form.validate_on_submit():
        search_term = form.query.data
        results = Foo.query.all()
        return render_template('search.html', form=form, results=results)
    return render_template('search.html', form=form)

search.html

{% block content%}
<form method="post">
    {{ form.csrf_token }}
    {{ form.query }}
    {{ form.submit }}
    {% if results %}
        {{ results }}
    {% endif %}
</form>
{% endblock %}
like image 76
simanacci Avatar answered Sep 02 '25 06:09

simanacci



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!