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

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

一、实战场景

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

二、主要知识点

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

涉及的知识点和细节很多,我下面就直接贴出注册部分的核心代码。

三、核心代码

马上安排!

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

'''
Description: 创建应用程序,并注册相关蓝图
Python学习群 279199867 加群免费领取软件工具、视频教程、电子书、源码、课件,视频相关源码、福利文件赠送,学习问题交流共同进步!

'''
 
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

 

3、蓝图初始化

from flask import Blueprint
 
auth_bp = Blueprint(
    'auth',
    __name__,
)
 
from app.auth.user import user, auth

 

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; 2017–2022</p>
  </form>
</main>

 

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)

 

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))

 

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)

 

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('昵称已存在')

 

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、注册和验证

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

2、注册成功登录

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

3、登录

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

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

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:【Python】Flask + MySQL 实现用户注册,登录和登出 - Python技术站

(0)
上一篇 2023年4月2日 下午5:21
下一篇 2023年4月2日

相关文章

  • Python:如何只用十几行代码写一个程序?

    Python可以做的事情真的太多了,常见的网站开发,软件开发,爬虫,数据分析,人工智能,机器学习,量化投资,自动化办公,自动化运维,游戏开发,脚本制作,树莓派等等等等~ 今天咱们就来试试用Python做一个简单的程序,只需要十几行代码即可,灰常简单~     知识点 PyQt6 sys   代码展示 #引入类 # 更多好玩的代码 都放在这个群啦 279199…

    2023年4月2日
    00
  • 连连看有点费脑力,于是我直接用Python写了个自动过关脚本!太爽了!

    最近女朋友在玩连连看,玩了一个星期了还没通关,真的是菜。 我实在是看不过去了,直接用python写了个脚本代码,一分钟一把游戏。 快是快,就是联网玩容易被骂,嘿嘿~ 直接上代码 模块导入 import cv2 import numpy as np import win32api import win32gui import win32con from PIL…

    Python开发 2023年4月2日
    00
  • 重温Python基础——操作列表

    哈喽兄弟们,今天咱们来复习一下Python基础中的列表操作,不知道各位还记得多少呢? 遍历整个列表加粗样式 遍历列表的所有元素,对每一个元素进行相同的操作,是我们常常所需要的。在python中可使用for()循环。 假如我们需要将一个列表中的手机品牌一一打印,我们可以分别获取手机品牌的名字。如果数据特别的,对我们的操作要求量很大,而且容易输入错误,但使用fo…

    Python开发 2023年4月2日
    00
  • Python爬取安居客房源信息,轻松获取优质房源!

    又到了所谓的金山银四就业季,那找工作的小伙伴宿舍住不惯的话,就会去租房子住,当然也不一定有宿舍,那么自己找房子的话,肯定是不知道哪哪好。 所以今天教大家用Python来采集本地房源数据,帮助大家筛选好房。 本文涉及知识点 爬虫基本流程 requests 发送请求 parsel 解析数据 csv 保存数据 开发环境 Python 3.8 Pycharm   本…

    Python开发 2023年3月31日
    00
  • 下班在家没事干?教大家用Python做一个任何视频都能看的软件, 当然,只能看正经的!

    这不,国庆假期结束了,又得开始上班下班之旅了~ 有没有被疫情堵着出不来的呢?     话说回来,放这么久的假,大家还记得Python吗? 这不是怕大家又不能出去旅游,回家了或者在宿舍没事干太无聊,所以特地给大家献上如何用Python来开发一款看视频不需要VIP的软件~ 如果想发给朋友用的话,咱们在打包成exe可执行软件,这样小伙伴也能一起用了~ 效果展示 我…

    2023年4月2日
    00
  • 用Python写一个自动下载B站视频、弹幕、评论的软件

    哈喽兄弟们,今天来实现一个Python采集视频、弹幕、评论与一体的小软件。 平常咱们都是直接代码运行,不过今天我们做成软件,这样的话,咱们不仅能自己用,还能分享给小伙伴,女朋友一起使用。 内容有点多,拿好小本本,做好笔记,发车了~ 效果展示 我们先来看看效果,全部代码文末获取。 整体界面 我随便找个视频下载一下 弹幕和评论我都顺便下载了 有一说一,确实方便,…

    Python开发 2023年4月2日
    00
  • 文件太乱了?不要慌,教你用Python全自动整理

    文件太乱了?不要慌,教你用Python全自动整理到对应分类中~ 主要知识点 文件读写 基础语法 字符串处理 循环遍历 素材 先来看看我这乱七八糟的文件​ 这就看起来乱七八糟了,这要是手动整理,还好,哈哈~ 但是几百个上千个文件呢? 所以,还得是有个技能傍身才方便啊! 马上安排! 代码展示 # 我还给大家准备了海量资料:Python视频教程、100本Pytho…

    Python开发 2023年4月2日
    00
  • 为了防止这个公众号被封,我连夜用Python爬取了它所有图片~

    哈喽兄弟们,今天来试试批量获取公众号文章,emmm…     虽然名义上是文章,单其实它是一篇纯图片文,至于为什么不是文字,小姐姐不比文字香?     事前准备     我们需要用到 Fiddler Everywhere 这个软件,Crack是本次要使用到的文件,以及要安装微信PC版客户端,我专门录了一个安装 及使用的教程。 本次使用的是Python3.8 …

    2023年4月2日
    00
合作推广
合作推广
分享本页
返回顶部