关键词搜索

源码搜索 ×
×

【Python】Flask + MySQL 实现用户注册,登录和登出

发布2022-07-12浏览1044次

详情内容

今天用Flask + MySQL 实现用户注册,登录和登出。

一、实战场景

Flask 框架实现用户的注册,登录和登出。

二、主要知识点

  • flask_login 插件使用
  • SQLAlchemy 基础操作
  • 用户基础类设计
  • Flask 读取配置文件
  • 蓝图注册与使用
  • wtforms 表单提交数据
  • wtforms 表单验证
  • Bootstrap 集成
  • Jinjia2 模版继承

涉及的知识点和细节很多,我下面就直接贴出注册部分的核心代码,有需要源码的小伙伴私信我哦!

三、核心代码

马上安排!

1、应用初始化 MySQL 和 flask_login 模块

'''
Description: 创建应用程序,并注册相关蓝图
'''
 
from flask import Flask
from base.base_model import db
from flask_login import LoginManager
 
# 登录插件
login_manager = LoginManager()
 
def register_auth_blueprint(app):
    # 注册蓝图
    from app.auth import auth_bp
    app.register_blueprint(auth_bp)
 
def create_app(config=None):
    # 创建应用
    app = Flask(__name__)
 
    # 加载配置
    app.config.from_object('config')
 
    # 注册 SQLAlchemy
    db.init_app(app)
    #
    # 注册 login 模块
    login_manager.init_app(app)
 
    # 未登录时候的默认跳转页面
    login_manager.login_view = 'auth.login'
    # # login_manager.login_message = '请先登录或注册'
 
    register_auth_blueprint(app)
 
    if config is not None:
        if isinstance(config, dict):
            app.config.update(config)
        elif config.endswith('.py'):
            app.config.from_pyfile(config)
 
    return app
 
app = create_app()
 
with app.app_context():
    db.create_all()
 
if __name__ == '__main__':
    # 如果要使用 vscode 调试,需要将 debug 设置为 False,否则无法命中请求断点
    app.run(host='0.0.0.0', debug=True)

    2、设置配置文件

    APP_NAME = "north"
     
    SECRET_KEY = "fNqh2TNw3l0Dj8ZCMQyQh7m1YvWVSgDx"
     
    DEBUG = True
     
    SQLALCHEMY_DATABASE_URI = 'mysql://username:password@ip:3306/dbname'
     
    # 设置sqlalchemy自动更跟踪数据库
    SQLALCHEMY_TRACK_MODIFICATIONS = True
     
    # 查询时会显示原始SQL语句
    SQLALCHEMY_ECHO = True
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    3、蓝图初始化

    from flask import Blueprint
     
    auth_bp = Blueprint(
        'auth',
        __name__,
    )
     
    from app.auth.user import user, auth
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    4、编写注册表单

    <main class="form-signin w-100 m-auto">
     <form action="{{ url_for('auth.register') }}" method="post">
        <img class="mb-4" src="{{ url_for('static', filename="3rd/images/bootstrap-logo.svg") }} " alt="" width="72" height="57">
        <h1 class="h3 mb-3 fw-normal">注册信息</h1>
     
        <div class="form-floating">
          <input class="form-control"
                 id="nickname" name="nickname"
                  value="{{ form.data['nickname'] | default('',true) }}"
                  placeholder="昵称">
          <label for="floatingInput">昵称</label>
        </div>
        <div class="form-floating">
          <input type="email" class="form-control"
                 id="email" name="email"
                  value="{{ form.data['email'] | default('',true) }}"
                  placeholder="Email">
          <label for="floatingInput">邮箱</label>
        </div>
        <div class="form-floating">
          <input type="password" class="form-control"
                  id="password" name="password"
                  value="{{ form.data['password'] | default('',true) }}"
                  placeholder="Password">
          <label for="floatingPassword">密码</label>
        </div>
        <div class="form-floating">
          <input type="password" class="form-control"
                  id="confirm_password" name="confirm_password"
                  value="{{ form.data['confirm_password'] | default('',true) }}"
                  placeholder="Confirm Password">
          <label for="floatingPassword">确认密码</label>
        </div>
            {% if form and form.errors %}
                {% for key, error in form.errors.items() %}
                    <div class="alert alert-warning" role="alert">{{ key }} : {{ error }}</div>
                {% endfor %}
            {% endif %}
     
        <button class="w-100 btn btn-lg btn-primary" type="submit">注册</button>
        <p class="mt-5 mb-3 text-muted">秀儿 &copy; 20172022</p>
      </form>
    </main>
    
    • 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

    5、提交注册表单

    @auth_bp.route("/register", methods=['POST', 'GET'])
    def register():
        # 注册逻辑
        form = RegisterForm(request.form)
     
        # 检查
        if request.method == 'POST' and form.validate():
            # 执行正确逻辑
            user = User()
            user.set_attrs(form.data)
     
            user.name = user.nickname
            user.token = user.generate_token()
     
            db.session.add(user)
            db.session.commit()
     
            # 执行登录
            login_user(user, False)
     
            return redirect(url_for('auth.home'))
     
        return render_template("auth/register.html", form=form)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    6、用户模型

    import random
     
    from sqlalchemy import Column, ForeignKey, func
    from sqlalchemy import String, Unicode, DateTime, Boolean
    from sqlalchemy import TIMESTAMP, Integer, Float
    from flask_login import login_user, login_required, logout_user, current_user, UserMixin
    from werkzeug.security import generate_password_hash, check_password_hash
     
     
    from common.helpers.str_helper import random_string
    from north import login_manager
     
    from  base.base_model import BaseModel
     
    class User(BaseModel, UserMixin):
        # UserMixin 继承属性
        __tablename__ = 'users'
     
        # 表基础值
        phone_number = Column(String(16), unique=True)
        email = Column(String(64), unique=True, nullable=False)
        token = Column(String(64))
        password = Column('password', String(100))
        status = Column(Integer, default=1)
        type = Column(Integer, default=1)
     
        # 定义一个对象属性,对应表中的 password 字段
        _password = Column('password', String(100))
     
        @property
        def password(self):
            # 定义属性,使用对象属性赋值
            return self._password
     
        @password.setter
        def password(self, raw):
            # 属性赋值
            self._password = generate_password_hash(raw)
     
        def check_password(self, raw):
            # 检查密码
            if not self._password:
                return False
            return check_password_hash(self._password, raw)
     
        def generate_token(self, expiration=60000):
            # 生成 token
            return random_string(32)
     
     
    @login_manager.user_loader
    def get_user(uid):
        # 必须, login 插件制定方法
        return User.query.get(int(uid))
    
      52
    • 53
    • 54

    7、模型基类

    import pymysql
    import datetime
     
    from flask_sqlalchemy import SQLAlchemy
    from sqlalchemy import Column, Integer, SmallInteger
    from sqlalchemy import String, Unicode, DateTime, Boolean
     
    # 初始化数据库类型
    pymysql.install_as_MySQLdb()
    db = SQLAlchemy()
     
    # 模型基础类
    class BaseModel(db.Model):
        __abstract__ = True
     
        id = Column(Integer, primary_key=True)
        name = Column(String(32), nullable=False)
        nickname = Column(String(32), nullable=False)
        is_enable = Column(SmallInteger, default=1, nullable=False)
        created_at = db.Column(db.DateTime, default=datetime.datetime.now)
        updated_at = db.Column(db.DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now)
        deleted_at = db.Column(db.DateTime)
     
        def __init__(self):
            pass
     
        # 字典赋值, 场景: 表单提交
        def set_attrs(self, attrs):
            for key, value in attrs.items():
                if hasattr(self, key) and key != 'id':
                    setattr(self, key, value)
    
    • 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

    8、表单验证

    from wtforms import StringField, PasswordField, Form, validators
    # from wtforms.validators import Length, Email, \
    #     ValidationError, EqualTo
    from app.auth.user.user_model import User
     
    class RegisterForm(Form):
        nickname = StringField('昵称',
            validators = [
                validators.DataRequired(),
                validators.Length(2, 32)
                #   validators.Email(message='电子邮箱不符合规范')
            ])
        email = StringField('电子邮件',
            validators = [
                validators.DataRequired(),
                validators.Length(10, 50)
     
                #   validators.Email(message='电子邮箱不符合规范')
            ])
        password = PasswordField('密码', [
            validators.DataRequired(),
            validators.EqualTo('confirm_password', message='密码需要一致')
        ])
        confirm_password = PasswordField('Repeat Password', [
            validators.DataRequired(),
     
        ])
     
        def validate_email(self, field):
            # 自定义验证,命名对应
            if User.query.filter_by(email=field.data).first():
                raise validators.ValidationError('邮件已被注册')
     
        def validate_nickname(self, field):
            if User.query.filter_by(nickname=field.data).first():
                raise validators.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
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    9、代码主要目录结构

    ├── app
    │   ├── __init__.py
    │   ├── auth
    │   │   ├── __init__.py
    │   │   └── user
    │   └── tools
    │       ├── __init__.py
    │       └── db_tools.py
    ├── base
    │   ├── __init__.py
    │   ├── base_blueprint.py
    │   ├── base_form.py
    │   └── base_model.py
    ├── common
    │   ├── __init__.py
    │   └── helpers
    │       ├── __init__.py
    │       └── str_helper.py
    ├── config.py 
    
    ├── north.py 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    四、运行结果

    1、注册和验证

    2、注册成功登录

    3、登录

    兄弟们,今天的分享就到这里,下次见!

    相关技术文章

    点击QQ咨询
    开通会员
    返回顶部
    ×
    微信扫码支付
    微信扫码支付
    确定支付下载
    请使用微信描二维码支付
    ×

    提示信息

    ×

    选择支付方式

    • 微信支付
    • 支付宝付款
    确定支付下载