FLASK的一些查询操作和项目基本流程

API设计

  1. 所有班级 GET cls/

    • flask
      • 根据班级模型类查询全部数据
      • 先排序(desc(字段)
      • 再分页
      • 最后序列化解析
      • 返回解析后的数据,格式: [{},{}]
    • Vue
      • 定义方法,使用axios的 GET请求所有班级数据
      • 挂载方法
      • 循环展示
  2. 所有学生 GET stu/

    • flask

      • 根据学生模型类查询全部数据
      • 先排序(desc(字段)
      • 再分页
      • 最后序列化解析
      • 返回解析后的数据,格式: [{},{}]
    • Vue

      • 定义方法,使用axios的 GET请求所有班级数据
      • 挂载方法
      • 循环展示
  3. 班级的学生 GET cls/stu/?cls_id=xx

    • flask
      • 接收参数: 班级id
      • 在 学生模型类 中查询: 使用 filter_by, 过滤班级的学生
      • 序列化解析
      • 直接返回数据
    • Vue
      • 定义方法,使用axios的 GET请求所有班级数据, 需要传递 查询字符串: cls_id
      • 挂载方法
      • 循环展示
  4. 搜索 GET stu/search/?text=xx

    • flask
      • 接收参数:关键字
      • 在 学生模型类 中查询: 使用 filter(), 条件既可以是 班级名 ,也可以是 学生名
      • 序列化解析
      • 直接返回数据
    • Vue
      • 定义方法,使用axios的 GET请求所有班级数据, 需要传递 查询字符串: text
      • 挂载方法
      • 循环展示

Flask

项目构建

app包

负责 生成 flask项目的核心app

config.py

指定 项目的app所需的 配置项

class Config(object):
    DEBUG = True
    SQLALCHEMY_DATABASE_URI = 'mysql://root:mysql@localhost:3306/flask07'
    SQLALCHEMY_TRACK_MODIFICATIONS = False

extensions.py

指明 项目所使用的的 第三方 插件

from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_cors import CORS

# 如果安装的插件是pymysql,还需要另外两句话

db = SQLAlchemy()  # 链接数据库
migrate = Migrate()  # 迁移模型类
cors = CORS()  # 跨域


def config_extensions(app):
    db.init_app(app)
    migrate.init_app(app, db=db)
    cors.init_app(app)

__init__.py

创建工厂函数,导入配置项、第三方插件、(蓝图),最后返回 app

from flask import Flask
from .config import Config
from .extensions import config_extensions


def create_app():
    app = Flask(__name__)

    app.config.from_object(Config)

    config_extensions(app)
    # 后期创建完蓝图之后,需要注册蓝图
    return app

manage.py

负责管理项目: 迁移模型类、启动服务

from flask_script import Manager, Server
from flask_migrate import MigrateCommand

from app import create_app

# 1. 利用工厂函数生成APP
app = create_app()
# 2. 创建manage 管理app的对象
manage = Manager(app)

# 3. 给管理对象中添加命令
manage.add_command('runserver', Server())
manage.add_command('db', MigrateCommand)

if __name__ == '__main__':
    manage.run()

蓝图

蓝图类似于django中的子应用,一般是每个功能模块 创建一个 蓝图

__init__.py

创建蓝图,注册蓝图

from flask import blueprints

school_bp = blueprints.Blueprint('school', __name__)

app/__init__.py中的 工厂函数中国注册蓝图

app.register_blueprint(school_bp)

models.py

当前功能模块的所有模型类

from app.extensions import db
from datetime import datetime


class Cls(db.Model):
    __tablename__ = 'tb_cls'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(32), nullable=False, unique=True)
    state = db.Column(db.Integer, default=1)
    addtime = db.Column(db.DATETIME, default=datetime.now)


class Stu(db.Model):
    __tablename__ = 'tb_stu'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(32), nullable=False, unique=True)
    age = db.Column(db.Integer)
    gender = db.Column(db.Integer, default=1)
    state = db.Column(db.Integer, default=1)
    addtime = db.Column(db.DATETIME, default=datetime.now)
    # 外键字段
    cls_id = db.Column(db.Integer, db.ForeignKey('tb_cls.id'))
    # 外键关系
    cls = db.relationship('Cls', backref='students')

需要让 蓝图识别 模型类,需要在 __init__.py中导入模型类

from .models import *

在终端使用如下命令,生成表

python manage.py db init #初始化,生成迁移目录
python manage.py db migrate  # 根据模型类,生成迁移文件
python manage.py db upgrade  # 根据迁移文件,生成表

views.py

一般 定义 视图类,进行业务逻辑处理,返回数据

班级列表页

GET cls/

为了提高查询速度,再重新每个班级时,顺便 提高 反向查询,得到每个班级的学生,在前端Vue再判断展示

from flask_restful import Resource, reqparse
from sqlalchemy import desc
from .models import *

class ClsView(Resource):
    def get(self):
        # 1. 创建解析参数的对象
        parser = reqparse.RequestParser()
        # 2. 指明需要解析的参数
        parser.add_argument('page', type=int, location='args', default=1, help='页码不合法')

        # 3. 获取参数, 得到 字典 { 参数名: 参数值}
        args = parser.parse_args()
        # 4. 从字典中取出具体的 参数
        page = args.get('page')

        # 5. 先查询,后排序,再分页, 得到分页器对象
        pagination = Cls.query.order_by(desc('addtime')).paginate(page=page, per_page=2)

        # 6. 为了解析时间格式,还是 手动解析
        cls = [
            {
                'id': cls.id,
                'name': cls.name,
                'state': cls.state,
                'add_time': cls.addtime.strftime('%Y-%m-%d %H:%M:%S'),
                'stus': [
                    {
                        'id': stu.id,
                        'name': stu.name,
                        'gender': '男' if stu.gender else '女',
                        'age': stu.age,
                        'state': stu.state,
                    }
                    
                    for stu in cls.students
                ]
            }

            for cls in pagination.items
        ]

        # 7. 返回响应数据
        return {
            'cls': cls,
            'pages': pagination.pages
        }

学生列表页

from flask_restful import Resource, reqparse
from sqlalchemy import desc
from .models import *


class StuView(Resource):
    def get(self):
        # 1. 创建解析参数的对象
        parser = reqparse.RequestParser()
        # 2. 指明需要解析的参数
        parser.add_argument('page', type=int, location='args', default=1, help='页码不合法')

        # 3. 获取参数, 得到 字典 { 参数名: 参数值}
        args = parser.parse_args()
        # 4. 从字典中取出具体的 参数
        page = args.get('page')

        # 5. 先查询,后排序,再分页, 得到分页器对象
        pagination = Stu.query.order_by(desc('addtime')).paginate(page=page, per_page=2)

        # 6. 为了解析时间格式,还是 手动解析
        stus = [
            {
                'id': stu.id,
                'name': stu.name,
                'gender': '男' if stu.gender else '女',
                'age': stu.age,
                'state': stu.state,
                'cls': stu.cls.name,
                'add_time': stu.addtime.strftime('%Y-%m-%d %H:%M:%S')
            }

            for stu in pagination.items
        ]

        # 7. 返回响应数据
        return {
            'stus': stus,
            'pages': pagination.pages
        }

模糊查询

flask想要查询 关联表的字段,不能直接查询,需要先将 两表进行连接, 再查询字段

class SearchView(Resource):
    def get(self):
        # 1. 创建解析参数的对象
        parser = reqparse.RequestParser()
        # 2. 指明需要解析的参数
        parser.add_argument('text', type=str, location='args', help='关键字不合法')

        # 3. 获取参数, 得到 字典 { 参数名: 参数值}
        args = parser.parse_args()
        # 4. 从字典中取出具体的 参数
        text = args.get('text')

        # 5. 根据关键字模糊查询, 得到学生的 查询集
        stus = Stu.query.join(Cls, Cls.id == Stu.cls_id). \
            filter(or_(
            Cls.name.like('%{}%'.format(text)),
            Stu.name.like('%{}%'.format(text))
        )).all()

        # 6. 循环解析
        data = [
            {
                'id': stu.id,
                'name': stu.name,
                'gender': '男' if stu.gender else '女',
                'age': stu.age,
                'state': stu.state,
                'cls': stu.cls.name,
                'add_time': stu.addtime.strftime('%Y-%m-%d %H:%M:%S')
            }

            for stu in stus
        ]

        return {
            'stus': data
        }

路由配置

一般是 蓝图的 __init__.py中添加路由

from flask import blueprints
from flask_restful import Api
from .models import *
from .views import *

school_bp = blueprints.Blueprint('school', __name__)

api = Api(school_bp)  # 创建路由对象
api.add_resource(ClsView, '/cls')
api.add_resource(StuView, '/stu')

Vue

在Vue项目中,有某个功能经常使用,可以单独定义一个组件,后期 复用即可

封装组件

<template>
  <div>
    <button>
      <routerLink :to="{name:'Cls'}" :style="{'text-decoration': 'none'}">
          所有班级
      </routerLink>
    </button>
    <button>
      <routerLink :to="{name:'Stu'}" :style="{'text-decoration': 'none'}">所有学生</routerLink>
    </button>
  </div>
</template>

<script>
export default {
  name: "navbar"
}
</script>

班级列表页

<template>
  <div>
    <navbar></navbar>
    <h1>班级列表</h1>
    <!--  3 先循环班级列表,在每个班级展示时,循环对应的学生列表, 默认不显示,点击查看按钮,修改状态   -->
    <div v-for="(c, index) in cls" :key="index">
      <p>
        {{ c.id }} == {{ c.name }} == {{ c.add_time }} == {{ c.state }}
        <button @click="c.flag = !c.flag">查看</button>
      </p>
      <div v-for="s in c.stus" v-if="c.flag">
        {{ s.id }} == {{ s.name }} == {{ s.age }} == {{ s.gender }}
      </div>
    </div>
    <!-- 4 循环所有页码,生成页码按钮   -->
    <button @click="pageChange(page-1)">上一页</button>
    <button v-for="i in pages" @click="pageChange(i)">{{ i }}</button>
    <button @click="pageChange(page+1)">下一页</button>
  </div>
</template>

<script>
import navbar from "./navbar";

export default {
  name: "Cls",
  components: {
    navbar
  },
  data() {
    return {
      // 0. 对应空数据
      cls: [], // 当前页的所有数据
      pages: 1, // 总页码
      page: 1, // 当前页
    }
  },
  methods: {
    //   1. 定义方法,请求当前页的数据,传递 页码
    get_cls() {
      this.$axios.get('/cls', {
        params: {
          'page': this.page
        }
      })
        .then(resp => {
          this.cls = resp.data.cls
          this.pages = resp.data.pages
        })
    },
    // 5, 点击页码按钮,传递当前按钮代表 的 页码
    pageChange(n) {
      // 5.1 判断传递的 数字n  是否符合页码规则
      if (n < 1 || n > this.pages || this.page === n) {
        return
      }
      // 5.2 根据新的数字n修改 当前页码page
      this.page = n
      // 5.3 根据新页码,重新请求班级数据
      this.get_cls()
    }
  },
  mounted() {
    // 2. 挂载执行请求数据的方法
    this.get_cls();
  }
}
</script>

学生列表页

<template>
  <div>
    <navbar></navbar>
    <h1>学生列表</h1>
    <!--  3 只需要循环学生列表即可   -->
    <div v-for="(s, index) in stu" :key="index">
      {{ s.id }} == {{ s.name }} == {{ s.age }} == {{ s.gender }} == {{ s.add_time }} == {{ s.cls }}
    </div>
    <!-- 4 循环所有页码,生成页码按钮   -->
    <button @click="pageChange(page-1)">上一页</button>
    <button v-for="i in pages" @click="pageChange(i)">{{ i }}</button>
    <button @click="pageChange(page+1)">下一页</button>
  </div>
</template>

<script>
import navbar from "./navbar";

export default {
  name: "Stu",
  components: {
    navbar
  },
  data() {
    return {
      // 0. 对应空数据
      stu: [], // 当前页的所有数据
      pages: 1, // 总页码
      page: 1, // 当前页
    }
  },
  methods: {
    //   1. 定义方法,请求当前页的数据,传递 页码
    get_stus() {
      this.$axios.get('/stu', {
        params: {
          'page': this.page
        }
      })
        .then(resp => {
          this.stu = resp.data.stus
          this.pages = resp.data.pages
        })
    },
    // 5, 点击页码按钮,传递当前按钮代表 的 页码
    pageChange(n) {
      // 5.1 判断传递的 数字n  是否符合页码规则
      if (n < 1 || n > this.pages || this.page === n) {
        return
      }
      // 5.2 根据新的数字n修改 当前页码page
      this.page = n
      // 5.3 根据新页码,重新请求班级数据
      this.get_stus()
    }
  },
  mounted() {
    // 2. 挂载执行请求数据的方法
    this.get_stus();
  }
}
</script>

搜索页面

  • v-model 获取用户输入的 关键字
  • 点击搜索按钮,执行搜索方法
  • 在方法中,发送 get请求, 携带 关键字参数
  • 请求成功,在页面循环展示所有数据
posted @ 2021-06-10 19:54  lsp的飘柔  阅读(563)  评论(0)    收藏  举报