# 介绍 `SQLAlchemy`是一个数据库的`ORM`框架,让我们操作数据库的时候不要再用`SQL`语句了,跟直接操作模型一样。安装命令为:`pip install SQLAlchemy`。 # 连接数据库 前面的学习我们已经掌握了如何在本地部署mysql服务了,现在将mysql启动之后,创建测试的数据库 - 点击`start.bat` 启动mysql数据库 ![image-20241219144614007](./01.SQLAlchemy/image-20241219144614007.png) - 点击`connect.bat` 连接到数据库中 ![image-20241219144653494](./01.SQLAlchemy/image-20241219144653494.png) - 输入如下命令创建数据库 ```sql create database login; show databases; ``` ![image-20241219144732276](./01.SQLAlchemy/image-20241219144732276.png) - 执行下面的代码 ```python from flask import Flask from flask_sqlalchemy import SQLAlchemy from sqlalchemy import text app = Flask(__name__) HOSTNAME = 'localhost' # 数据库地址 PORT = 3306 # 数据库端口号 USERNAME = "root" # 数据库用户名 PASSWORD = "usbw" # 数据库密码 DATABASE = "login" # 数据库名 app.config['SQLALCHEMY_DATABASE_URI'] = f'mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}/{DATABASE}?charset=utf8' # 配置flask连接数据库的配置 db = SQLAlchemy(app) # 连接数据库,并且拿到连接的接口 with app.app_context(): rs = db.session.execute(text('select 1')) # 执行一个测试的sql语句 print(rs.fetchone()) # 输出测试结果 ``` # 创建表 - 在`flask_sqlalchemy` 中,一个表就对应一个类,所以想要创建对应的表,就要先把类创建好 - 在类中,我们可以定义这个表中应该有哪些数据 ```python class User(db.Model): # 这个类是对应了user这个表 __tablename__ = 'user' # 设置表的选项,包括字符集为utf8 __table_args__ = { 'mysql_charset': 'utf8', 'mysql_collate': 'utf8_general_ci' } # 设置表名 id = db.Column(db.Integer, primary_key=True, autoincrement=True) # 第一列数据,列名为id,后面对应的参数是(整数类型,主键,自动增长) username = db.Column(db.String(100), unique=True, nullable=False) # username列,长度为100的字符串,唯一,不能为空 password = db.Column(db.String(100), nullable=False) # password列,长度为100的字符串,不能为空 with app.app_context(): # 如果想要在主程序中调用数据库,就要启动上下文管理 db.create_all() # 创建对应的表,不用担心反复创建,sqlalchemy会自动处理好幂等性 ``` - 代码运行后,可以查看数据库中已经存在对应的表,并且按照要求创建好 ```sql use login show tables; explain user; ``` ![image-20241219145706987](./01.SQLAlchemy/image-20241219145706987.png) # 插入数据 - 创建一个网页,当我们访问这个页面的时候就插入多个用户 ```python @app.route("/user/add") def user_add(): user1 = User(username="user01", password="123456") # 实例化一个用户对象 user2 = User(username="user02", password="123456") user3 = User(username="user03", password="123456") db.session.add(user1) # 实例化一个用户对象,将这个对象加到db接口中 db.session.add(user2) db.session.add(user3) db.session.commit() # 提交更改的内容 return "用户创建成功!" app.run(debug=True, host="0.0.0.0", port=8000) ``` - 访问此页面 ![image-20241219150537129](./01.SQLAlchemy/image-20241219150537129.png) - 从命令行里面查看,确认数据都已经创建 ```sql mysql> select * from user; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | user01 | 123456 | | 2 | user02 | 123456 | | 3 | user03 | 123456 | +----+----------+----------+ 3 rows in set (0.00 sec) ``` # 查询数据 - 单独写一个页面用于用户数据的查询 ```python @app.route("/user/fetch") def user_fetch(): user = User.query.filter(and_(User.username == "user01", User.password == "123456")).all() # 获取用户对象,查询用户名和密码是否正确 if len(user) == 0: # 如果查询到的结果是0,说明没有用户名和密码是对的 return "用户名或密码不正确" else: return f"欢迎用户{user[0].username}登录成功!" ``` - 访问测试 ![image-20241219152029971](./01.SQLAlchemy/image-20241219152029971.png) # 登录功能实现 ## 登录页面 - 创建模板的文件夹`templates`,并且将前面的登录注册页面放进去 ![image-20241219152938127](./01.SQLAlchemy/image-20241219152938127.png) - 编写python代码,将登录页渲染到模版中 ```python from flask import Flask, render_template app = Flask(__name__) @app.route("/") def index(): return render_template("login.html") app.run(debug=True, host="0.0.0.0", port=8000) ``` - 访问效果如下 ![image-20241219153544582](./01.SQLAlchemy/image-20241219153544582.png) ## 后端业务逻辑 - 修改前端源码,将注册按钮跳转地址改为`/register` ![image-20241219153752702](./01.SQLAlchemy/image-20241219153752702.png) - 修改python代码 - 增加允许的提交方法是`POST` - 接受用户名和密码,并且拉入数据库进行比对 - 返回登录结果 ```python from flask import Flask, render_template, request from flask_sqlalchemy import SQLAlchemy from sqlalchemy import text, and_ app = Flask(__name__) HOSTNAME = 'localhost' # 数据库地址 PORT = 3306 # 数据库端口号 USERNAME = "root" # 数据库用户名 PASSWORD = "123456" # 数据库密码 DATABASE = "login" # 数据库名 app.config['SQLALCHEMY_DATABASE_URI'] = f'mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}/{DATABASE}?charset=utf8' # 配置flask连接数据库的配置 db = SQLAlchemy(app) class User(db.Model): # 这个类是对应了user这个表 __tablename__ = 'user' # 设置表的选项,包括字符集为utf8 __table_args__ = { 'mysql_charset': 'utf8', 'mysql_collate': 'utf8_general_ci' } # 设置表名 id = db.Column(db.Integer, primary_key=True, autoincrement=True) # 第一列数据,列名为id,后面对应的参数是(整数类型,主键,自动增长) username = db.Column(db.String(100), unique=True, nullable=False) # username列,长度为100的字符串,唯一,不能为空 password = db.Column(db.String(100), nullable=False) # password列,长度为100的字符串,不能为空 with app.app_context(): # 如果想要在主程序中调用数据库,就要启动上下文管理 db.create_all() # 创建对应的表 @app.route("/", methods=['GET', 'POST']) def index(): if request.method == 'POST': # 如果是post请求,说明是提交过来的请求 username = request.form.get('username') password = request.form.get('password') user = User.query.filter(and_(User.username == username, User.password == password)).all() # 获取用户对象,查询用户名和密码是否正确 if len(user) == 0: # 如果查询到的结果是0,说明没有用户名和密码是对的 return "用户名或密码不正确" else: return f"欢迎用户{user[0].username}登录成功!" return render_template("login.html") app.run(debug=True, host="0.0.0.0", port=8000) ``` - 在页面中测试登录成功或失败 # 注册功能实现 ## 注册页面 - 编写python代码,将注册页渲染到模版中 ```python @app.route("/register", methods=['GET', 'POST']) def register(): return render_template("register.html") ``` - 访问效果如下 ![image-20241219154701791](./01.SQLAlchemy/image-20241219154701791.png) ## 后端业务逻辑 - 修改`register.html`中的跳转代码。点击登录,可以正确的跳转到登录页面 ![image-20241219154828636](./01.SQLAlchemy/image-20241219154828636.png) - 修改python代码 - 获取前端输入的用户名和两次输入的密码 - 如果用户名已存在就直接显示用户名已存在 - 用户名不存在,但是两次密码不一样,就直接显示两次密码不一致 - 如果用户名不存在,且密码符合要求,就将用户名和密码加入数据库中,直接显示注册成功 ```python from flask import Flask, render_template, request from flask_sqlalchemy import SQLAlchemy from sqlalchemy import text, and_ app = Flask(__name__) HOSTNAME = 'localhost' # 数据库地址 PORT = 3306 # 数据库端口号 USERNAME = "root" # 数据库用户名 PASSWORD = "123456" # 数据库密码 DATABASE = "login" # 数据库名 app.config['SQLALCHEMY_DATABASE_URI'] = f'mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}/{DATABASE}?charset=utf8' # 配置flask连接数据库的配置 db = SQLAlchemy(app) class User(db.Model): # 这个类是对应了user这个表 __tablename__ = 'user' # 设置表的选项,包括字符集为utf8 __table_args__ = { 'mysql_charset': 'utf8', 'mysql_collate': 'utf8_general_ci' } # 设置表名 id = db.Column(db.Integer, primary_key=True, autoincrement=True) # 第一列数据,列名为id,后面对应的参数是(整数类型,主键,自动增长) username = db.Column(db.String(100), unique=True, nullable=False) # username列,长度为100的字符串,唯一,不能为空 password = db.Column(db.String(100), nullable=False) # password列,长度为100的字符串,不能为空 with app.app_context(): # 如果想要在主程序中调用数据库,就要启动上下文管理 db.create_all() # 创建对应的表 @app.route("/user/add") def user_add(): user1 = User(username="user01", password="123456") # 实例化一个用户对象 user2 = User(username="user02", password="123456") user3 = User(username="user03", password="123456") db.session.add(user1) # 实例化一个用户对象,将这个对象加到db接口中 db.session.add(user2) db.session.add(user3) db.session.commit() # 提交更改的内容 return "用户创建成功!" @app.route("/", methods=['GET', 'POST']) def index(): if request.method == 'POST': # 如果是post请求,说明是提交过来的请求 username = request.form.get('username') password = request.form.get('password') user = User.query.filter(and_(User.username == username, User.password == password)).all() # 获取用户对象,查询用户名和密码是否正确 if len(user) == 0: # 如果查询到的结果是0,说明没有用户名和密码是对的 return "用户名或密码不正确" else: return f"欢迎用户{user[0].username}登录成功!" return render_template("login.html") @app.route("/register", methods=['GET', 'POST']) def register(): if request.method == 'POST': username = request.form.get('username') password = request.form.get('password') confirm_password = request.form.get('confirmPassword') user = User.query.filter_by(username=username).all() # 判断用户名是否存在 if len(user) > 0: print(user) return "用户名已存在" if password != confirm_password: # 判断两次密码是否一致 return "两次密码不一致" temp_user = User(username=username, password=password) db.session.add(temp_user) db.session.commit() # 将用户名和密码加入数据库 return "注册成功" return render_template("register.html") app.run(debug=True, host="0.0.0.0", port=8000) ``` - 最后测试一下是否能够正常的注册与登录 ![image-20241219164014985](./01.SQLAlchemy/image-20241219164014985.png)