Store post data for use after authenticating with Flask-Login
Clash Royale CLAN TAG#URR8PPP
Store post data for use after authenticating with Flask-Login
Each article page has a form for logged in users to add a comment. I want users to be able to comment even if they haven't logged in yet. They should be redirected to the login page, and then the comment should be added. However, when Flask-Login's login_required
redirects back to the page, it is not a POST request, and the form data is not preserved. Is there a way to preserve the POST data after logging in and redirecting?
login_required
@articles.route('/articles/<article_id>/', methods=['GET', 'POST'])
def article_get(article_id):
form = CommentForm(article_id=article_id)
if request.method == 'POST':
if form.validate_on_submit():
if current_user.is_authenticated():
return _create_comment(form, article_id)
else:
return app.login_manager.unauthorized()
r = requests.get('%s/articles/%s/' % (app.config['BASE'], article_id))
article = r.json()['article']
comments = r.json()['comments']
article['time_created'] = datetime.strptime(article['time_created'], '%a, %d %b %Y %H:%M:%S %Z')
for comment in comments:
comment['time_created'] = datetime.strptime(comment['time_created'], '%a, %d %b %Y %H:%M:%S %Z')
return render_template('articles/article_item.html', article=article, comments=comments, form=form)
def _create_comment(form, article_id):
headers = 'Content-type': 'application/json', 'Accept': 'text/plain'
data = 'body': form.body.data, 'article_id': article_id, 'user_id': current_user.id
r = requests.post('%s/articles/comment/' % app.config['BASE'], data=json.dumps(data), headers=headers)
return redirect(url_for('.article_get', article_id=article_id, _anchor='comment-set'))
1 Answer
1
Since users have to be logged in to post, it would make more sense to just show a "click here to log in" link instead of the form if the user is not logged in.
If you really want to do this, you can store any form data in the session when redirecting to the login route, then check for this stored data once you're back in the comment route. Store the requested path as well, so that the data will only be restored if you go back to the same page. To store the data you'll need to create your own login_required
decorator.
login_required
request.form.to_dict(flat=False)
will dump the MultiDict
data to a dict of lists. This can be stored in the session
.
request.form.to_dict(flat=False)
MultiDict
session
from functools import wraps
from flask import current_app, request, session, redirect, render_template
from flask_login import current_user
from werkzeug.datastructures import MultiDict
def login_required_save_post(f):
@wraps(f)
def decorated(*args, **kwargs):
if current_app.login_manager._login_disabled or current_user.is_authenticated:
# auth disabled or already logged in
return f(*args, **kwargs)
# store data before handling login
session['form_data'] = request.form.to_dict(flat=False)
session['form_path'] = request.path
return current_app.login_manager.unauthorized()
return decorated
@app.route('/article/<int:id>', methods=['GET', 'POST'])
@login_required_save_post
def article_detail(id):
article = Article.query.get_or_404(id)
if session.pop('form_path', None) == request.path:
# create form with stored data
form = CommentForm(MultiDict(session.pop('form_data')))
else:
# create form normally
form = CommentForm()
# can't validate_on_submit, since this might be on a redirect
# so just validate no matter what
if form.validate():
# add comment to article
return redirect(request.path)
return render_template('article_detail.html', article=article)
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.