Flask-SQLAIchemy项目后端-注册账户(实验项目第二期)

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注册功能遇到的问题

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Flask中实现前端实时显示后端处理进度可以通过使用WebSocket技术来实现。WebSocket是一种基于TCP的协议,可以实现双向通信,使得前后端能够在同一个连接上进行实时的数据交换。 首先,我们需要在Flask中使用WebSocket,可以使用Flask-SocketIO来方便地实现WebSocket功能。安装Flask-SocketIO后,我们可以在Flask应用中使用socketio对象来实现WebSocket的功能。 在后端代码中,我们可以通过在任务处理函数中发送进度信息给前端。例如,我们可以在任务处理函数的循环中,使用socketio的emit函数发送当前任务的进度信息。前端页面将通过监听WebSocket消息的方式接收进度信息。 在前端代码中,我们需要在页面中引入SocketIO的JavaScript库,并创建一个SocketIO对象。然后,我们可以使用socket.on()函数来监听后端发送的进度信息,并根据接收到的进度信息来更新前端页面上的进度显示。 需要注意的是,为了防止过多的WebSocket连接导致性能问题,我们可以考虑使用Flask-SocketIO提供的命名空间和房间功能。通过使用命名空间和房间,我们可以将客户端分组,只向特定的客户端发送进度信息。 总结起来,实现Flask和前端实时显示后端处理进度的关键步骤是:在Flask应用中使用Flask-SocketIO实现WebSocket功能,后端任务处理函数中使用socketio对象发送进度信息,前端页面中使用SocketIO对象监听进度信息并更新页面显示。这样就能够实现前端实时显示后端处理进度的功能了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值