Flask蓝图结构整合(八)

flask项目蓝图目录结构:

《Flask蓝图结构整合(八)》

在蓝图版项目开始之前需要安装数据库同步的插件flask-migrate

《Flask蓝图结构整合(八)》
《Flask蓝图结构整合(八)》

项目结构化配置(flask-script蓝图版)

蓝图包初始化

main\__init__.py
from flask import Blueprint  # 导入flask蓝图

# 创建蓝图
main = Blueprint("main",__name__)

# 加载视图路由
from . import views

视图路由配置

main\views.py
""" 视图和路由文件 """
import hashlib
from flask import session
from flask import jsonify
from flask import request
from flask import redirect
from flask import render_template

from . import main # 导入创建的蓝图main
from app import csrf # 导入惰性csrf
from app.models import * # 导入所有模型类
from .forms import TeacherForm  # 导入from表单类


def SetPassword(password):
    md5 = hashlib.md5()
    md5.update(password.encode())
    return md5.hexdigest()

def loginValid(fun):
    def inner(*args,**kwargs):
        cookie_username = request.cookies.get("username")
        id = request.cookies.get("user_id")
        session_username = session.get("username")
        if cookie_username and id and session_username:
            if cookie_username == session_username:
                return fun(*args,**kwargs)
        return redirect("/login/")
    return inner


# 使用蓝图注册路由
@main.route("/register/",methods=["GET","POST"]) 
def register():
    if request.method == 'POST':
        form_data = request.form
        username = form_data.get("username")
        password = form_data.get("password")
        identity = form_data.get("identity")

        user = User()
        user.username = username
        user.password = SetPassword(password)
        user.identity = int(identity)
        user.save()

        return redirect('/login/')
    return render_template("register.html")


@main.route("/login/",methods=["GET","POST"])
def login():
    if request.method == "POST":
        form_data = request.form
        username = form_data.get("username")
        password = form_data.get("password")

        user = User.query.filter_by(username=username).first()
        if user:
            db_password = user.password
            md5_password = SetPassword(password)
            if md5_password == db_password:
                # 验证成功,跳转首页
                response = redirect('/index/')
                # 设置cookie
                response.set_cookie("username",username)
                response.set_cookie("user_id",str(user.id))
                # 设置session
                session["username"] = username
                # 返回跳转页面
                return response
    return render_template("login.html")

@main.route("/index/")
@loginValid
def index():
    # print(session.get('username'))
    response = render_template("index.html",**locals())
    return response

@main.route("/logout/",methods=["GET","POST"])
def logout():
    response = redirect('/login/')
    for key in request.cookies:
        response.delete_cookie(key)
    del session["username"]
    return response

# @csrf.exempt # 临时关闭csrf校验
@main.route("/add_teacher/",methods=["GET","POST"])
def add_teacher():
    teacher_form = TeacherForm()
    if request.method == "POST":
        name = request.form.get("name")
        age = request.form.get("age")
        gender = request.form.get("gender")
        course = request.form.get("course")

        teacher = Teacher()
        teacher.name = name
        teacher.age = age
        teacher.gender = gender
        teacher.course_id = course
        teacher.save()
    return render_template("add_teacher.html",**locals())

# csrf 如果没有配置跳转的错误页面
# @csrf.error_handler
@main.errorhandler
@main.route("/csrf_403/")
def csrf_tonken_error(reason):
    return render_template("csrf_403.html")

# ajax 前端校验
@main.route("/userValid/",methods=["GET","POST"])
def userValid():
    # 定义json字典数据格式
    result = { 
        "code":"",
        "data":""
    }
    if request.method == "POST":
        username = request.form.get("username")
        if username:
            user = User.query.filter_by(username=username).first()
            if user:
                result["code"] = 400
                result["data"] = "用户名已存在"
            else:
                result["code"] = 200
                result["data"] = "用户名未被注册,可以使用"
    return jsonify(result)

@main.route("/student_list/")
def student_list():
    students = Student.query.all()
    return render_template("student_lists.html",**locals())
    

form表单配置

main\forms.py
import wtforms # 定义字段
from flask_wtf import FlaskForm # 定义表单
from wtforms import validators # 定义校验
# forms当中禁止查看数据库,数据库查询被认为视图功能
course_list = []

class TeacherForm(FlaskForm):
    """ form字段的参数 label=None, 表单的标签 validators=None, 校验,传入校验的方法 filters=tuple(), 过滤 description='', 描述 id=None, html id default=None, 默认值 widget=None, 样式 render_kw=None, 属性 参数 """

    name = wtforms.StringField(
        label="教师姓名",
        validators=[
            validators.DataRequired('姓名不可以为空')
        ],
        render_kw={ 
            "class": "form-control",
            "placeholder": "教师姓名"
        }
    )
    age = wtforms.IntegerField(
        label="教师年龄",
        validators=[
            validators.DataRequired("年龄不可以为空"),
        ],
        render_kw={ 
            "class": "form-control",
            "placeholder": "教师年龄",
        }
    )
    gender = wtforms.SelectField(
        label="教师性别",
        choices=[
            ("1","男"),
            ("2","女")
        ],
        render_kw={ 
            "class": "form-control",
        }
    )
    course = wtforms.SelectField(
        label="学科",
        choices=course_list,
        render_kw={ 
            "class": "form-control",
        }
    )
    submit = wtforms.SubmitField(
        label="提交",
        render_kw={ 
            "class": "btn btn-primary btn-block",
        },
    )

app应用初始化

app\__init__.py
import pymysql
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import CSRFProtect # 导入csrf校验模块,csrfProtect在1.0之后移除


pymysql.install_as_MySQLdb()


# 惰性加载
csrf = CSRFProtect()

db = SQLAlchemy()

def create_app(config_name):
    # 创建flask App实例
    app = Flask(__name__)
    # 使用类配置加载
    app.config.from_object('settings.DebugConfig')

    # app惰性加载插件
    csrf.init_app(app)
    db.init_app(app)

    # 注册蓝图
    from .main import main as main_blueprint
    from .ApiResource import api_main
    app.register_blueprint(main_blueprint)
    app.register_blueprint(api_main,url_prefix='/api')
    return app

模型类配置

app\models.py
from app import db

# 创建数据库回话,基于会话进行增删改查
# 由于此处session与flask session设置冲突,改为sess

class BaseModel(db.Model):
    __abstract__ = True # 抽象表为True,代表当前类为抽象类,不会被创建
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)

    # 数据保存方法
    def save(self):
        sess = db.session()
        sess.add(self)
        sess.commit()

     # 数据删除方法
    def delete_data(self):
        sess = db.session()
        sess.delete(self)
        sess.commit()

class User(BaseModel):
    """ 用户表 """
    __tablename__ = "user"
    username = db.Column(db.String(32))
    password = db.Column(db.String(32))
    identity = db.Column(db.Integer) # 1教室 0学生
    identity_id = db.Column(db.Integer,nullable=True)

class Student(BaseModel):
    """ 学生表 """
    __tablename__ = "student"
    name = db.Column(db.String(32))
    age = db.Column(db.Integer)
    gender = db.Column(db.Integer) # 1 男 2 女
    to_attend = db.relationship(
        "Attend",
        backref = "to_student"
    )

# 学生课程关联表(多对多),也可以使用上面的方式创建该表
Student_Course = db.Table(
    "student_course",
    db.Column("id",db.Integer,primary_key=True,autoincrement=True),
    db.Column("student_id",db.Integer,db.ForeignKey("student.id")),
    db.Column("course_id",db.Integer,db.ForeignKey("course.id")),
    db.Column("delete_flag",db.Integer,default=1)  # 1没有停课 0停课

)

class Course(BaseModel):
    """ 课程表 """
    __tablename__ = "course"
    name = db.Column(db.String(32))
    description = db.Column(db.Text)
    to_teacher = db.relationship(
        'Teacher', # 映射模型
        backref = 'to_course', # 反向映射字段,反向映射表通过该字段查询当前表
    ) # 映射表字段

    to_student = db.relationship(
        "Student",# 映射模型
        secondary = Student_Course, # 第二映射的模型
        backref = db.backref("to_course",lazy="dynamic"),
        lazy = "dynamic"
            # select 访问该字段时,加载所有的映射数据
            # joined 对关联的两个表student和student_course进行join查询
            # dynamic 访问该字段时,不加载数据
    )

class Grade(BaseModel):
    """ 成绩表 学生、课程关联此表 """
    __tablename__ = "grade"
    grade = db.Column(db.Float,default=0)
    student_id = db.Column(db.Integer,db.ForeignKey("student.id"))
    course_id = db.Column(db.Integer,db.ForeignKey("course.id"))

class Attend(BaseModel):
    """ 考勤表:记录学生出勤状况 学生考勤:一对多 """
    __tablename__ = "attend"
    att_time = db.Column(db.Date)
    status = db.Column(db.Integer,default=1) # 0 请假 ;1 正常出勤 ;2 迟到 ;3 早退 ;4 旷课
    student_id = db.Column(db.Integer,db.ForeignKey("student.id"))

class Teacher(BaseModel):
    """ 老师表 老师与课程是多对一 """
    __tablename__ = "teacher"
    name = db.Column(db.String(32))
    age = db.Column(db.Integer)
    gender = db.Column(db.Integer)
    course_id = db.Column(db.Integer,db.ForeignKey("course.id"))

项目配置

settings.py
import os
# from mysql import connector
BASE_DIR = os.path.abspath(os.path.dirname(__file__))

# 通用配置
class BaseConfig():
    SQLALCHEMY_COMMIT_ON_TEARDOWN = True
    SQLALCHEMY_TRACK_MODIFICATIONS = True
    SECRET_KEY = "admin123"

# 调试配置
class DebugConfig(BaseConfig):
    DEBUG = True
    SQLALCHEMY_DATABASE_URI = "sqlite:///" + os.path.join(BASE_DIR, "Student_test.sqlite") + '?check_same_thread=False'
    # SQLALCHEMY_DATABASE_URI = "mysql://root:q1q1q1@localhost/StudentManage"
    # SQLALCHEMY_DATABASE_URI = "mysql+mysqlconnector://root:q1q1q1@localhost/StudentManage"


# 上线配置
class OnlineConfig(BaseConfig):
    DEBUG = False
    SQLALCHEMY_DATABASE_URI = "sqlite:///" + os.path.join(BASE_DIR, "Student.sqlite")

项目启动文件配置

manage.py
from app import create_app,db
from flask_script import Manager
from flask_migrate import Migrate # 用来同步数据库
from flask_migrate import MigrateCommand # 用来同步数据库的命令

# 实例化app
app = create_app("running")

# 命令行封装app
manager = Manager(app)

# 绑定可以管理的数据库模型
migrate = Migrate(app,db)

# 加载数据库管理命令,添加db命令
manager.add_command("db",MigrateCommand)

if __name__ == "__main__":
    manager.run()

至此,一个基本的flask蓝图结构及其配置就已经搭建完成,现在就可以测试项目是否有误。

查看项目可以使用的命令

python manage.py

《Flask蓝图结构整合(八)》

查看db的命令
《Flask蓝图结构整合(八)》

同步数据库,启动项目

使用flask-migrate的命令
  • python manage.py db init 初始化数据库,生成迁移文件
    《Flask蓝图结构整合(八)》
  • python manage.py db migrate 同步数据库
    《Flask蓝图结构整合(八)》
  • python manage.py upgrade 更新数据库
    《Flask蓝图结构整合(八)》
    查看数据库
    《Flask蓝图结构整合(八)》

启动项目

《Flask蓝图结构整合(八)》

蓝图项目中restful接口的使用

创建一个蓝图包,其下创建一个初始化文件和一个接口视图路由文件

《Flask蓝图结构整合(八)》
APIResource.py

from app.ApiResource import api
from flask_restful import Resource
from app.models import *

result = { 
    "version": "v1.0",
    "code": "",
    "data": []
}

@api.resource('/user/')
class UserInfo(Resource):
    def get(self):
        values = User.query.all()
        result["code"] = 200
        for value in values:
            result["data"].append(
                { 
                    value.username:{ 
                        "username":value.username,
                        "password":value.password,
                        "identity":value.identity,
                        "is_active":True
                    }
                }
            )
        result["count"] = len(values)
        return result

初始化蓝图:

from flask import Blueprint
from flask_restful import Api

api_main = Blueprint("api_main",__name__)

api = Api(api_main)

from . import ApiResource

app初始化文件中注册接口蓝图:
《Flask蓝图结构整合(八)》
在这里添加一个参数url_prefix=’/api’配置接口主路由,因为当我们有多个接口视图时,不可能都集中在一个视图路由或者每个接口配置一个根路由

《Flask蓝图结构整合(八)》

    原文作者:没了对象省了流量ii
    原文地址: https://blog.csdn.net/z_ipython/article/details/98982750
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞