文章目录
Flask-SQLAIchemy项目后端-注册账户(实验项目第二期)
在做一个vue+flask+mysql前后端分离项目的时候,后端Flask-SQLAIchemy对于整个后端的架构层级遇到了很多问题
问题1:关于开发,测试,生成的问题
我的flask后端运行的时候会出现(但是程序依然可以运行):
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
翻译:
警告:这是一个开发服务器。不要在生产部署中使用它。请改用生产WSGI服务器。
后查阅资料决定暂时不管它,因为我们处于项目开发阶段,而非生产部署。
问题2:关于运行时一些小bug
1)一个最小的应用
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello, World!'
if __name__ == '__main__':
app.run()
但是会出现Restarting with stat问题
于是将app.run()改成:
if __name__ == '__main__':
app.debug = True # 开启debug
app.run(use_reloader=False) # 在run()里加入参数 use_reloader=False,就可以解决 * Restarting with stat
2)app实例的上下文问题
报错:RuntimeError: Working outside of application context.
解决方法:使用app.app_context()
(上图为网上查找方法,个人使用的push()方法)
# 创建Flask对象
app = Flask(__name__)
# 数据库配置(此处省略)
app.config['SQLALCHEMY_DATABASE_URI'] = ....
...
...
# 实例化SQLAlchemy对象db[这两行也可以写成db = SQLAlchemy(app)]
db = SQLAlchemy()
db.init_app(app)
# 防止出现RuntimeError: Working outside of application context.
app.app_context().push()
问题3:关于整个flask项目层级架构
布局问题:
这是flask文档中的项目布局:
这是我的项目布局:(只涉及到注册功能的)
Stundet_employment
--src
----model
------user.py
----service
------register.py
--templates
----register.html
--venv
--database.py
--app.py
--requirements.txt
由于主程序app.py可以import其他py文件,但是其它py文件不能import主文件,并且py文件之间相互import时需要注意是否存在circula import(循环引入)所以采用下图的import路线
可能报错问题(循环引入):
ImportError: cannot import name ‘bp1’ from partially initialized module ‘src.controller.register’ (most likely due to a circular import)
注:此处仅为我个人作出的布局路线,不代表规范性
解释:
1)database.py
database.py文件中放置的是我的数据库配置,并且生成了app和db实例
具体代码:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
# 创建Flask对象
app = Flask(__name__)
# 数据库配置:
# Flask数据库的设置: app.config['SQLALCHEMY_DATABASE_URI'] = "mysql://账号:密码@数据库ip地址:端口号/数据库名"
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:123456@127.0.0.1:3306/mysqltest'
# 动态追踪修改设置,如未设置只会提示警告, 不建议开启
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 查询时会显示原始SQL语句
app.config['SQLALCHEMY_ECHO'] = True
# 实例化对象db[这两行也可以写成db = SQLAlchemy(app)]
db = SQLAlchemy()
db.init_app(app)
def config_app():
return app
def config_db():
return db
2)user.py文件
user.py文件使用Model类创建一个数据库user表(使用database.py里的函数引入app和db)
并且将该db传给register.py文件用于生成蓝图
import database
from database import *
# 实例化对象db
# db = SQLAlchemy(app)
app = database.config_app()
db = database.config_db()
# 防止出现RuntimeError: Working outside of application context.
app.app_context().push()
class User(db.Model):
# 定义表名
__tablename__ = 'users'
# 定义列对象
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(32), unique=True, index=True)
email = db.Column(db.String(32), unique=True)
password = db.Column(db.String(32))
# repr()方法显示一个可读字符串
def __repr__(self):
return '<User: %d %s %s %s>' % (self.id, self.username, self.email, self.password)
# 创建表
db.create_all()
def user_app():
return app
def user_db():
return db
3)register.py
register.py文件用于注册一个蓝图对象,实现具体的注册功能,并让app.py(主程序)注册这个蓝图对象
此处我定义了一个名称为register_bp的蓝图,并在该蓝图中定义了一个名为register1的路由函数。在该函数中,我获取了用户提交的表单数据中的username值,然后查询数据库中是否已经存在该用户名。如果已经存在,则返回一个错误响应,提示用户该用户名已被注册。如果不存在,则可以继续进行用户注册的逻辑。
from flask import Blueprint, jsonify, request, render_template
from src.model.user import User, db
import templates
#此处创建一个名称为register_bp的蓝图
#和应用对象一样, 蓝图需要知道是在哪里定义的,因此把 __name__ 作为函数的第二个参数。第三个参数可以加 url_prefix 会添加到所有与该蓝图关联的 URL 前面。
bp1 = Blueprint('register_bp', __name__)
@bp1.route('/register',methods=['GET','POST'])
def register1():
if request.method == 'GET':
return render_template('register.html')
# 获取用户提交的表单数据
username = request.form.get('username')
# 查询数据库,查看该用户名是否已经被注册
existing_user = User.query.filter_by(username=username).first()
if existing_user:
# 如果用户名已经存在,返回一个错误信息
response = {
'status': 'error',
'message': '该用户名已经被注册,请选择其他用户名'
}
return jsonify(response), 400
# 如果用户名不存在,可以继续进行用户注册的逻辑
email = request.form.get('email')
password = request.form.get('password')
#添加数据
user = User(username = username,email = email,password = password)
try:
db.session.add(user) # 添加单个用add()
# 提交添加,可通过rollback撤回
db.session.commit()
response = {
'status':'success',
'message':'注册成功'
}
return jsonify(response),200
except Exception:
response = {
'status': 'error',
'message': '注册失败,请稍后再试'
}
return jsonify(response), 500
4)app.py(主程序)
此处需要重新创建一个Flask对象实例app,然后在用database.py的app赋值
注意:不能让app=None值,不然会报错:
AttributeError: ‘NoneType’ object has no attribute ‘app_context’
错误代码:
database.py:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
_app = None
def config_app(app):
# 数据库配置:
# Flask数据库的设置: app.config['SQLALCHEMY_DATABASE_URI'] = "mysql://账号:密码@数据库ip地址:端口号/数据库名"
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:123456@127.0.0.1:3306/mysqltest'
# 动态追踪修改设置,如未设置只会提示警告, 不建议开启
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 查询时会显示原始SQL语句
app.config['SQLALCHEMY_ECHO'] = True
global _app
_app = app
def get_app():
global _app
return _app
app.py(主程序):
# 创建Flask对象
app = Flask(__name__)
#使用函数配置数据库连接
config_app(app)
运行结果:
正确代码:
database.py:
# 创建Flask对象
app = Flask(__name__)
# 数据库配置:
# Flask数据库的设置: app.config['SQLALCHEMY_DATABASE_URI'] = "mysql://账号:密码@数据库ip地址:端口号/数据库名"
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:123456@127.0.0.1:3306/mysqltest'
# 动态追踪修改设置,如未设置只会提示警告, 不建议开启
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 查询时会显示原始SQL语句
app.config['SQLALCHEMY_ECHO'] = True
# 实例化对象db
db = SQLAlchemy()
db.init_app(app)
def config_app():
return app
def config_db():
return db
app.py(主程序):
# 创建Flask对象
app = Flask(__name__)
#引入app
app = database.config_app()
# 防止出现RuntimeError: Working outside of application context.
app.app_context().push()
#使用 app.register_blueprint() 导入并注册 蓝图对象(注册后可在app里使用)
app.register_blueprint(register.bp1)
@app.route('/hello')
def hello_world():
return 'Hello, World!'
if __name__ == '__main__':
app.debug = True # 开启debug
app.run(use_reloader=False) # 在run()里加入参数 use_reloader=False,就可以解决 * Restarting with stat
Flask实例和SQLAIchemy实例绑定且唯一问题
app对象为Flask的应用配置,db对象为SQLAIchemy对象,SQLAIchemy对象需要知道它将要与哪个Flask应用程序实例绑定。
如果在一个工程项目中不同的python文件中创建了不同的Flask实例,并且在每个文件中都创建了一个SQLAIchemy实例,则会导致问题:
RuntimeError: The current Flask app is not registered with this ‘SQLAlchemy’ instance. Did you forget to call ‘init_app’, or did you create multiple ‘SQLAlchemy’ instances?
如图:
意思就是不能创建多个不同的app实例和db实例,并且app和db需要绑定
所有模块都应该使用相同的 Flask 应用程序实例(app)和 SQLAlchemy 实例(db),从而避免出现不同实例之间的冲突
正确代码如上4)app.py(主程序)的正确代码
问题4:关于蓝图blueprint使用
1)蓝图定义以后templates的模板文件放置
我们ctrl+左键点进Flask对象以后会发现它是默认指向“templates”文件夹的,
但是一直显示无法找到模板文件:
查阅资料后了解,templates文件夹必须放在app.py(主程序)同级
但是我的app = Flask(name)是在database.py里定义然后将app引入到app.py(主程序)文件中,依然无法识别
因此在app.py(主程序)中重新定义app = Flask(name),然后用database.py的函数传递app
app.py:
# 创建Flask对象
app = Flask(__name__)
#引入app
app = database.config_app()
2)蓝图的路由函数
这是我的错误原代码:
bp1 = Blueprint('register_bp', name)
@bp1.route('/register')
def register1():
username = input("请输入您的用户名:")
# 获取用户提交的表单数据
username1 = request.form.get('username')
# 查询数据库,查看该用户名是否已经被注册
existing_user = User.query.filter_by(username=username1).first()
if existing_user:
# 如果用户名已经存在,返回一个错误信息
response = {
'status': 'error',
'message': '该用户名已经被注册,请选择其他用户名'
}
return jsonify(response), 400
# 如果用户名不存在,可以继续进行用户注册的逻辑
email = input("请输入您的邮箱:")
password = input("请输入您的密码:")
#添加数据
user = User(username = username,email = email,password = password)
try:
db.session.add(user) # 添加单个用add()
# 提交添加,可通过rollback撤回
db.session.commit()
print("注册成功")
except Exception:
print("注册失败")
在这个代码中,我同时使用了input()函数和request对象来获取用户输入的username值。这是不合理的,因为input()函数是从控制台中获取用户输入的,而request对象则是从HTTP请求中获取用户提交的表单数据的。这两种方式是不同的,不能混用。如果想从HTTP请求中获取表单数据,应该使用request对象,而不是input()函数。
因此,需要修改代码,将获取username值的方式改为从HTTP请求中获取,而不是从控制台中获取。以下是一个修改后的代码示例:
bp1 = Blueprint('register_bp', __name__)
@bp1.route('/register',methods=['GET','POST'])
def register1():
if request.method == 'GET':
return render_template('register.html')
# 获取用户提交的表单数据
username = request.form.get('username')
# 查询数据库,查看该用户名是否已经被注册
existing_user = User.query.filter_by(username=username).first()
if existing_user:
# 如果用户名已经存在,返回一个错误信息
response = {
'status': 'error',
'message': '该用户名已经被注册,请选择其他用户名'
}
return jsonify(response), 400
# 如果用户名不存在,可以继续进行用户注册的逻辑
email = request.form.get('email')
password = request.form.get('password')
#添加数据
user = User(username = username,email = email,password = password)
try:
db.session.add(user) # 添加单个用add()
# 提交添加,可通过rollback撤回
db.session.commit()
response = {
'status':'success',
'message':'注册成功'
}
return jsonify(response),200
except Exception:
response = {
'status': 'error',
'message': '注册失败,请稍后再试'
}
return jsonify(response), 500
在这个示例中,我们使用methods=[‘GET’,‘POST’]来限定该路由函数请求。然后使用request对象获取用户提交的表单数据中的username、email和password值。
再查询数据库,查看该用户名是否已经被注册。如果已经存在,则返回一个错误响应,提示该用户名已被注册。如果不存在,则使用ORM模型中的add()方法向数据库中添加一条新的用户记录。如果添加成功,则返回一个成功响应,提示用户注册成功。如果添加失败,则返回一个错误响应,提示用户注册失败。
以下是我的register.html的模板代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册</title>
</head>
<body>
<div class="container">
<h1 class="mt-5 mb-3">注册</h1>
<form id="register-form" method="post" action="/register">
<div class="form-group">
<label for="username">用户名</label>
<input type="text" class="form-control" id="username" name="username" placeholder="请输入用户名">
</div>
<div class="form-group">
<label for="email">邮箱</label>
<input type="email" class="form-control" id="email" name="email" placeholder="请输入邮箱">
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" class="form-control" id="password" name="password" placeholder="请输入密码">
</div>
<button type="submit" class="btn btn-primary">注册</button>
</form>
</div>
</body>
</html>
运行程序访问/register路由:
可成功运行
该文章仅包含一个简单的后端flask注册功能遇到的问题