温馨提示
用这个命令,仅在这个虚拟环境安装包
1. 目录结构
1.1 根目录新建一个exts.py
把所有的扩展都放这里
例子:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
from exts import db
db.init_app(app)
1.2 根新建一个config.py
DB_USERNAME = 'root'
DB_PASSWORD = '1234'
DB_HOST = '127.0.0.1'
DB_PORT = '3306'
DB_NAME = 'pythonbbs'
DB_URI = 'mysql+pymysql://%s:%s@%s:%s/%s?charset=utf8mb4' % (DB_USERNAME,DB_PASSWORD,DB_HOST,DB_PORT,DB_NAME)
import config
app.config.from_object(config)
2. 数据库
2.1
pip install flask_migrate
2.2
#`Flask-Migrate` 是一个用于 Flask 应用程序的数据库迁移工具
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
DB_USERNAME = 'root'
DB_PASSWORD = '1234'
DB_HOST = '127.0.0.1'
DB_PORT = '3306'
DB_NAME = 'pythonbbs'
DB_URI = 'mysql+pymysql://%s:%s@%s:%s/%s?charset=utf8mb4' % (DB_USERNAME,DB_PASSWORD,DB_HOST,DB_PORT,DB_NAME)
SQLALCHEMY_DATABASE_URI = DB_URI
SQLALCHEMY_TRACK_MODIFICATIONS = False
2.3 分模块
新建一个models包 在models包下面新建模块,比如auth.py
pip install pymysql
#是用来实现 **SQLAlchemy 模型对象的序列化功能** 的。它属于 `sqlalchemy-serializer` 库,提供了一种简单的方法将 SQLAlchemy 的模型对象转换为 JSON 或字典格式,方便在 API 中返回模型数据。
pip install sqlalchemy_serializer
可选:
#`shortuuid` 是一个 Python 库,用于生成简短、可读性更高的唯一标识符 (UUID)。
import shortuuid
举例:
from sqlalchemy_serializer import SerializerMixin
from exts import db
import shortuuid
from datetime import datetime
from werkzeug.security import generate_password_hash, check_password_hash
class Permission(object):
# 255的二进制方式来表示 1111 1111
ALL_PERMISSION = 0b11111111
# 1. 访问者权限
VISITOR = 0b00000001
# 2. 管理板块的权限
BANNER = 0b00001000
# 3. 管理前台用户的权限j
USER = 0b00010000
# 4. 管理后台管理员的权限
STAFF = 0b01000000
class RoleModel(db.Model, SerializerMixin):
serialize_only = ("id", "name", "desc", "create_time")
__tablename__ = 'role'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(50), nullable=False)
desc = db.Column(db.String(200),nullable=True)
create_time = db.Column(db.DateTime,default=datetime.now)
permissions = db.Column(db.Integer,default=Permission.VISITOR)
class UserModel(db.Model, SerializerMixin):
serialize_rules = ("-_password", "-posts", "-comments")
__tablename__ = "user"
id = db.Column(db.String(100), primary_key=True, default=shortuuid.uuid)
email = db.Column(db.String(50), unique=True, nullable=False)
username = db.Column(db.String(50), nullable=False)
_password = db.Column(db.String(200), nullable=False)
avatar = db.Column(db.String(100))
signature = db.Column(db.String(100))
join_time = db.Column(db.DateTime, default=datetime.now)
is_staff = db.Column(db.Boolean, default=False)
is_active = db.Column(db.Boolean, default=True)
role_id = db.Column(db.Integer, db.ForeignKey("role.id"))
role = db.relationship("RoleModel", backref="users")
def __init__(self, *args, **kwargs):
if "password" in kwargs:
self.password = kwargs.get('password')
kwargs.pop("password")
super(UserModel, self).__init__(*args, **kwargs)
@property
def password(self):
return self._password
@password.setter
def password(self, newpwd):
self._password = generate_password_hash(newpwd)
def check_password(self, rawpwd):
return check_password_hash(self.password, rawpwd)
def has_permission(self, permission):
# 当前用户所拥有的权限&permission = permission
# 0b011 & 0b001 = 0b001
# 0b011 & 0b100 = 0b000
return (self.role.permissions & permission) == permission
from flask import Flask
import config
from exts import db
from flask_migrate import Migrate
from models import auth
app = Flask(__name__)
app.config.from_object(config)
db.init_app(app)
migrate = Migrate(app, db)
if __name__ == '__main__':
app.run()
migrate = Migrate(app, db)
将ORM模型映射到数据库中三部曲
1.初始化迁移仓库:flask db init
2.将ORM模型生成迁移脚本: flask db migrate
3.运行迁移脚本,生成表:flask db upgrade
3. 蓝图
from apps.front import front_bp
from flask import g, redirect, url_for
from functools import wraps
def login_required(func):
@wraps(func)
def inner(*args, **kwargs):
if hasattr(g, "user"):
return func(*args, **kwargs)
else:
return redirect(url_for("front.login"))
return inner
from flask import Blueprint
bp = Blueprint('front', __name__, url_prefix='/')
#可选:
#session登录
from flask_jwt_extended import create_access_token
#分页
from flask_paginate import Pagination
#头像
from flask_avatars import Identicon
#发送邮箱
from flask_mail import Message
#`@bp.before_app_request` 是 **一个请求钩子**,会在每次请求到达任何路由处理函数之前执行。
@bp.before_app_request
def front_before_request():
if 'user_id' in session:
user_id = session.get("user_id")
user = UserModel.query.get(user_id)
setattr(g, "user", user)
#`@bp.context_processor` 是 **上下文处理器**,用来将一些变量或函数注入到模板上下文中,使得这些变量或函数可以直接在模板中使用。
@bp.context_processor
def front_context_processor():
if hasattr(g, "user"):
return {"user": g.user}
else:
return {}
from flask import request
from flask_wtf.file import FileAllowed, FileSize
#本身是一个强大的表单处理库
from wtforms import Form,validators
from wtforms.fields import StringField,IntegerField,FileField
from wtforms.validators import Email, Length, EqualTo, ValidationError, InputRequired
from exts import cache
from models.auth import UserModel
class LoginForm(BaseForm):
email = StringField(validators=[Email(message="请输入正确的邮箱!")])
password = StringField(validators=[Length(6, 20, message="请输入正确长度的密码!")])
remember = IntegerField()
4.方法
新建一个utils包
例子:
# Restful API
from flask import jsonify
class HttpCode(object):
# 响应正常
ok = 200
# 没有登陆错误
unloginerror = 401
# 没有权限错误
permissionerror = 403
# 客户端参数错误
paramserror = 400
# 服务器错误
servererror = 500
def _restful_result(code, message, data):
return jsonify({"message": message or "", "data": data or {}, "code": code})
def ok(message=None, data=None):
return _restful_result(code=HttpCode.ok, message=message, data=data)
def unlogin_error(message="没有登录!"):
return _restful_result(code=HttpCode.unloginerror, message=message, data=None)
def permission_error(message="没有权限访问!"):
return _restful_result(code=HttpCode.paramserror, message=message, data=None)
def params_error(message="参数错误!"):
return _restful_result(code=HttpCode.paramserror, message=message, data=None)
def server_error(message="服务器开小差啦!"):
return _restful_result(code=HttpCode.servererror, message=message or '服务器内部错误', data=None)
5.注册命令
新建一个commands.py
def init_boards():
board_names = ['主食', '小食', '甜点', '火锅']
for index, board_name in enumerate(board_names):
board = BoardModel(name=board_name, priority=len(board_names)-index)
db.session.add(board)
db.session.commit()
print("板块初始化成功!")
# app.py
app.cli.command("init_boards")(commands.init_boards)
flask init_boards
6.热更
pip install watchdog
watchmedo auto-restart --pattern="*.py" --recursive -- python app.py
7.跨域
pip install flask_cors
from flask_cors import CORS
cors = CORS()
from exts import cors
cors.init_app(app, resources={r"/cmsapi/*": {"origins": "*"}})
8.查询的方法
boards = db.session.query(
BoardModel.id.label('cid'),
BoardModel.name.label('label'),
BoardModel.sele_quantity,
).order_by(BoardModel.priority.desc()).all()
boards_dict = [BoardModel(id=board.cid, name=board.label, sele_quantity=board.sele_quantity).to_dict() for board in boards]
boards = BoardModel.query.order_by(BoardModel.priority.desc()).all()
boards_dict = [board.to_dict() for board in boards]
9.问题总结
- tablename = "XXX" 必须为小写,不然最后flask db migrate会出问题!!