Flask+Bootstrap实战三
书接上回,完成了用户注册的页面,下面来完成用户登录的页面
2025-03-07 21:20:34 星期五
项目教程地址:
Youtobe源地址:Bootstrap Flask
Bilibili搬运:哔哩哔哩
一.Flask制作用户登录界面
-
首先需要在app.py中修改导入
from flask_login import LoginManager,之后login = LoginManager(app)。 -
修改model.py用户模型。加入了一个user_loader回调
from flask_login import UserMixin
from app import db, login
@login.user_loader
def load_user(id):
return User.query.get(id)
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True)
email = db.Column(db.String(120), unique=True)
password = db.Column(db.String(20), unique=True)
def __repr__(self):
return '<User %r>' % self.username
- 在routes.py中新建一个login路由函数
@app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
pass
return render_template("login.html", form=form)
- 在用户注册表单中form.py中编写LoginForm类,注意这里需要先从wtforms中导入BooleanField
class LoginForm(FlaskForm):
username = StringField("Username", validators=[DataRequired(), Length(min=3, max=20)])
password = PasswordField("Password", validators=[DataRequired(), Length(min=6, max=20)])
remember = BooleanField("Remember")
submit = SubmitField("Login")
- 新建login.html模板
{% extends "base.html" %}
{% block app_content %}
<h1>Login Now</h1>
<br>
<div class="row">
<div class="col-md-6">
{% import 'bootstrap/wtf.html' as wtf %}
{{ wtf.quick_form(form) }}
</div>
</div>
{% endblock %}
- 在navbar.html中新建一login标签
最后运行截图如下
二.用户名和密码校验以及登录成功界面
- 修改routes.py文件,首先判断当前用户是不是第一次出现,另外,检查当前输入的密码是否与user查询得到的密码相匹配,如果匹配,fflash消息后重定向到successful界面,如果不匹配,则同样flash一条消息。
@app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
username = form.username.data
password = form.password.data # Use the plain password from the form
remember = form.remember.data
user = User.query.filter_by(username=username).first()
if user and bcrypt.check_password_hash(user.password, password):
# user exists and password is true
login_user(user, remember=remember)
flash("Login success", category="info")
return redirect(url_for("login_success"))
else:
flash("user not exists or password not true", category="danger")
return render_template("login.html", form=form)
这里其实有一个小问题,就是如果登录不成功,他并不会flash一条消息,就是没动静
函数的category参数用于指定消息的类别,通常用于设置消息的样式。常见的类别包括:
- success:表示成功消息,通常显示为绿色。
- info:表示信息消息,通常显示为蓝色。
- warning:表示警告消息,通常显示为黄色。
- danger:表示错误消息,通常显示为红色。
所以在这里,除了给原先的login_success做登录成功的页面跳转之外,还需要在login.html中加上falshing处理消息,并给danger,代码如下
点击查看代码
{% extends "base.html" %}
{% block app_content %}
<h1>Login Now</h1>
<br>
<div class="row">
<div class="col-md-6">
{% with messages = get_flashed_messages(with_categories=True) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ category }}">
{{ message }}
</div>
{% endfor %}
{% endif %}
{% endwith %}
{% import 'bootstrap/wtf.html' as wtf %}
{{ wtf.quick_form(form) }}
</div>
</div>
{% endblock %}
- 在routes.py中添加新的路由
@app.route('/login_success')
def login_success():
return render_template("login_success.html")
- 制作login_successful模板,这个和register.html模板一摸一样
点击查看代码
{% extends "bootstrap/base.html" %}
{% block content %}
<div class = "container">
<div class="row">
<div class="col-md-6">
{% with messages = get_flashed_messages(with_categories=True) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ category }}">
{{ message }}
</div>
{% endfor %}
{% endif %}
{% endwith %}
</div>
</div>
</div>
<script>
// Wait for 2 seconds and then redirect to the index page
setTimeout(function() {
window.location.href = "{{ url_for('index') }}";
}, 2000);
</script>
{% endblock %}
这样就可以实现密码不对或者用户名错误时有红色警告了
- 此时就可以进行登录了,但是这样就是可以重复进行登录,所以需要进行判断当前用户不让他重复登录。修改login的路由,同时修改register的路由
@app.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for("index"))
- 为了确保用户必须登录之后才能进入index页面,需要在__init__.py初始化时加上。其目的就是当用户处于未登录状态时,会在login页面提示"You must login to access this page"
login.login_view = "login"
login.login_message = "You must login to access this page"
login.login_message_category = "info"
- 最后就是为了在登录状态只显示登出按钮,在未登录状态只显示登录按钮,需要在navbar.html文件中做如下修改,三个<li>标签中间加if判断即可标签中间加if判断即可
<ul class="nav navbar-nav navbar-right">
{% if not current_user.is_authenticated %}
<li class="{% if request.endpoint == 'login' %}active{% endif %}">
<a href="{{url_for('login')}}">Login</a>
</li>
<li class="{% if request.endpoint == 'register' %}active{% endif %}">
<a href="{{url_for('register')}}">Register</a>
</li>
{% else %}
<li class="{% if request.endpoint == 'logout' %}active{% endif %}">
<a href="{{url_for('logout')}}">Logout</a>
</li>
{% endif %}
</ul>
三.添加重置密码的界面
- 首先在用户登录界面login.html做修改如下,在最下方添加如下代码,和上面的隔开
<div class="row">
<div class="col-md-6">
<hr>
Forget your password?
<a href= "{{ url_for('send_password_reset_request') }}">
Please click here to reset your password.
</a>
</div>
</div>
- 之后新建路由函数,此时可以发现我们缺少一个form,所以下一步需要在forms.py中新建一个PasswordResetForm
@app.route('/send_password_reset_request', methods=['GET', 'POST'])
def send_password_reset_request():
form = PasswordResetForm()
return render_template("send_password_reset_request.html", form=form)
- 新建一个PasswordResetForm
class PasswordResetForm(FlaskForm):
email = StringField("Email", validators=[DataRequired(), Email()])
submit = SubmitField("send")
def validate_email(self, email):
user = User.query.filter_by(email=email.data).first()
if not user:
raise ValidationError("email not exists")
- 新建一个send_password_reset_request.html,和register.html模板文件几乎一模一样,现在发现了就是form中定义了几个Field,那么他在html模板中进行渲染的时候就会自动生成几个,很方便
{% extends "base.html" %}
{% block app_content %}
<h1>Reset Now</h1>
<br>
<div class="row">
<div class="col-md-6">
{% import 'bootstrap/wtf.html' as wtf %}
{{ wtf.quick_form(form) }}
</div>
</div>
{% endblock %}
ok,这个也做完了
-
优化一些页面跳转。
-
首先第一个就是logout的时候,加一个
@login_required,来确保只有在登录状态下才能登出,但是这个并不是必要的,因为在未登录状态前面设置了navbar并不会显示logout按钮 -
在register_success.html编写跳转的时候,不再去index页面,而是直接去login页面
-
浙公网安备 33010602011771号