• Python Flask Web:博客登录和注册页面实现代码


    1. 项目预览

    1.1 登录

    在这里插入图片描述

    1.2 注册

    在这里插入图片描述

    2. 项目目录结构

    在这里插入图片描述

    3. 项目代码展示

    blueprint

    init.py

    from .user import bp as user_bp
    
    • 1

    forms.py

    import wtforms
    from wtforms.validators import length, email, EqualTo
    from models import EmailCaptchaModel, UserModel
    
    
    class LoginForm(wtforms.Form):
        email = wtforms.StringField(validators=[email()])
        password = wtforms.StringField(validators=[length(min=6, max=20)])
    
    
    class RegisterForm(wtforms.Form):
        username = wtforms.StringField(validators=[length(min=3, max=20)])
        email = wtforms.StringField(validators=[email()])
        captcha = wtforms.StringField(validators=[length(min=4, max=4)])
        password = wtforms.StringField(validators=[length(min=6, max=20)])
        password_confirm = wtforms.StringField(validators=[EqualTo("password")])
    
        def validate_captcha(self, field):
            captcha = field.data
            email = self.email.data
            captcha_model = EmailCaptchaModel.query.filter_by(email=email).first()
    
            if captcha_model.captcha.lower() != captcha.lower():
                raise wtforms.ValidationError("邮箱验证码错误!")
    
        def validate_email(self, field):
            email = field.data
            user_model = UserModel.query.filter_by(email=email).first()
            if user_model:
                raise wtforms.ValidationError("邮箱已经存在!")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    user.py

    from flask import Blueprint, render_template, request, redirect, url_for, jsonify, session, flash
    from exts import mail, db
    from flask_mail import Message
    from models import EmailCaptchaModel, UserModel
    from datetime import datetime
    from .forms import RegisterForm, LoginForm
    from werkzeug.security import generate_password_hash, check_password_hash
    import random
    import string
    
    bp = Blueprint("user", __name__)
    
    
    @bp.route("/")
    def index():
        return render_template("index.html")
    
    
    @bp.route("/login", methods=['GET', 'POST'])
    def login():
        if request.method == 'GET':
            return render_template("login.html")
        else:
            form = LoginForm(request.form)
            if form.validate():
                email = form.email.data
                password = form.password.data
                user = UserModel.query.filter_by(email=email).first()
                if user and check_password_hash(user.password, password):
                    session['user_id'] = user.id
                    return redirect("/")
                else:
                    flash("邮箱和密码不匹配!!!")
                    return redirect(url_for("user.login"))
            else:
                flash("邮箱或密码错误!!!")
                return redirect(url_for("user.login"))
    
    
    @bp.route("/register", methods=['GET', 'POST'])
    def register():
        if request.method == 'GET':
            return render_template("register.html")
        else:
            form = RegisterForm(request.form)
            if form.validate():
                email = form.email.data
                username = form.username.data
                password = form.password.data
    
                # md5
                hash_password = generate_password_hash(password)
                user = UserModel(email=email, username=username, password=hash_password)
                db.session.add(user)
                db.session.commit()
                return redirect(url_for("user.login"))
            else:
                return redirect(url_for("user.register"))
    
    
    @bp.route("/logout")
    def logout():
        session.clear()
        return redirect(url_for('user.login'))
    
    
    @bp.route("/captcha", methods=['POST'])
    def get_captcha():
        # GET,POST
        email = request.form.get("email")
        letters = string.ascii_letters + string.digits
        captcha = "".join(random.sample(letters, 4))
        if email:
            message = Message(
                subject='【验证码】',
                recipients=[email],
                body=f"【验证码】您的注册验证码是{captcha},请不要告诉任何人哦!"
            )
            mail.send(message)
            captcha_model = EmailCaptchaModel.query.filter_by(email=email).first()
            if captcha_model:
                captcha_model.captcha = captcha
                captcha_model.create_time = datetime.now()
                db.session.commit()
            else:
                captcha_model = EmailCaptchaModel(email=email, captcha=captcha)
                db.session.add(captcha_model)
                db.session.commit()
            print("captcha:", captcha)
            return jsonify({"code": 200})
        else:
            return jsonify({"code": 400, "message": "请先传递邮箱!"})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92

    static

    bootstrap@4.6.min.css

    点击下载css代码

    jquery.3.6.min.js

    点击下载jquery代码

    register.js

    function bindCaptchaBtnClick(){
        $("#captcha-btn").on("click",function (event){
            var $this = $(this);
            var email = $("input[name='email']").val()
            if(!email){
                alert("请先输入邮箱");
                return;
            }
            $.ajax({
                url: "/user/captcha",
                method: "POST",
                data: {
                    "email": email
                },
                success: function (res){
                    var code = res['code'];
                    if (code == 200){
                        $this.off("click")
                        var countDown = 60;
                        var timer = setInterval(function (){
                            countDown -= 1;
                            if (countDown > 0){
                                $this.text(countDown+"秒后重新发送");
                            }else {
                                $this.text("获取验证码");
                                bindCaptchaBtnClick();
                                clearInterval(timer);
                            }
                        },1000)
                        alert("验证码发送成功!");
    
                    }else{
                        alert(res['message']);
                    }
                }
            })
        });
    }
    $(function (){
        bindCaptchaBtnClick();
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    templates

    base.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>{% block title %}{% endblock %}</title>
        <link rel="stylesheet" href="{{ url_for('static',filename='bootstrap/bootstrap@4.6.min.css') }}">
        <link rel="stylesheet" href="{{ url_for('static',filename='css/css.css') }}">
        {% block head %}{% endblock %}
    </head>
    <body>
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
        <div class="container">
            <a class="navbar-brand" href="/">
                <svg t="1659145665644" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6166" width="50" height="50"><path d="M512 512m-405.333333 0a405.333333 405.333333 0 1 0 810.666666 0 405.333333 405.333333 0 1 0-810.666666 0Z" fill="#4CAF50" p-id="6167"></path><path d="M640 426.666667c47.061333 0 85.333333 38.272 85.333333 85.333333s-38.272 85.333333-85.333333 85.333333-85.333333-38.272-85.333333-85.333333 38.272-85.333333 85.333333-85.333333m0-85.333334a170.666667 170.666667 0 1 0 0 341.333334 170.666667 170.666667 0 0 0 0-341.333334z" fill="#FFFFFF" p-id="6168"></path><path d="M384 426.666667c47.061333 0 85.333333 38.272 85.333333 85.333333s-38.272 85.333333-85.333333 85.333333-85.333333-38.272-85.333333-85.333333 38.272-85.333333 85.333333-85.333333m0-85.333334a170.666667 170.666667 0 1 0 0 341.333334 170.666667 170.666667 0 0 0 0-341.333334z" fill="#FFFFFF" p-id="6169"></path></svg>
            </a>
            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
                    aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
    
            <div class="collapse navbar-collapse" id="navbarSupportedContent">
                <ul class="navbar-nav mr-auto">
                    <li class="nav-item active">
                        <a class="nav-link" href="/">首页 <span class="sr-only">(current)</span></a>
                    </li>
                </ul>
                <ul class="navbar-nav">
                    {% if user %}
                        <li class="nav-item">
                            <span class="nav-link">{{ user.username }}</span>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link" href="{{ url_for('user.logout') }}">退出登录</a>
                        </li>
                    {% else %}
                        <li class="nav-item">
                            <a class="nav-link" href="{{ url_for('user.login') }}">登录</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link" href="{{ url_for('user.register') }}">注册</a>
                        </li>
                    {% endif %}
                </ul>
            </div>
        </div>
    </nav>
    <div class="container">{% block body %}{% endblock %}</div>
    </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    index.html

    {% extends "base.html" %}
    
    {% block title %}首页{% endblock %}
    
    {% block head %}
    
    {% endblock %}
    
    {% block body %}
    <h1>文章首页</h1>
    {% endblock %}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    login.html

    {% extends "base.html" %}
    
    {% block title %}登录{% endblock %}
    
    {% block head %}
    
    {% endblock %}
    
    {% block body %}
        <div class="row mt-4">
            <div class="col"></div>
            <div class="col">
                <form action="{{ url_for("user.login") }}" method="post">
                    <div class="form-group">
                        <label for="exampleInputEmail1">邮箱</label>
                        <input type="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" name="email">
                    </div>
                    <div class="form-group">
                        <label for="exampleInputPassword1">密码</label>
                        <input type="password" name="password" class="form-control" id="exampleInputPassword1">
                    </div>
    
                    {% for message in get_flashed_messages() %}
                        <div class="from-group">
                        <div class="text-danger">{{ message }}</div>
                        </div>
                    {% endfor %}
    
                    <div class="from-group">
                        <button type="submit" class="btn btn-primary btn-block">立即登录</button>
                    </div>
                </form>
            </div>
            <div class="col"></div>
        </div>
    {% endblock %}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    register.html

    {% extends "base.html" %}
    
    {% block title %}注册{% endblock %}
    
    {% block head %}
        <script src="{{ url_for('static',filename='jquery/jquery.3.6.min.js') }}"></script>
        <script src="{{ url_for('static',filename='js/register.js') }}"></script>
    {% endblock %}
    
    {% block body %}
        <div class="row mt-4">
            <div class="col"></div>
            <div class="col">
                <form action="{{ url_for("user.register") }}" method="post">
                    <div class="form-group">
                        <label for="exampleInputEmail1">邮箱</label>
                        <input type="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp"
                               name="email">
                        <small id="emailHelp" class="form-text text-muted">我们不会把邮箱用于其他用途</small>
                    </div>
    
                    <div class="form-group">
                        <label for="exampleInputEmail1">验证码</label>
                        <div class="input-group">
                            <input type="text" class="form-control" name="captcha">
                            <div class="input-group-append">
                                <button class="btn btn-outline-secondary" type="button" id="captcha-btn">获取验证码</button>
                            </div>
                        </div>
                    </div>
    
                    <div class="form-group">
                        <label for="exampleInputEmail1">用户名</label>
                        <input type="text" class="form-control" name="username">
                    </div>
    
                    <div class="form-group">
                        <label for="exampleInputPassword1">密码</label>
                        <input type="password" class="form-control" id="exampleInputPassword1" name="password">
                    </div>
    
                    <div class="form-group">
                        <label for="exampleInputPassword1">确认密码</label>
                        <input type="password" class="form-control" name="password_confirm">
                    </div>
    
                    <button type="submit" class="btn btn-primary btn-block">立即注册</button>
                </form>
            </div>
            <div class="col"></div>
        </div>
    {% endblock %}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    app.py

    from flask import Flask, session, g
    import config
    from exts import db, mail
    from blueprints import user_bp
    from flask_migrate import Migrate
    from models import UserModel
    
    app = Flask(__name__)
    app.config.from_object(config)
    db.init_app(app)
    mail.init_app(app)
    
    migrate = Migrate(app, db)
    
    app.register_blueprint(user_bp)
    
    
    @app.before_request
    def before_request():
        user_id = session.get("user_id")
        if user_id:
            try:
                user = UserModel.query.get(user_id)
                g.user = user
            except:
                g.user = None
    
    
    @app.context_processor
    def context_processor():
        if hasattr(g, "user"):
            return {"user": g.user}
        else:
            return {}
    
    
    if __name__ == '__main__':
        app.run()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    config.py

    
    # 数据库配置信息
    HOSTNAME = '127.0.0.1'  # 数据库地址
    PORT = '3306'  # 端口默认:3306
    DATABASE = '数据库名'
    USERNAME = '数据库账号'
    PASSWORD = '数据库密码'
    DB_URI = 'mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)
    SQLALCHEMY_DATABASE_URI = DB_URI
    
    SQLALCHEMY_TRACK_MODIFICATIONS = True
    
    SECRET_KEY = "sdasd54as56d4a65s4"
    
    
    # 邮箱配置
    MAIL_SERVER = "smtp.qq.com"
    MAIL_PORT = 465
    MAIL_USE_TLS = False
    MAIL_USE_SSL = True
    MAIL_DEBUG = True
    MAIL_USERNAME = "发件邮箱"
    MAIL_PASSWORD = "授权码"
    MAIL_DEFAULT_SENDER = "默认发件邮箱"
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    decorators.py

    from flask import g, redirect, url_for
    from functools import wraps
    
    
    def login_required(func):
        @wraps(func)
        def wrapper(*args,**kwargs):
            if hasattr(g,'user'):
                return func(*args,**kwargs)
            else:
                return redirect(url_for("user.login"))
        return wrapper
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    exts.py

    from flask_sqlalchemy import SQLAlchemy
    from flask_mail import Mail
    
    db = SQLAlchemy()
    mail = Mail()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    models.py

    from exts import db
    from datetime import datetime
    
    
    class EmailCaptchaModel(db.Model):
        __tablename__ = "email_captcha"
        id = db.Column(db.Integer, primary_key=True, autoincrement=True)
        email = db.Column(db.String(100), nullable=False, unique=True)
        captcha = db.Column(db.String(10), nullable=False)
        creat_time = db.Column(db.DateTime, default=datetime.now)
    
    
    class UserModel(db.Model):
        __tablename__ = "user"
        id = db.Column(db.Integer, primary_key=True, autoincrement=True)
        username = db.Column(db.String(200), nullable=False, unique=True)
        email = db.Column(db.String(100), nullable=False, unique=True)
        password = db.Column(db.String(200), nullable=False)
        join_time = db.Column(db.DateTime, default=datetime.now)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
  • 相关阅读:
    2024年集创赛FPGA紫光同创赛道男女声,童声变声
    一颗完整意义的LPWAN SOC无线通信芯片——ASR6601
    2022 China Collegiate Programming Contest (CCPC) Weihai Site A J
    JUC第十五讲:JUC集合-ConcurrentHashMap详解(面试的重点)
    vscode软件安装包下载安装教程
    Android 12(S) 图像显示系统 - drm_hwcomposer 简析(上)
    EFCore学习笔记(8)——关系
    【PyQt5】PythonUI设计开发技巧(持续更新中)
    机器学习笔记 - GluonCV:基于MXNet/PyTorch + Kinetics400 + 各种先进网络的动作识别的预训练模型
    Docker入门
  • 原文地址:https://blog.csdn.net/PoGeN1/article/details/126077200