问题
I have a simple Flask web app showing a table that I read from a TSV file (using Pandas). For each row, I'm showing the index, some text, a label (positive/negative) a date, and a "change label" button.
I want to be able to change the label in the TSV file for the specific text for which I clicked the "change label" button. I was thinking of using a URL like /edit/<index>
so I can use the index passed in the URL to find the corresponding row in the TSV and change it, but without luck.
For instance, when I click the button "change label" in the first row of the table, the url would be /edit/0
Here's what I have.
Python Flask app
@app.route('/admin', methods=['GET', 'POST'])
def admin():
if request.method == 'GET':
return render_template('admin.html')
if request.method == 'POST':
if request.form['submit'] == 'Manage':
from_date = '01-01-1900'
to_date = '01-01-2900'
df = pd.read_csv('dataset.tsv', sep='\t', encoding='utf-8')
indexes = df.index.values.tolist()
texts = df['text'].values.tolist()
labels = df['label'].values.tolist()
dates = df['date'].values.tolist()
data = zip(indexes, texts, labels, dates)
return render_template('admin.html', from_date=from_date, to_date=to_date, data=data)
@app.route('/edit/<id>', methods=['GET', 'POST'])
def edit():
if request.method == 'GET':
return render_template('admin.html')
if request.method == 'POST':
# TODO, open TSV file and change label
return render_template('admin.html')
admin.html
<!doctype html>
<head>
<link rel="stylesheet" media="screen" href ="static/bootstrap.min.css">
<link rel="stylesheet" href="static/bootstrap-theme.min.css">
<meta name="viewport" content = "width=device-width, initial-scale=1.0">
</head>
<div class="container">
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Text</th>
<th scope="col">Label</th>
<th scope="col">Date</th>
<th scope="col">Edit</th>
</tr>
</thead>
<tbody>
{% for index, text, label, date in data %}
<tr>
<th>{{ index }}</th>
<th>{{ text }}</th>
<th>{{ label }}</th>
<th>{{ date }}</th>
<th>
<form action="/edit/{{ index }}" method="post" role="form">
<input type="submit" name="submit" value="Change Label" class="btn btn-info">
</form>
</th>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</html>
I know the problem has to do with the <form action="/edit/{{ index }}" method="post" role="form">
in the admin.html
, because it fails to pass the index in the URL. When I click any button it just redirects me to /edit/
without any index. Is it possible somehow to pass the variable {{ index }}
in the URL or should this be done differently?
回答1:
Why don't you utilize hidden form inputs? In your form, add the hidden input element:
{% for index, text, label, date in data %}
<tr>
<th>{{ index }}</th>
<th>{{ text }}</th>
<th>{{ label }}</th>
<th>{{ date }}</th>
<th>
<form action="/edit" method="post" role="form">
<input type="hidden" id="index" name="index" value="{{ index }}">
<input type="submit" name="submit" value="Change Label" class="btn btn-info">
</form>
</th>
</tr>
{% endfor %}
Then in your route:
@app.route('/edit', methods=['GET', 'POST'])
def edit():
if request.method == 'GET':
return render_template('admin.html')
if request.method == 'POST':
index = int(request.form['index'])
# Now use `index` to change your TSV
return render_template('admin.html')
回答2:
For this kind of task I would suggest you to use url_for.
I would consider it the preferred way because it will allow you to build meaningful and always working URLs, without necessarily relying to a user form.
This will be of great help if you decide to make an API, for example or if your users decide to share bookmarks in order to quickly achieve specific functions in your webapp.
Here's a relevant example from the documentation (check URL Building if you want to read more):
from flask import Flask, url_for
app = Flask(__name__)
@app.route('/')
def index():
return 'index'
@app.route('/login')
def login():
return 'login'
@app.route('/user/<username>')
def profile(username):
return '{}\'s profile'.format(username)
with app.test_request_context():
print(url_for('index'))
print(url_for('login'))
print(url_for('login', next='/'))
print(url_for('profile', username='John Doe'))
Here's also an example of how to write the template from a small app I wrote (it has basic CRUD functionality so you might find it useful):
<div data-role="content">
<h3 class="center">Edit restaurant</h3>
<label for="textinput-hide" class="ui-hidden-accessible">Text Input:</label>
<form id="new-restaurant-form" action="{{url_for('edit_restaurant', restaurant_id=restaurant.id)}}" method="POST" target="_parent">
<input type="text" name="restaurant-name" id="textinput-hide" placeholder="{{restaurant.name}}" value="">
<fieldset class="ui-grid-a">
<div class="ui-block-a"><a href="#" data-role="button" data-rel="back" data-theme="c">Cancel</a></div>
<div class="ui-block-b"><button type="submit" data-role="button" data-transition="flow" data-theme="b"
id="btn-add-new-ok">Ok</button></div>
</fieldset>
</form>
</div>
来源:https://stackoverflow.com/questions/51514488/python-flask-pass-jinja-variable-to-backend