Submitting edited Prepopulate Flask-WTForm data from database - python

I would like to pre-populate my form with data from my database to make necessary changes and modify my database with these changes.
However when i run the following code below, when the form.validate_on_submit() method is initialised, the form's data is the pre-populated data from the database and not the edited version. How do i access the edited value of the form data?
#auth.route('/edit_projects', methods=['GET', 'POST'])
#auth.route('/edit_projects/<project>', methods=['GET', 'POST'])
#login_required
def edit_projects(project=None):
form = ProjectForm()
project_db = Project.query.all()
edit_project_db = Project.query.filter_by(id=project).first()
if project != None:
form.name.data=edit_project_db.name
form.project_brief.data=edit_project_db.project_brief
form.project_description.data=edit_project_db.project_description
if form.validate_on_submit():
edit_project_db.name = form.name.data
edit_project_db.project_brief = form.project_brief.data
edit_project_db.project_description = form.project_description.data
db.session.commit()
flash('Product %s updated.' %(str(form.name.data)))

I think it could help to distinguish between 'GET' and 'POST', on 'GET' you prepopulate the fields, but on 'POST' you want to see if the user has actually edited the form content.
I would split the code like:
if request.method == 'GET':
# prepopulate
if project != None:
form.name.data=edit_project_db.name
form.project_brief.data=edit_project_db.project_brief
elif request.method == 'POST':
# check form validates
if form.validate_on_submit():
# keep the rest as it is
...
Hope this offers some help.

Related

AttributeError: 'FileField' object has no attribute 'save' - Flask - WTForms [duplicate]

How do I get the data from a WTForms form after submitting it? I want to get the email entered in the form.
class ApplicationForm(Form):
email = StringField()
#app.route('/', methods=['GET', 'POST'])
def index():
form = ApplicationForm()
if form.validate_on_submit():
return redirect('index')
return render_template('index.html', form=form)
<form enctype="multipart/form-data" method="post">
{{ form.csrf_token }}
{{ form.email }}
<input type=submit>
</form>
Each field has a data attribute containing the processed data.
the_email = form.email.data
Working with form data is described in the getting started doc.
The most probable place for you to do things with the Form.attrs is in the index function. I have added some conditional guards on the method param. You want to do different things if they are using GET or POST as well. There are other ways to do all of this but I didn't want to change too much at once. But you should think about it clearly this way. If I have no form data because I've just made the initial request, I'm going to be using GET. Once I render the form in the template, I'm going to be sending a POST (as you can see in the top of your template). So I need those two cases dealt with firstly.
Then, once the form is rendered and returned I will have data or no data. So dealing with the data is going to happen in the POST branch of the controller.
#app.route('/index', methods=['GET', 'POST'])
def index():
errors = ''
form = ApplicationForm(request.form)
if request.method == 'POST':
if form.is_submitted():
print "Form successfully submitted"
if form.validate_on_submit():
flash('Success!')
# Here I can assume that I have data and do things with it.
# I can access each of the form elements as a data attribute on the
# Form object.
flash(form.name.data, form.email.data)
# I could also pass them onto a new route in a call.
# You probably don't want to redirect to `index` here but to a
# new view and display the results of the form filling.
# If you want to save state, say in a DB, you would probably
# do that here before moving onto a new view.
return redirect('index')
else: # You only want to print the errors since fail on validate
print(form.errors)
return render_template('index.html',
title='Application Form',
form=form)
elif request.method == 'GET':
return render_template('index.html',
title='Application Form',
form=form)
To help, I'm adding a simple example from some of my working code. You should be able to follow it given your code and my walk through.
def create_brochure():
form = CreateBrochureForm()
if request.method == 'POST':
if not form.validate():
flash('There was a problem with your submission. Check the error message below.')
return render_template('create-brochure.html', form=form)
else:
flash('Succesfully created new brochure: {0}'.format(form.name.data))
new_brochure = Brochure(form.name.data,
form.sales_tax.data,
True,
datetime.datetime.now(),
datetime.datetime.now())
db.session.add(new_brochure)
db.session.commit()
return redirect('brochures')
elif request.method == 'GET':
return render_template('create-brochure.html', form=form)

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)

Python/Flask. How can include multiple forms on a single view.py file

I am developing a python web application using the Flask framework. The application has several forms namely: The login form, the registration form, check balance form, withdraw cash form, and transfer money form. I have a single view.py file that i intend to use to render all these forms like this:
###login form
#app.route('/login', methods = ['POST'])
def login():
form = LoginForm()
if request.method == 'POST':
if form.validate() == False:
flash('pin is required.')
else:
return render_template('index.html')
elif request.method == 'GET':
return render_template('login.html', form = form)
##withdraw cash
#app.route('/withdrawCash', methods=['GET', 'POST'])
def withdrawCash():
form = withdrawCashForm()
if request.method == 'POST':...
##transfer cash
#app.route('/transferCash', methods=['GET', 'POST'])
def transferCash():
form = transferCashForm()
if request.method == 'POST':......etc
Is this possible to have one view file rendering all these forms or should i have view files for each form?
The question above has been edited. I initially thought i had gone around the problem but after reviewing the problem it is clear that whatever answer i had provided was wrong.

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.

Redirect loop while using url_for function with parameters in flask

I get a redirect loop when I try to use the redirect and url_for functions in flask as follows:
#app.route('/edit/<id>' , methods=['POST', 'GET'])
def edit (id):
#Getting user by primary key:
post = Post.query.get(id)
if request.method == 'POST':
post.title = request.form['title']
post.text = request.form['text']
db.session.commit()
flash('New entry was successfully posted')
return redirect(url_for('edit', id=id, post=post))
Update: Solved http://techarena51.com/index.php/flask-sqlalchemy-tutorial/
I presume you only want to redirect if the user submitted a POST request? I think your code should be:
#app.route('/edit/<id>' , methods=['POST', 'GET'])
def edit (id):
#Getting user by primary key:
post = Post.query.get(id)
if request.method == 'POST':
post.title = request.form['title']
post.text = request.form['text']
db.session.commit()
flash('New entry was successfully posted')
return redirect(url_for('edit', id=id, post=post))
# The rest of this code is executed when a GET is performed
return render_template("edit.html",id=id, post=post)
otherwise, yes, your current code will redirect to the same route every time it is accessed. I've updated my example to show how you need to render the edit template when the request method is not POST.

Categories