Math Noob
Math Noob

Reputation: 85

Multiple forms in a single page using flask and WTForms in which one form link to another

This is what it looks like now:

Form one

Form two

This is what I need

(words in bold are the part that works)

My code:

main function

@app.route("/searchArea", methods=['GET', 'POST'])
@login_required
def searchArea():
  if current_user.is_authenticated and verifyIdentity(current_user.username)==True:
    form1 = FindArea()
    form2 = SelectUser()
    if form1.submit1.data and form1.validate(): 
      allMatch = User.query.filter_by(area=form1.area1.data).all()
      
      if(allMatch == []):
        flash('area code does not exist', 'danger')
        return redirect(url_for('searchArea'))
      if form2.submit2.data and form2.validate(): #######
        user_select = int(form2.area.data)
        if(user_select>0 or user_select<=len(allMatch)):
          user= allMatch[user_select-1]
          author_name = user.username
          posts = Post.query.filter_by(author=author_name).all()
          emty_list = []
          while(len(posts)!= emty_list):
            db.session.delete(posts[0])
          db.session.delete(user)
          db.session.commit()
          return redirect(url_for('home'))
          flash('change have been made successfully', 'success')
          #return redirect(url_for('deleteUser',user=allMatch[user_select]))
        else:
          return redirect(url_for('searchArea'))
          flash('check your entry', 'danger')#######
      return render_template('print_area.html', title='Account',users=allMatch,form=form2)
    return render_template('searchArea.html', title='Account',form=form1)

forms.py

class FindArea(FlaskForm):
  area1=TextAreaField('Area Code', validators=[DataRequired()])
  submit1 = SubmitField('Search')
class SelectUser(FlaskForm):
  area2=TextAreaField('user number', validators=[DataRequired()])
  submit2 = SubmitField('confirm')

template(searchArea.html)

{% extends "layout.html"%} {% block content %}
<div>
    <form method="POST" action="" enctype="multipart/form-data">
        {{ form.hidden_tag() }}


        <div class="form-group">
            {{ form.area1.label(class="form-control-label") }} {% if form.area1.errors %} {{ form.area1(class="form-control form-control-lg
            is-invalid") }}
            <div class="invalid-feedback">
                {% for error in form.area1.errors %}
                <span>{{ error }}</span>
                            {% endfor %}
                        </div>
                    {% else %}
                        {{ form.area1(class="form-control form-control-lg") }}
                    {% endif %}
                </div>
          
        
          {{ form.submit1(class="btn btn-outline-info") }}
      </form>
  </div>
{% endblock content %}

template(print_area.html)

{% extends "layout.html"%} {% block content %}
<div>
    <form method="POST" action="" enctype="multipart/form-data">
        {{ form.hidden_tag() }}


        <div class="form-group">
            {{ form.area.label(class="form-control-label") }} {% if form.area.errors %} {{ form.area(class="form-control form-control-lg
            is-invalid") }}
            <div class="invalid-feedback">
                {% for error in form.area.errors %}
                <span>{{ error }}</span>
                            {% endfor %}
                        </div>
                    {% else %}
                        {{ form.area(class="form-control form-control-lg") }}
                    {% endif %}
                </div>
          
        
          {{ form.submit(class="btn btn-outline-info") }}
      </form>
  </div>
{% endblock content %}

Any help would be awsome! Thanks!

Upvotes: 0

Views: 1225

Answers (2)

Math Noob
Math Noob

Reputation: 85

Okay so this is what I learn from this lesson. form.validate() and return render is a very tricky thing when it came to coding it run from top to bottm twice, first time when you enter the page it does not validate but render, second time it velidate; you can really do nothing to it except just add an variable to check if first form has been submitted, and return render for first when irst form has not been submitted and else return render for second. Here are my fixes of my code:

main function

@app.route("/searchArea", methods=['GET', 'POST'])
@login_required
def searchArea():
  global allMatch
  form1Passer = False
  
  if current_user.is_authenticated and verifyIdentity(current_user.username)==True:
    
    form1 = FindArea()
    form2 = SelectUser()
    
    if form1.submit1.data and form1.validate() and form1Passer == False: # notice the order 
      
      form1Passer == True
      
      allMatch = User.query.filter_by(area=form1.area1.data).all()
      
      if(allMatch == []):
        flash('area code does not exist', 'danger')
        return redirect(url_for('searchArea'))
      return render_template('print_area.html', title='Account',users=allMatch,form=form2)
    
    if form2.submit2.data and form2.validate(): # notice the order
      
      user_select = int(form2.area2.data)
      if(user_select>0 and user_select<=len(allMatch)):
        print("0")
        user= allMatch[user_select-1]
        print("1")
        
        print("2")
        posts = Post.query.filter_by(author=user).all()
        print(type(posts))
        while(True):
          try:
            db.session.delete(posts[0])
          except:
            break
        db.session.delete(user)
        db.session.commit()
        return redirect(url_for('home'))
        flash('change have been made successfully', 'success')
        #return redirect(url_for('deleteUser',user=allMatch[user_select]))
      else:
        
        return redirect(url_for('searchArea'))
        flash('check your entry', 'danger')
    
    if form1Passer == False:
      
      return render_template('searchArea.html', title='Account',form=form1)
    else:
      
      return render_template('print_area.html', title='Account',users=allMatch,form=form2)

no modification need to be done. If you are having the same problem with me wish this would help you!

Edits: the code above totally works (but it's a poor practice) but when query returns a list the object in it is not linked to the object itself!

It's kinda like the adress of the supermarket! When you change the adress you pu down wouldn't take affect to the actual location of the supermarket.

And when the superMarket moves, the adress would not automatic update itself!

using the filter method and .first() could avoid any oissible future problem! Since .first() is a direct controller of the object itself

This following code would also works when you only assigned a value to an object (ex: post_target.prperty = value) while the above will not(# is the line I modified):

allMatch=[] #
user; #

@app.route("/searchArea", methods=['GET', 'POST'])
@login_required
def searchArea():
  global allMatch
  global user
  form1Passer = False
  form2Passer = False
  
  if current_user.is_authenticated and verifyIdentity(current_user.username)==True:
    
    form1 = FindArea()
    form2 = SelectUser()
    form3 = ConfirmForm()
    
    if form1.submit1.data and form1.validate() and form1Passer == False: # notice the order 
      
      form1Passer == True
      if(form1.area1.data == "0"):
        flash('this is an illegal move', 'danger')
        return redirect(url_for('searchArea'))
      allMatch = User.query.filter_by(area=form1.area1.data).all()
      
      if(allMatch == []):
        flash('area code does not exist', 'danger')
        return redirect(url_for('searchArea'))
      
      return render_template('print_area.html', title='Account',users=allMatch,form=form2)
    
    if form2.submit2.data and form2.validate() and form2Passer == False: # notice the order
      
      user_select = int(form2.area2.data)
      if(user_select>0 and user_select<=len(allMatch)):
        
        user= allMatch[user_select-1]
        return render_template('confirm.html', title='Account',user=user,form=form3)
      else:
        flash('check your entry', 'danger')
        return redirect(url_for('searchArea'))
    
    if form3.submit_cancel.data and form3.validate():
        return redirect(url_for('searchArea'))
    if form3.submit_confirm.data and form3.validate():
        user_target = User.query.filter_by(email = user.email).first()#
        while(True):
          try:
            post_target = Post.query.filter_by(author=user_target).first()#
            db.session.delete(post_target)#
            db.session.commit()
          except:
            break
        db.session.delete(user_target)#
        db.session.commit()
        flash('change have been made successfully', 'success')
        return redirect(url_for('home'))
        
        #return redirect(url_for('deleteUser',user=allMatch[user_select]))
      
    
    if form1Passer == False:
      
      return render_template('searchArea.html', title='Account',form=form1)
    elif form2Passer == False:
      
      return render_template('print_area.html', title='Account',users=allMatch,form=form2)
    else:
      return render_template('confirm.html', title='Account',user=user,form=form3)
  elif current_user.is_authenticated:
    abort(403)
  else:
    return redirect(url_for('home'))

Upvotes: 0

weijiang1994
weijiang1994

Reputation: 331

When you click the submit button of form2, this condition(if form1.submit1.data and form1.validate():) is False.Maybe you need to change the code logic.

Upvotes: 1

Related Questions