flask url function not working properly - python

I have a an html form that is sending data with POST then I redirect to the same function using GET with the form data as arguments for the function
#app.route('/search/custom/', methods=['GET', 'POST'])
def search_custom(category=None, date=None, page=None):
if request.method == 'POST':
category = request.form.get('InputCategory')
date = request.form.get('InputDate')
return redirect(url_for('search_custom', category=category, date=date, page=1))
if request.method == 'GET':
if not(category and date and page):
return redirect(url_for('home'))
flash('worked', 'success')
return redirect(url_for('register'))
function is receiving the arguments correctly yet its only redirecting to "home":
127.0.0.1 - - [10/Apr/2018 01:55:36] "GET /search/custom/?category=Vetements&date=Dernier+mois&page=1 HTTP/1.1" 302 -

category, date, and page are all None when processing a get request.
Inside of the Get handler, you'll need to actually pull the parameters from the query string.
Something like:
category = request.args.get('category')
date = request.args.get('date')
page = request.args.get('page')
should do the trick.
Put the before the check for the parameters and it should work.
I didn't have a chance to test this, so let me know if it doesn't work and I'll actually dig into it a bit more.
The way you have it now, you would probably want to have a formatted url for. Something like /search/custom/<category>/<date>/<page>. This would require changing the format of the incoming url too though, and that probably isn't what you want.
The code would look something like
#app.route('/search/custom/<category>/<date>/<page>', methods=['GET', 'POST'])
#app.route('/search/custom/', methods=['GET', 'POST'])
def search_custom(category=None, date=None, page=None):
# do stuff

Related

Why does inserting a function inside a route differ from inserting the code inside the function in Flask?

I am trying to make a web app with a login system. I want to make it so that a user can't access certain pages unless they are logged in.
What I want is that when you click to go to another page while not logged in, you get redirected to the login page and on it you get a message flash.
This is what works:
#app.route("/home", methods=['GET', 'POST'])
def home():
#some form
if not current_user.is_authenticated:
flash('You need to be logged in to access this page.', 'info')
return redirect(url_for('login'))
#rest of the code
But I would need to add all of this to other routes as well. So I created the function and added it to the routes instead:
#app.route("/home", methods=['GET', 'POST'])
def home():
#some form
require_login()
#rest of the code
def require_login():
if not current_user.is_authenticated:
flash('You need to be logged in to access this page.', 'info')
return redirect(url_for('login'))
But this does not work as I want it to. It instead redirects to the home page and then flashes the message. How do I fix this?
The problem is that the redirect(...) doesn't itself do the redirect. It returns a value to Flask telling flask that it needs to do the redirect.
In your first piece of code, you handle this correctly. You take the result of redirect(...) and return it to flask. In your second piece of code, you take the redirection returned by require_login and ignore it in home.
You might try something like:
value = require_login()
if value:
return value
You need to return the function
return require_login()
But be aware, after that u cant have code. You should create an decorator for this. There are examples online just Google "flask authorized decorator"
Your Advantage of this that u can move the auth Logic out of the Views and you can easily decorate your Views and dont have this Stuff in each View/route

Flask WTForms - Retrieve form data when submitting to a different route, i.e. a different POST route than the GET route which renders the form

I would like to set up my URLs/endpoints according to REST as closely as possible, while still utilising Flask-WTForms.
I would like my form to render at GET /posts/new, and submit to POST /post.
With Flask-WTForms I can only work out how to get it to GET/POST to the same URL.
My current code looks like this:
#post_bp.route('/posts/new', methods=['GET', 'POST'])
def show_post_form():
create_post_form = CreatePostForm()
if create_post_form.validate_on_submit():
return 'success'
return render_template('create_post_form.html', form=create_post_form)
However I would like to be able to make it look something more like this, but I just can't seem to work it out:
#post_bp.route('/posts/new', methods=['GET'])
def show_post_form():
create_post_form = CreatePostForm()
return render_template('create_post_form.html', form=create_post_form)
this route only shows the form
the form submits a POST request to /post
<form action="{{url_for('shipment.C_shipment')}}" method="POST" novalidate>
the POST /post route handles the submitted form and if there are errors for example, then it redirects back to GET /posts/new:
#post_bp.route('/post', methods=['POST'])
def create_post():
create_post_form = CreatePostForm()
if create_post_form.validate_on_submit():
return "success!"
if len(create_post_form.errors) != 0:
for error in create_shipment_form.errors:
for msg in create_shipment_form.errors[error]:
flash(msg)
return redirect(url_for('shipment.show_create_shipment_form'))
i guess creating a new CreatePostForm() object here doesn't really work..
Any suggestions?
Creating a new CreatePostForm is correct as it parses the submitted form data for you. This allows you to call validate_on_submit() on the form object.
I don't think you're generating the correct URL for the form action in your HTML snippet. The argument to url_for() should be the desired endpoint (see docs) which should be <post_bp>.create_post. This would be similar to your call
return redirect(url_for('shipment.show_create_shipment_form'))
If this does not fix the issue, please provide both frontend and backend error messages you receive when trying to send the data to /post.

How can I clear values from WTF form upon submission? [duplicate]

I want to reset the form after it validates. Currently the form will still show the previous data after it is submitted and valid. Basically, I want the form to go back to the original state with all fields clean. What is the correct to do this?
#mod.route('/', methods=['GET', 'POST'])
def home():
form = NewRegistration()
if form.validate_on_submit():
#save in db
flash(gettext(u'Thanks for the registration.'))
return render_template("users/registration.html", form=form)
The issue is that you're always rendering the form with whatever data was passed in, even if that data validated and was handled. In addition, the browser stores the state of the last request, so if you refresh the page at this point the browser will re-submit the form.
After handling a successful form request, redirect to the page to get a fresh state.
#app.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
# do stuff with valid form
# then redirect to "end" the form
return redirect(url_for('register'))
# initial get or form didn't validate
return render_template('register.html', form=form)
davidism answer is correct.
But once I had to reload a form with only a few fields that had to be resetted.
So, I did this, maybe it's not the cleanest way but it worked for me:
form = MyForm()
if form.validate_on_submit():
# save all my data...
myvar1 = form.field1.data
myvar2 = form.field2.data
# etc...
# at first GET and at every reload, this is what gets executed:
form.field1.data = "" # this is the field that must be empty at reload
form.field2.data = someobject # this is a field that must be filled with some value that I know
return render_template('mypage.html', form=form)
You can clear a form by passing formdata=None
#mod.route('/', methods=['GET', 'POST'])
def home():
form = NewRegistration()
if form.validate_on_submit():
#save in db
######### Recreate form with no data #######
form = NewRegistration(formdata=None)
flash(gettext(u'Thanks for the registration.'))
return render_template("users/registration.html", form=form)
you can also return new form object using render_template if form does not validates you can also pass message
#mod.route('/', methods=['GET', 'POST'])
def home():
form = NewRegistration()
if form.validate_on_submit():
#save in db
return render_template("user/registration.html", form = NewRegistration())
return render_template("users/registration.html", form=form)

How to give arguments to view with flask, redirect url_for

I have an application build with flask and I want to pass one input tag from my current html view ('/setpickup') to another view, in order to reuse the variable values of that input and print them again in the new view ('/payments.html'). But I dont know if it is possible, thanks you. Here is a brief of the code that is not working at this moment.
#app.route('/')
#app.route('/setpickup', methods=['GET', 'POST'])
#login_required
def setpickup():
form = RideForm()
device = Utils.getDevice()
if request.method == 'POST':
data_input_data = form.data_input.data
return redirect(url_for('payment', data_input_data=data_input_data))
#app.route('/payment')
#login_required
def payment(data_input_data):
device = Utils.getDevice()
return render_template("/"+device+"/payment.html",
device=device,
data_input_data=data_input_data)

Redirect to other view after submitting form

I have a survey form. After submitting the form, I'd like to handle saving the data then redirect to a "success" view. I'm using the following code right now, but it just stays on the current url, while I'd like to go to /success. How can I do this?
#app.route('/surveytest', methods=['GET', 'POST'])
def surveytest():
if request.method == 'GET':
return render_template('test.html', title='Survey Test', year=datetime.now().year, message='This is the survey page.')
elif request.method == 'POST':
name = request.form['name']
address = request.form['address']
phone = request.form['phone']
email = request.form['email']
company = request.form['company']
return render_template('success.html', name=name, address=address, phone = phone, email = email, company = company)
You have the right goal: it's good to redirect after handling form data. Rather than returning render_template again, use redirect instead.
from flask import redirect, url_for, survey_id
#app.route('/success/<int:result_id>')
def success(result_id):
# replace this with a query from whatever database you're using
result = get_result_from_database(result_id)
# access the result in the tempalte, for example {{ result.name }}
return render_template('success.html', result=result)
#app.route('/survey', methods=["GET", "POST"])
def survey():
if request.method == 'POST':
# replace this with an insert into whatever database you're using
result = store_result_in_database(request.args)
return redirect(url_for('success', result_id=result.id))
# don't need to test request.method == 'GET'
return render_template('survey.html')
The redirect will be handled by the user's browser, and the new page at the new url will be loaded, rather than rendering a different template at the same url.
Though I am not specifically answering your current question I found myself with a similar problem with getting the page to redirect after the submission button had been clicked. So I hope this solution could potentially work for others that find themselevs in a similar predicament.
This example uses Flask forms for handling forms and submissions.
from flast_wtf import FlaskForm
#app.route("/", methods=["GET", "POST"])
def home():
stock_form = StockForm()
tick = stock_form.text_field.data
if tick != None:
return redirect(f'/{tick}', code=302)
return render_template("home.html", template_form=stock_form, ticker=tick)
The if statement checks that the submission after being clicked has a value, then redirects to your chosen link. This code is a copy and paste from a badly programmed stock price lookup.

Categories