400 lines
12 KiB
Markdown
400 lines
12 KiB
Markdown
# 介绍
|
||
|
||
`SQLAlchemy`是一个数据库的`ORM`框架,让我们操作数据库的时候不要再用`SQL`语句了,跟直接操作模型一样。安装命令为:`pip install SQLAlchemy`。
|
||
|
||
# 连接数据库
|
||
|
||
前面的学习我们已经掌握了如何在本地部署mysql服务了,现在将mysql启动之后,创建测试的数据库
|
||
|
||
- 点击`start.bat` 启动mysql数据库
|
||
|
||

|
||
|
||
- 点击`connect.bat` 连接到数据库中
|
||
|
||

|
||
|
||
- 输入如下命令创建数据库
|
||
|
||
```sql
|
||
create database login;
|
||
show databases;
|
||
```
|
||
|
||

|
||
|
||
- 执行下面的代码
|
||
|
||
```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;
|
||
```
|
||
|
||

|
||
|
||
# 插入数据
|
||
|
||
- 创建一个网页,当我们访问这个页面的时候就插入多个用户
|
||
|
||
```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)
|
||
```
|
||
|
||
- 访问此页面
|
||
|
||

|
||
|
||
- 从命令行里面查看,确认数据都已经创建
|
||
|
||
```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}登录成功!"
|
||
```
|
||
|
||
- 访问测试
|
||
|
||

|
||
|
||
# 登录功能实现
|
||
|
||
## 登录页面
|
||
|
||
- 创建模板的文件夹`templates`,并且将前面的登录注册页面放进去
|
||
|
||

|
||
|
||
- 编写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)
|
||
```
|
||
|
||
- 访问效果如下
|
||
|
||

|
||
|
||
## 后端业务逻辑
|
||
|
||
- 修改前端源码,将注册按钮跳转地址改为`/register`
|
||
|
||

|
||
|
||
- 修改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")
|
||
```
|
||
|
||
- 访问效果如下
|
||
|
||

|
||
|
||
## 后端业务逻辑
|
||
|
||
- 修改`register.html`中的跳转代码。点击登录,可以正确的跳转到登录页面
|
||
|
||

|
||
|
||
- 修改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)
|
||
```
|
||
|
||
- 最后测试一下是否能够正常的注册与登录
|
||
|
||

|
||
|