Multiple Forms on 1 Page Python FLASK - python

So I am loading all users from a database on a single page and I'm generating a password reset form for each user on the same page rather than having an individual page for each user.
My question is how can I click submit and apply the change for that specific user since I have multiple forms and submit buttons for each user via drop-down menu?
In my case the submit button is the "Reset Password" button.
I'm trying to call the form normally using
if request.method == "POST" and form.validate():
password = request.form['password']
but I'm getting exception error
name 'form' is not defined
I've been trying to solve this for a while but i'm getting pretty confused now as I've got multiple forms (one per user) on the same page.
NOTE : I'm not using WTForms for this task
Thanks

I'm not sure if this one has been answered but here is what i just figured out:
After your standard
if request.method == 'POST':
you can test for the existence of each form item within the request.form data. So add another if statement after the first
if 'my_form_element_name' in request.form:
print ('stuff')
If you have other types of form data such as files, you can do something like:
if request.method == 'POST':
if 'file_element_name' in request.files:
return stuff
elif 'my_form_element_name' in request.form:
return stuff
else: return stuff
else: return stuff
I have four forms in one html file and this method worked for me.

Related

WTForm used in two different views validate only using one view

I'm having a problem using a WTForm in two different views. One view creates a new item, using the form data. The other view display information for items already in the database and the user should be able to update the form data from there.
I can create and view the items in the database. The problem is updating the information when in in the display view. The steps I take are something like:
Create a item in /create. Before saving to database check that the same ID is not already in database. If exists show a flash and do not permit saving the item. Reloading /create
To display information about a existing item the route /display/<item> call the database, populate the form and show the information using the same form.
Desired behavior
To update information when in /display/<item>. After updating any field data and pressing the submit button, the form should save to the database and reload /display/<item>.
Actual behavior
After pressing the submit button the form takes me back to the /create route, and performs the ID validation.
I don't understand why, being in a different view /display/<item>, the form's submit button takes me to the /create view.
The code goes something like this:
This is a simple form
class ItemForm(FlaskForm):
id = IntegerField("id", validators=[DataRequired()])
name = StringField("Email", validators=[DataRequired()])
submit = SubmitField("Submit")
With this I create a new item in the database, checking that the same Id is not already in the database:
#app.route("/create", methods=["GET", "POST"])
def create():
form = ItemForm()
if form.validate_on_submit():
item = item = Item.query.filter(Item.id == form.id).first()
# Check the same id is not already created
if item is not None:
flash('item already in database')
return redirect(url_for("create"))
item = Item()
form.populate_obj(item)
db.session.add(item)
db.session.commit()
return redirect(url_for("display", item = form.id))
else:
return render_template("create.html", form=form)
And then after there is created items in the database i can call a display route. In this route I should be able to update the fields in the form and save it to the database. Whit out validating as the the same ID is already present in the database (I'm updating, no creating a new one).
#app.route("/display/<item>", methods=["GET", "POST"])
def display(item):
item = Item.query.filter(Item.id == item).first()
form = ItemForm(obj=item)
if form.validate_on_submit():
form.populate_obj(item)
db.session.add(item)
db.session.commit()
return redirect(url_for("display", item=form.id))
else:
return render_template("display.html", form=form)
The problem is that when in the /display/<item> route, the submit button takes me back to the /create route. Performing the validations in there. Of course the item is already created in the database so I get the flash and I'm redirected to /create, when it should reload /display/<item>.
Could someone point me in the right direction, please. Thank you all!
My mistake, but #the_gañañufla asked the right question. The problems of coding alone.
I had added an action to the HTML and i forgot to remove it.
I had
<form id="form_item" action="{{ url_for('create') }}" class="form" method=post>
After correct it I have:
<form id="form_product" action="" class="form" method=post>

Modal forms not displaying

i am working on a project, and i created two modal forms on the landing page. both forms are for registration and login.
only one form seems to be coming up and the other cannot come up and thereby making it impossible for the forms to submit.
how do i achieve this challenge, that both forms can be displayed and can submit to the database respectively.
also i am a rookie i just started a few weeks ago
i have tried and all i keep getting are errors or only one form displays
#app.route('/main', methods=['GET', 'POST'])
def main():
form = Signup_Form()
forms = Login_Form()
if request.method =="GET":
return render_template('/main.html', form=form, forms=forms)
if request.method == "POST":
return render_template('main.html', form=form, forms=forms)
else:
return redirect('home.html')
i expect to see both forms display when clicked and also submit to the database when the submit button is clicked

How to submit multiple forms to same flask page?

I have multiple forms in a page.On submit it all should goto same page for processing.
But how will I address that?
Currently I have this:
if request.method == 'POST':
project = request.form['project_name']
But this doesn't specify from which form I am submitting data from. Is there anyway to specify form to be processed?

How to deal with errors in large formsets?

I'm just starting with formsets and I have trouble making a user friendly error system.
So the user sees a list view that shows him all instances of a model already written into a formset. This pages is meant to show him the data and edit it as well.
Before I was using a lot of individual forms with a save button for every form. But now I want to improve it to have a formset that provides a single save button for all of the forms.
But there comes my problem: Before I used to send the user via "action" to another url (e.g. .../update/ ) which processes the request and then sends him back to the list view he saw before. That's to avoid multiple submits when hitting F5.
But now if I do this and only a single form is wrong all the information the user had entered is lost.
So instead I stopped using the extra URL and made the processing part of the list view. Now I can use form.error on every form, but also the user resubmits when hitting F5.
Is there a way to have both?
Also: I have 1 extra form. But if the user changes it, and I feed the POST data into the formset, save it and then put it back to the page I lost the extra formset, because now the former extra is showing the newly entered instance and there is no true extra field left until the page is refreshed without sending post data.
Here is my View:
class BVServerListView(View):
def get(self, request):
eigene_server = Server.objects.filter(user=request.user)
EigeneServerFormset = modelformset_factory(Server, extra=1, form=ServerForm)
eigene_server_formset = EigeneServerFormset(queryset=eigene_server)
context = {'eigene_server': eigene_server_formset,}
return render(request, 'bildverteiler/server_list.html', context)
def post(self, request):
eigene_server = Server.objects.filter(user=request.user)
EigeneServerFormset = modelformset_factory(Server, extra=1, form=ServerForm)
eigene_server_formset = EigeneServerFormset(request.POST, request.FILES)
for form in eigene_server_formset.forms:
if form.data.get('delete', False):
server = Server.objects.get(user=request.user, name=form.data['name'])
server.delete()
else:
if form.has_changed() and form.is_valid():
server = form.save(commit=False)
server.user = request.user
server.save()
context = {'eigene_server': eigene_server_formset,}
return render(request, 'bildverteiler/server_list.html', context)
There is no difference between using a single form or a formset here. The answer is the same: post to the same view, but redirect after a successful save.
The other thing that you are doing wrong here is to validate and save individual forms one by one. Don't do that, because you could end up with a situation that the first forms are valid and get saved, but subsequent ones are invalid and therefore the formset needs to be redisplayed. Instead, validate the formset as a whole:
if eigene_server_formset.is_valid():
for form in eigene_server_formset.forms:
if form.cleaned_data.get('delete'):
... delete ...
else:
form.save()
return HttpResponseRedirect('somewhere_else')
return render...

How to route form errors to another view using Flask, FlaskWTF

I'm trying to create two views using Flask. The first view show_entries displays a list of entries in a table. It also includes a form to create new entries.
The form gets submitted to a second view new_entry which accepts the POST method and is responsible for adding the new entry to the table using SQLAlchemy. new_entry then redirects back to show_entries.
My problem is that form.errors are not routed to show_entries, so the user never sees them. I'm not sure of the best way to go about this, or if I'm even on the right track with the way I've divided up the views.
Here's what I currently have:
def show_entries():
entryForm = EntryForm()
entries = g.user.entries
return render_template('show_entries.html',
entries=entries,
entryForm=entryForm)
def new_entry():
form = EntryForm()
if form.validate_on_submit():
newEntry = Entry(g.user, form.time.data)
db_session.add(newEntry)
db_session.commit()
flash('New entry was succesfully posted')
return redirect(url_for('show_entries'))
The normal pattern is to have /show_entries as a listing page with new_entry as the form. When you do a GET request to new_entry you get the form, then POST to it to add the entry. That way if there's an error you can just show it next to the form - all the data is available. If you split the views as you have then you'll need some way of moving the error data (and form data) from the new_entry view to the show_entries view.
Something more like (untested):
def show_entries():
entries = g.user.entries
return render_template('show_entries.html',
entries=entries)
def new_entry():
form = EntryForm()
if form.validate_on_submit():
newEntry = Entry(g.user, form.time.data)
db_session.add(newEntry)
db_session.commit()
flash('New entry was successfully posted')
return redirect(url_for('show_entries'))
return render_template('show_new_entry_form.html',
entryForm=form)

Categories