I have a form that I am using for post the data
<form enctype="multipart/form-data" method="post" action="">
<div class="form-group">
<label>Application Name <span class="mandatory">*</span></label>
<input type="text" class="form-control" name="app_name" id="appname" required maxlength="40">
<button>submit</button>
</div>
</form>
In flask i am fetching the form data and trying to do post method
if request.method == "POST":
application_data = request.form.to_dict()
postedata = post(application_data )
if posteddata:
print("sucessfully posted")
else:
print("unsucessful")
return render_template("application/addapplication.html", data=application_data)
but what I want is when else part executes that means post data doesnot happens i want to retain the values in the form. but, since here page will reload the form data is disapperaring. please can anyone help me in this?
<input type="text" value="{{ request.form.get('app_name','')}}" class="form-control" name="app_name" id="appname" required maxlength="40">
For Select tag, Let's take the data from the Flask flask_option = 'batman'.
<select>
<option {% if flask_option == "superman"%} selected {% endif %} value="superman">Clark</option>
<option {% if flask_option == "batman"%} selected {% endif %} value="batman">Bruce</option>
<option {% if flask_option == "wonderwomen"%} selected {% endif %} value="wonderwomen">Diana</option>
<option {% if flask_option == "aquaman"%} selected {% endif %} value="aquaman">Arthur</option>
</select>
If you are using API for the select options,
let's take the API response like this,
{'response': [
{'value': 'superman', 'inner_text': 'Clark'},
{'value': 'batman', 'inner_text': 'Bruce'},
{'value': 'aquaman', 'inner_text': 'Arthur'},
{'value': 'wonderwomen', 'inner_text': 'Diana'}
]}
You can iterate over the API to generate the select tag,
<select>
{% for value, text in varible_name.response %}
<option {% if flask_option == value %} selected {% endif %} value = '{{value}}'> {{text}} </option>
{% endfor %}
</select>
For textarea, you can use
<textarea>{{reqest.form.get("txt")}}</textarea>
or javascript
$('textarea').text('{{reqest.form.get("txt")}}')
I have a Flask template that displays a page with a dropdown list of owners, a table with the owner's win-loss record, and a radio to toggle between regular season record and playoff record.
The desired workflow is:
If navigated to the page through the navigation bar, it should default to /matchup-history/regular. (this works)
Else it should route accordingly whenever the radio is toggled. (this doesn't work)
matchup-history.html
{%- extends "base.html" -%}
{% block nav_matchups %}active{% endblock %}
{%- block content -%}
<form action="{{ url_for('show_matchup_history', matchup_type=request.form['matchup_type']) }}" method="post">
<label>
<select name="owner_id" onchange="this.form.submit()">
{%- for o in owners %}
{%- if request.form['owner_id'] == o['owner_id']|string() %}
<option value="{{ o['owner_id'] }}" selected>{{o['first_name'] + " " + o['last_name'] }}</option>
{%- else %}
<option value="{{ o['owner_id'] }}">{{o['first_name'] + " " + o['last_name'] }}</option>
{%- endif %}
{%- endfor %}
</select>
</label>
{% block matchup_type_radio %}{% endblock %}
</form>
{%- if records|length > 0 %}
<div class="stats-table">
<table>
<tr>
{%- for th in table_headers %}
<th>{{ th }}</th>
{%- endfor %}
</tr>
{%- for r in records %}
<tr>
{%- for cn in column_names %}
<td>{{ r[cn] }}</td>
{%- endfor %}
</tr>
{%- endfor %}
</table>
</div>
{%- endif %}
{% endblock -%}
matchup-history/regular.html
{%- extends "matchup-history.html" -%}
{% block matchup_type_radio %}
<label><input type="radio" name="matchup_type" value="regular" onclick="this.form.submit()" checked>Regular Season</label>
<label><input type="radio" name="matchup_type" value="playoffs" onclick="this.form.submit()">Playoffs</label>
{% endblock %}
matchup-history/playoffs.html
{%- extends "matchup-history.html" -%}
{% block matchup_type_radio %}
<label><input type="radio" name="matchup_type" value="regular" onclick="this.form.submit()">Regular Season</label>
<label><input type="radio" name="matchup_type" value="playoffs" onclick="this.form.submit()" checked>Playoffs</label>
{% endblock %}
app.py
#app.route('/matchup-history/<string:matchup_type>', methods=['GET', 'POST'])
def show_matchup_history(matchup_type):
table_headers = ["Opponent", "Wins", "Losses"]
column_names = ["opponent_owner_name", "wins", "losses"]
owners = queries.get_owners()
if request.method == 'POST':
owner_id = request.form['owner_id']
else:
owner_id = owners[0]['owner_id']
if matchup_type == REGULAR_SEASON:
records = queries.get_matchup_history_regular(owner_id)
else:
records = queries.get_matchup_history_playoffs(owner_id)
return render_template("matchup-history/{matchup_type}.html".format(matchup_type=matchup_type),
title='Matchup History', table_headers=table_headers, column_names=column_names,
owners=owners, records=records)
The page correctly loads /matchup-history/regular when clicked on, but fails whenever the radio button is toggled:
127.0.0.1 - - [20/Sep/2018 08:32:53] "GET /matchup-history/regular HTTP/1.1" 200 -
127.0.0.1 - - [20/Sep/2018 08:32:56] "POST /matchup-history/ HTTP/1.1" 404 -
It seems like request.form['matchup_type'] is empty when matchup-history.html is rendered, so submitting the form will not have the desired effect. How can I refactor to route url_for to different matchup_type?
Edit: Per #Joost's suggestion, I rethought the design.
matchup-history.html
{%- extends "base.html" -%}
{% block nav_matchups %}active{% endblock %}
{%- block content -%}
<form action="{{ url_for('show_matchup_history') }}" method="get">
<label>
<select name="owner_id" onchange="this.form.submit()">
{%- for o in owners %}
<option value="{{ o['owner_id'] }}" {%- if o['owner_id'] == selected_owner %} selected {% endif %}>{{o['first_name'] + " " + o['last_name'] }}</option>
{%- endfor %}
</select>
</label>
<label><input type="radio" name="matchup_type" value="regular" onclick="this.form.submit()" {%- if matchup_type == "regular" %} checked {% endif %}>Regular Season</label>
<label><input type="radio" name="matchup_type" value="playoffs" onclick="this.form.submit()"{%- if matchup_type == "playoffs" %} checked {% endif %}>Playoffs</label>
</form>
{%- if records|length > 0 %}
<div class="stats-table">
<table>
<tr>
{%- for th in table_headers %}
<th>{{ th }}</th>
{%- endfor %}
</tr>
{%- for r in records %}
<tr>
{%- for cn in column_names %}
<td>{{ r[cn] }}</td>
{%- endfor %}
</tr>
{%- endfor %}
</table>
</div>
{%- endif %}
{% endblock -%}
base.html
...
Matchups
...
app.py
#app.route('/matchup-history', methods=['GET'])
def show_matchup_history():
table_headers = ["Opponent", "Wins", "Losses"]
column_names = ["opponent_owner_name", "wins", "losses"]
matchup_type = request.args.get('matchup_type', default="regular")
owner_id = request.args.get('owner_id', type=int)
owners = queries.get_owners()
if not owner_id:
owner_id = owners[0]['owner_id']
if matchup_type == REGULAR_SEASON:
records = queries.get_matchup_history_regular(owner_id)
else:
records = queries.get_matchup_history_playoffs(owner_id)
return render_template("matchup-history.html".format(matchup_type=matchup_type),
title='Matchup History', table_headers=table_headers, column_names=column_names,
matchup_type=matchup_type, selected_owner=owner_id, owners=owners, records=records)
Flow is now:
Clicking on Matchups from navbar will route to /matchup-history and default to showing regular season matchups
Clicking on Playoffs radio will route to /matchup-history?matchup_type=playoffs&owner_id=12345
Clicking on Regular radio will route to /matchup-history?matchup_type=regular&owner_id=12345
Clicking on a different owner in the dropdown will route to /matchup-history?matchup_type=regular&owner_id=98765
So right now you are trying to access the request.form in a get request. However, the form will always be empty in a get request because that's the nature of a get request. So only when you access the route #app.route('/matchup-history/<string:matchup_type>' trough a post request, will it be able to redirect in the right way.
This working miniapp displays it nicely:
from flask import Flask, render_template_string, request
app = Flask(__name__)
TEMPLATE_STRING = """
<form action="{{ url_for('index') }}" method="post">
{{request.form['matchup_type']}}<br><br>
<label><input type="radio" name="matchup_type" value="regular" onclick="this.form.submit()" checked>Regular Season</label>
<label><input type="radio" name="matchup_type" value="playoffs" onclick="this.form.submit()">Playoffs</label>
</form>
"""
#app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'GET':
return render_template_string(TEMPLATE_STRING)
else:
return render_template_string(TEMPLATE_STRING)
The first time you open the page, you see only the radio button. But as soon as you click on a radio button, it POSTS the form, and therefore you will see the selected value on top of the page now. If you click again, you post the form again, etc.
So how should you solve it? I think that there is no need to do a POST request with this form, because you're not updating any data, you're just querying.
from flask import Flask, render_template_string, request
app = Flask(__name__)
TEMPLATE_STRING = """
<form action="{{ url_for('history') }}" method="get">
<select name="owner_id">
{% for owner in owners %}
<option {% if owner['id'] == selected_owner_id %} selected {% endif %}value="{{owner['id']}}">{{owner['name']}}</option>
{% endfor %}
</select>
<label><input type="radio" name="matchup_type" value="regular" {%if selected_matchup_type == 'regular'%}checked{%endif%} onclick="this.form.submit()">Regular Season</label>
<label><input type="radio" name="matchup_type" value="playoffs" {%if selected_matchup_type == 'playoffs'%}checked{%endif%} onclick="this.form.submit()" >Playoffs</label>
<br>Queried data goes here
</form>
"""
owners = [{'id': 1, 'name': 'bob'}, {'id': 2, 'name': 'gary'}, {'id': 3, 'name': 'tom'}]
matchup_types = 'regular', 'playoffs'
#app.route('/history', methods=['GET'])
def history():
owner_id = request.args.get('owner_id', None, type=int)
if owner_id not in [owner['id'] for owner in owners]:
owner_id = owners[0]['id']
matchup_type = request.args.get('matchup_type', None)
if matchup_type not in matchup_types:
matchup_type = matchup_types[0]
# now you know the owner_id and the matchup type, and know that both are valid, do some query to get table data
return render_template_string(TEMPLATE_STRING, owners=owners,
selected_owner_id=owner_id,
selected_matchup_type=matchup_type,
matchup_types=matchup_types)
I think this is what you need. The form is never posted, by always put as a get request (<form action="{{ url_for('history') }}" method="get">). If the values are missing or invalid, we default back to some owner/matchup_type. The checked values are remembered, and used to render the template.
This puts all you flask logic in the #app.route, and all your jinja logic in the template.
Some general remarks:
I think that accessing the request in jinja not preferable because jinja deals with errors/missing values differently, and if they are a result of logic related to your request, it's becomes hard to guess what's going on. So deal with the incoming request on the python side.
Instead of wrapping having 2 radio blocks depending on the chosen value, just use one block and check within the options if the are to one you need. <option {% if some_value == some_other_value %} checked {% endif%}>blabla</option>.
Do a lot more input validation! In your first example, you template name is decided by some user inputted value (the matchup type). But what if the user posts a nonexisting value? You get errors.
If the only difference between the two templates is which radio button is selected, you don't need two templates. See the updated version how to just deal with it in one template.
I am currently trying to compare the product id to the id given in the URL. But the if statement in the template always returns "else" even though testing provides both to be equal.
views.py (where data is given)
def editstatus(request, product_id):
try:
request.session['user_id']
except KeyError:
return redirect("/login")
products = Product.objects.all()
context = {
"product":products,
"theid" : product_id,
}
return render(request, 'posystem/status.html', context)
status.html (with not working if statement)
{%for product in product%}
<tbody>
<tr>
<td>{{product.id}}</td>
<td>{{theid}}</td>
<td>{{product.product_description}}</td>
<td>{{product.product_number}}</td>
<td>{{product.product_quantity}}</td>
<td>{{product.unit_cost}}</td>
<td>{{product.final_cost}}</td>
<td>{{product.status}}</td>
{% ifequal product.id theid %}
<h1>hello</h1>
{% else %}
<h1>hello2</h1>
{% endifequal %}
{% if theid %}
{% if product.id == theid %}
<td><select>
<option value="5 Votes Needed">5 Votes Needed</option>
<option value="Ready to Order">Ready to Order</option>
<option value="Needs to Be Signed">Needs to Be Signed</option>
<option value="Ordered">Ordered</option>
<option value="Recieved">Recieved</option>
</select></td>
<td><form class="" action="/changestatus/{{product.id}}" method="post">
{% csrf_token %}
<button type="submit" name="edit">Save</button>
</form></td>
{% endif %}
{% else %}
<td><form class="" action="/status/{{product.id}}" method="post">
{% csrf_token %}
<button type="submit" name="edit">Edit</button>
</form></td>
{% endif %}
</tr>
</tbody>
{% endfor %}
I am confused on why it will neither work with a ifequal tag nor a normal if tag.
Since product_id is from the URL then it will be a string, not an integer. You need to convert it to an integer.
context = {
"product":products,
"theid" : int(product_id),
}
In Python, and the Django template language, '1' is not equal to 1.
I want to use Jinja variables to generate n options in a drop down. Here is an example:
Session Select: <br>
{{ sessions }}
<select style="color:black">
{% for session in sessions %}
<li>{{ session }}</li>
{% endfor %}
</select> <br><br>
The value of sessions is:
['Session 1', 'Session 2', 'Session 3']
Any thoughts?
Assuming no_sessions is your n value... I would try something like this:
Session Select: <br>
<select style="color:black">
{% range number from 1 to no_sessions %}
<option>Session {{ number }}</option>
{% endrange %}
</select> <br><br>
(related to this question)
To generate items within a select box you use the <option> tag, not <li>.
Session Select: <br>
<select style="color:black">
{% for session in sessions %}
<option value="{{ session }}">{{ session }}</option>
{% endfor %}
</select> <br><br>
I am trying to create a drop down list box with the selected value equal to a value passed from the template values, but with no success. Can anyone take a look and show me what I am doing wrong.
<select name="movie">
{% for movie in movies %}
{% ifequal movie.id selected_movie.id %}
<option value="{{movie.key}}" selected="true">Movie {{movie.id}}: {{movie.name}}</option>
{% endifequal %}
{% ifnotequal movie.id selected_movie.id %}
<option value="{{movie.key}}">Movie {{movie.id}}: {{movie.name}}</option>
{% endifnotequal %}
{% endfor %}
</select>
In this example, movies and selected_movie are passed from the template values.
Please advice!
Your code works for me with django 1.0.2 and firefox 3.5.
You can use {% else %} instead of {% ifnotequal %} and set selected="selected". Hope it helps.
<select name="movie">
{% for movie in movies %}
{% ifequal movie.id selected_movie.id %}
<option value="{{movie.key}}" selected="selected">Movie {{movie.id}}: {{movie.name}}</option>
{% else %}
<option value="{{movie.key}}">Movie {{movie.id}}: {{movie.name}}</option>
{% endifequal %}
{% endfor %}
</select>