if request.method == "POST":
user = None
users = User.query.all()
for x in users:
if x.email == request.form["email"] and check_password_hash(x.password, request.form["password"]):
user = x
if not user:
return render_template("login.html",err = "Invalid Credentials")
else:
login_user(user)
return redirect(url_for("home"))
else:
if current_user.is_authenticated:
return redirect(url_for("home"))
I'm always finding myself setting a variable = None then later checking if the variable is still None like the example above. I feel like there are way better ways to write this but I can't think of any. Any help is appreciated
CodePudding user response:
Instead of querying the database for all users and then looping through all the results in your application, let the database do the work.
Here's how I'd rewrite your code snippet (I'm guessing you're using Flask-SQLAlchemy):
if request.method == "POST":
user = User.query.filter_by(email=request.form["email"]).first()
if not user or not check_password_hash(user.password, request.form["password"]):
return render_template("login.html", err="Invalid Credentials")
login_user(user)
return redirect(url_for("home"))
if current_user.is_authenticated:
return redirect(url_for("home"))
Some things to note:
- simplify your flow control and avoid unnecessary nesting
- in your code, you're looping through all users in the database, even after you've found the user in question. Make sure to use
break
andcontinue
statements to avoid unnecessary work - avoid manually implementing logic for tasks that databases are built for (e.g. querying and filtering data)
CodePudding user response:
You could use a try/except
and catch a NameError
.
try:
login_user(user)
return redirect(url_for("home"))
except NameError:
render_template("login.html",err = "Invalid Credentials")
This does not require you to define user=None
, and makes more sense in terms of readability, assuming you expect to get a user more often than not. I am a little confused by your code, however, because you are iterating through a list but only assigning one variable. Why not put all of the code in the loop under the if
statement? I am sure you have a reason to not do that, but it is not clear from your code.
CodePudding user response:
I find the code in the question is good enough and the logic is clear.
That said, below is an example using list comprehension to show another approach. Note that there won't be efficiency gain. It is a matter of preference and style.
if request.method == "POST":
def _validated(x):
return (x.email == request.form["email"] and
check_password_hash(x.password, request.form["password"])
users = [x for x in User.query.all() if _validated(x)]
if len(users) == 0:
return render_template("login.html",err = "Invalid Credentials")
else:
login_user(users[0])
return redirect(url_for("home"))
else:
if current_user.is_authenticated:
return redirect(url_for("home"))