3
\$\begingroup\$

I'm trying to capture all input fields in a form (i.e. sign_up.html) & validating them - if one of them is null or empty then it should show a validation message. I've done it but I'm looking for an elegant way to do it.

sign_up.html

{% extends "layout.html" %}
{% block main %}
<form action="/sign_up.html" method="POST" autocomplete="off" name="sign_up">
 <h2>Sign Up</h2>
 <label for="username">User name:
 <input type="text" placeholder="Username" name="username" required="required" maxlength="20">
 </label>
 <br>
 <sup>* Password must be 8-12 Digit ,Numbers & letters & punctuations @, !, ,ドル ETC..</sup>
 <label for="password">Password:
 <input type="password" placeholder="password" name="password" required="required" minlength="8" maxlength="12">
 </label>
 <label for="check">Check Password:
 <input type="password" placeholder="Check Password" name="check" required="required" minlength="8" maxlength="12">
 </label>
 <br>
 <label for="security_question">Security question :
 <select name="security_question">
 <option value="where were you born?" name="q1" >where were you born?</option>
 <option value="what is your favorite nickname?" name="q2" >what is your favorite nickname?</option>
 <option value="what is the name of your first pet?" name="q3" >what is the name of your first pet?</option>
 <option value="what is the name of your first best friend?" name="q4" >what is the name of your first best friend?</option>
 </select>
 </label>
 <label for="answer">Security answer:
 <input type="text" placeholder="Answer" name="answer" required="required">
 </label>
 <br>
 <input type="submit" value="Sign Up">
</form>
{% endblock %}

this is my spaghetti validation python code:

from flask import Flask, flash, redirect, render_template, Request, request, session
from werkzeug.datastructures import ImmutableOrderedMultiDict
from werkzeug.utils import HTMLBuilder
#Something in between
class OrderedRequest(Request):
 parameter_storage_class = ImmutableOrderedMultiDict
app = Flask(__name__)
app.request_class = OrderedRequest
#Something in between
@app.route("/sign_up.html", methods=["GET", "POST"])
def sign_up():
if request.method == "POST":
 #assigning returning page
 page = "sign_up.html"
 #Null fields checking
 if not request.form.get("username"):
 return render_template("errors/general_error.html", error = "Username field is Empty", page = page)
 elif not request.form.get("password"):
 return render_template("errors/general_error.html", error = "Password field is Empty", page = page)
 elif not request.form.get("check"):
 return render_template("errors/general_error.html", error = "Check Password field is Empty", page = page)
 elif not request.form.get("answer"):
 return render_template("errors/general_error.html", error = "answer field is Empty", page = page)
#something at the end

this will return a page with the validation error massage.

I need to loop through an element gives me names of all the inputs inside the form & I'll return the error massage due to it..

& code will be like:

for i in needed_element:
 if not i:
 return render_template("errors/general_error.html", error = f"{i} field is Empty", page = page)

or something similar or any more elegant way because I'm repeating this step many times in the project :'D

200_success
145k22 gold badges190 silver badges478 bronze badges
asked Aug 11, 2021 at 21:49
\$\endgroup\$
0

2 Answers 2

2
\$\begingroup\$

Readability

Before addressing the main concern, readability should be addressed.

Many python developers adhere to PEP8 for consistent code style.

This code does not adhere to a few aspects:

Limit all lines to a maximum of 79 characters.

For flowing long blocks of text with fewer structural restrictions (docstrings or comments), the line length should be limited to 72 characters.

Don't use spaces around the = sign when used to indicate a keyword argument, or when used to indicate a default value for an unannotated function parameter:

Repeated code

As you already identified, the code to check for missing fields in order to display validation prior errors is quite redundant. This goes against the Don't Repeat Yourself principle .

One option is to abstract out the fields to check into a dictionary:

field_mapping = {'username': 'Username', 'password': 'Password',
 'check': 'Check Password', 'answer': 'Answer'}

Then the items() method can be used to iterate through the keys and values, unpacked to a tuple:

for field, label in field_mapping.items():
 if not request.form.get(field):
 return render_template("errors/general_error.html",
 error=f"{label} field is Empty", page=page)
answered Aug 12, 2021 at 5:56
\$\endgroup\$
3
  • \$\begingroup\$ many thanks for Readability instruction's. I found that too I can easily do ``` for i in request.form: if not request.form.get(i): return render_template("errors/general_error.html", error = i + " field is Empty", page=page) ``` \$\endgroup\$ Commented Aug 12, 2021 at 15:52
  • \$\begingroup\$ Ah I had considered mentioning that but figured it wouldn't allow customizing the label - e.g. check -> Check Password \$\endgroup\$ Commented Aug 12, 2021 at 16:02
  • 1
    \$\begingroup\$ that's a nice concentration, I find that too so I changed the input names to be check -> check_password then applying "check_password".replace("_"," ").capitalize() when returning values to jinja. \$\endgroup\$ Commented Aug 12, 2021 at 16:11
1
\$\begingroup\$

I found that I can iterate through form inputs by doing this..

for i in request.form:
 if not request.form.get(i):
 return render_template("errors/general_error.html", error = i + " field is Empty", page=page)

as request.form will give you a list contains all names of inputs in form.

Note: it excludes <input type="submit" value="Sign Up"> by default, because this input have no name.

answered Aug 12, 2021 at 15:59
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.