1.4 Flask数据模型ORM

一、模型model

1、 什么是模型

模型 - 根据数据库中表结构而创建出来的class
数据库中每一张表对应到变成语言中就是一个class
表中的每一个列, 对应到变成语言中就是class的一个属性

2、模型的框架–ORM框架

1) 、 什么是ORM
    ORM---Object Relational Mapping ,简称: ORM 、 O/RM 、 O/R Mapping
    中文名: 对象关系映射

1.4 Flask数据模型ORM_第1张图片

2) ORM的三大特征
 - 数据表(Table) 到编程类(Class)的映射
 - 数据类型的映射
    数据库中表的字段以及数据类型对应到编程语言中就是类的属性及数据类型
 - 关系映射( ******)
   将数据库中表与表的关系对应到变成语言中类与类的关系
   【1-1关系】: 
       A表中的一条数据只能与B表中的一条数据关联 ------           A表中的一条数据只能与B表中的一条数据关联
   【1-多关系】
     A表中的一条数据与B表中的多条数据关联 ------           A表中的一条数据只能与B表中的一条数据关联
   【多-多关系】
      A表中的一条数据与B表中的多条数据关联 ------           A表中的一条数据与B表中的多条数据关联
3) ORM的优点
 - 封装了数据库中所有的操作,提升效率
 - 可以省略庞大的数据访问层,即便不用SQL编码也能完成对数据库的CRUD操作
   Create、Retrieve、Update、Delete

二、Flask中ORM框架

1、SQLALchemy 框架

1) 安装SQLALchemy : pip安装
2) Flask需要使用flask-sqlachemy支持包: pip install flask-sqlalchemy

2、在Flask中配置数据库

# app.config['SQLALCHEMY_DATABASE__URL'] = "mysql://用户名:密码@数据库服务地址:端口号/数据库"
app.config['SQLALCHEMY_DATABASE__URL'] = "mysql://root:123456@localhost:3306/flask"
# 创建SQLALchemy 的实例 -db,以后再程序中通过db来操作数据库
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app)

3、 拓展

统一资源标识符(Uniform Resource Identifier) ---URL
统一资源标识符(Uniform Resource Identifier) ---URL
create database flask default utf8 collate utf8_general_ci  # 创建数据库
--- Navicat for Mysql 数据库第三方可视化工具
--- Power Designer  数据库建模工具

二、ORM框架熟知+数据库表设计 *****

1、创建模型model

1) Flask-SQLALchemy连接数据库以及创建表

flask应用实例
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['DEBUG'] = True
app.config["ENV"] = "development"
# 连接数据库
# app.config['SQLALCHEMY_DATABASE__URL'] = "mysql://用户名:密码@数据库服务地址:端口号/数据库"
app.config['SQLALCHEMY_DATABASE_URL'] = "mysql://root:123456@localhost:3306/flask"
# 设置是否跟踪数据库的修改情况,一般不跟踪
app.config['SQLALCHEMY_TRACE_MODIFICATIONS'] = False  # 设置字段+属性
# 数据库操作时是否显示原始SQL语句,一般是打开的,因为需要后台日志
app.config['SQLALCHEMY_ECHO'] = True

# 实例化ORM框架的操作对象,后续数据库操作,都要基于操作对象来完成
db = SQLAlchemy(app)


class Role(db.Model):
    __tablename = "my_users"  # 设置表名
    user_id = db.Column(db.Integer, primary_key=True)
    user_name = db.Column(db.String(10), nullable=False)


@app.route("/index", endpoint="home")
def index():
    return "这是首页"


if __name__ == "__name__":
    # 创建当前应用中声明的所有模型类对应的数据表,db.drop_all()是删除表
    db.create_all()
    app.run(debug=True)

创建模型model-数据库配置
名称                                   说明
SQLALCHEMY_DATABASE_URL               用于链接的数据库URL:"mysql://用户名:密码@数据库服务地址:端口号/数据库"
SQLALCHEMY_BINDS                      一个映射binds到链接URL的字典, 更多binds的信息见Binds操作多个数据库 ---- 连接多个数据库
SQLALCHEMY_ECHO                       如果设置为True,SQLALchemy会记录所有发给stderr的语句,这对调试有用(打印sql语句)
SQLALCHEMY_RECORD_QUERIES             可以用于显式的禁用或启用查询记录。查询记录在调试或测试模式自动启用
SQLALCHEMY_NATIVE_UNICODE             可以用于显式禁用原生unicode支持。当使用不合适的指定无编码的数据库默认值时, 这对于
                                      一些数据库适配器时必须的
SQLALCHEMY_POOL_SIZE                  数据库链接池的大小。默认时引擎默认值(通常是5)
SQLALCHEMY_POOL_TIMEOUT               设定链接池的连接超时时间,默认是10
SQLALCHEMY_POOL_RECYCLE               多少秒自动回连连接。对MYsql是必要的。它默认移除闲置多余8小时的连接,注意如果使用了
                                      MYSQL, Flask-SQLALchemy自动设定这个值为2小时
创建模型model-Binds操作多个数据库
示例配置–连接多个数据库

– 创建模型model-binds

SQLALCHEMY_DATABASE_URL = "mysql://root:123456@localhost:3306/flask"
SQLALCHEMY_BINDS = {
   "users_1": SQLALCHEMY_DATABASE_URL,
   "users_2": "mysql://root:123456@localhost:3306/flask2" }

– 创建和删除表

 create_all() 和drop_all()方法默认作用域声明的所有bind,包括默认的, ,"__all__"可以指向一个bind名,或者所有binds,默认是: 
bind(SQLALCHEMY_DATABASE_URL) 名为None:
dp。create_all()
dp.create_all(bind=['users_1'])
 dp.drop_all(bind=['users_1'])

– 引用Binds

- 当声明模型时,可以用: __bin_key__属性指定bind
  class Role(db.Model):
      __bind_key__ = "users_1"  
      user_id = db.Column(db.Integer, primary_key=True)
- bind_key内部存储在表的info字典中,作为bind_key键值,:想要创建一个表对象时,可以如下
   user_favorites = db.Table('user_favorites',
                          db.Column('user_id', db.Integer, db.ForeignKey('user_id')),
                          db.Column('message_id', db.Integer, db.ForeignKey('message_id')),
                          info={'bind_key', 'users_1'})
  # 如果在模型上指定了__bind_key__, 你可以用他们准确的做想做的,模型会自行连接到指定的数据库连接

– 总结

  binds? ----可以执行SQL语句并且通常是一个连接或引擎,,在Flask-SQLALchemy中,bind总是背后自动创建好引擎,引擎中的每个之后都会关联
  短键(bind_key),这个键会在模型声明时使用,来把一个模型关联到一个特定引擎----若没有为模型指定bind key,会默认连接:
  SQLALCHEMY_DATABASE_URL配置的值

2、 创建模型model—字段类型

1) 常见的SQLALchemy字段类型

类型名                  Python类型           说明
Integer               int                  普通整数,一般32位
SmallInteger          int                  取值范围小的整数,一般16位
BigInteger            int/long              不限精度的整数
Float                 float                 浮点数
Numeric               decimal.Decimal       普通整数,一般32位
String                str                   变长字符串
Text                  str                   变长字符串,对较长或不限长度的字符串做了优化
Unicode               unicode         
Unicode Text          unicode
Boolean               bool                  布尔
Date                  datetime.data         时间
Time                  datetime.datetime     日期和时间
LargeBinary           str                   二进制文件

2) 常用的SQLALchemy列选项

列选项              说明
primary_key        如果为True,代表表的主键
unique             如果为True,代表这列不允许出现重复值
index              如果为True,为这列创建索引,提高查询效率
nullable           如果为True,允许有空值,如果为False,不允许有空值
default            为这列定义默认值

3、 模型关系映射(一对一)

-   一对一在数据库中的设置
   关联两张表中的任意一张表:  1) 增量外键,引用另一张表主键  2) 并且要实时唯一约束
-   在ORM中实现
    1) 在任意一张表中增加外键和唯一约束
        外键列名 = db.Column(db.Integer, db.ForeignKey(主表.主键),unique=True)
    2) 在另一个实体类中增加关联属性和反向引用关系属性
        属性名 = db.relationship('关联的实体类名',backref='反向引用关系属性名',uselist=False)
    uselist: 设置为False, 表示关联属性是一个标量而非一个列表
- 示例 
```
 class Strudent(db.Model):
    __tablename__ = "tb_student"
    id = db.Column(db.Integer, primary_key=True, comment="主键ID")
    name = db.Column(db.String(250), comment="姓名")
    age = db.Column(db.Integer, comment="年龄")

    # 关联属性,是SQLALchemy提供给开发者快速引用外键模型的一个对象属性,不存在mysql中
    # backref反向引用,类似django的related,通过外键模型查询主模型数据时的惯量属性
    info = db.relationship('StrudentInfo', backref='own', uselist=False)

    def __repr__(self):
        return self.name


class StudentInfo(db.Model):
    __tablename__ = "tb_student_info"
    id = db.Column(db.Integer, primary_key=True, comment="主键ID")
    # 外键 -在另一模型中添加外键
    sid = db.Column(db.Integer, db.ForeignKey(Strudent.id), comment="学生ID")
    address = db.Column(db.String(250), nullable=True, comment="家庭住址")
    mobile = db.Column(db.String(15), unique=True, comment="联系电话")

    def __repr__(self):
        return self.own.name
class Config:
    DENUG = True
    JSON_AS_ASCII = False
    SQLALCHEMY_DATABASE_URL = "mysql://root:123456@localhost:3306/flask"
    SQLALCHEMY_TRACK_MODIFICATIONS = True
    SQLALCHEMY_ECHO = True


if __name__ == "__name__":
    # 创建当前应用中声明的所有模型类对应的数据表,db.drop_all()是删除表
    app.config.from_object(Config)
    db = SQLAlchemy(app)
    db.init_app(app) --- 初始化

```

4、 模型关系映射(一对多)

原则

 在“多”的实体中增加外键关系
 在“一”的试题中增加关联属性和反向引用关系属性
在 “多” 的实体中
 外键列名 = db.Co(db.Integer, db.ForeignKey(‘主表.主键‘)
 属性名=db.relationhip('多的实体类名',backref='反向引用的关系属性名',lazy='dynamic')
在“一”的实体中
增加关联属性和反向引用关系属性
属性名= db.relationship('多的实体类名',backref='反向引用关系属性名',lazy=dynamic)
lazy --- 指定如何加载相关记录
      select : 首次访问时加载相关关联数据
      immediate --- 元对象加载后立马加载关联数据(使用连接)
      subquery --- 效果同上,使用子查询
      noload --- 永不加载
      dynamic ---- 不加载记录, 但提供加载记录的查询
如: Course与Teacher是存在一对多的关系
     course = Course.query.filter_by(id=1).first
     course.teachers.all()\course.teachers.first(),course.filter_by().all()

获取数据

- 通过“一”对象找“多” 的关联对象们
  course = Course.query.filter_by(id=1).first()
  teachers = course.teachers.all()
- 通过’多‘对象找’一‘的关联对象(通过反向引用关系属性 查找) 
  tea= Teacher.query.filter_by(id=1).first()
  course = tea.course

5、 模型关系映射(多对多)

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['DEBUG'] = True
app.config["ENV"] = "development"
# 连接数据库
# app.config['SQLALCHEMY_DATABASE__URL'] = "mysql://用户名:密码@数据库服务地址:端口号/数据库"
SQLALCHEMY_DATABASE_URL = "mysql://root:123456@localhost:3306/flask"
app.config['SQLALCHEMY_DATABASE_URL'] = SQLALCHEMY_DATABASE_URL

# 实例化ORM框架的操作对象,后续数据库操作,都要基于操作对象来完成
db = SQLAlchemy(app)

""" 以db.Table关系表来确定模型之间的多对多关联"""
achievement = db.Table(
    'tb_achievement',
    db.Column('student_id', db.Integer, db.ForeignKey('tb_student.id')),
    db.Column('course_id', db.Integer, db.ForeignKey('tb_course.id')),
    # 这里的表信息,在主键模型中,仅仅表达的是关联关系,所以中间表的字段,无法通过主模型来获取
    db.Column('score', db.DECIMAL(5, 2), comment='成绩'),
    db.Column('create_time', db.DateTime, comment='考试时间')

)


class Strudent(db.Model):
    __tablename__ = "tb_student"
    id = db.Column(db.Integer, primary_key=True, comment="主键ID")
    name = db.Column(db.String(250), comment="姓名")
    age = db.Column(db.Integer, comment="年龄")

    # 关联属性,是SQLALchemy提供给开发者快速引用外键模型的一个对象属性,不存在mysql中
    # backref反向引用,类似django的related,通过外键模型查询主模型数据时的惯量属性
    info = db.relationship('StrudentInfo', backref='own', uselist=False)

    def __repr__(self):
        return self.name


class Teacher(db.Model):
    __tablename__ = "tb_teacher"
    id = db.Column(db.Integer, primary_key=True, comment="主键ID")
    name = db.Column(db.String(250), comment="姓名")
    sex = db.Column(db.Boolean, default=False, comment="性别")
    age = db.Column(db.Integer, comment="年龄")
    option = db.Column(db.Enum('老师', '助教', '班主任'), default='老师', comment='教职')
    # 关联属性,是SQLALchemy提供给开发者快速引用外键模型的一个对象属性,不存在mysql中
    # backref反向引用,类似django的related,通过外键模型查询主模型数据时的惯量属性
    course_list = db.relationship('Course', uselist=True, backref='teacher', lazy='subquery')

    def __repr__(self):
        return self.name


class Course(db.Model):
    __tablename__ = "tb_course"
    id = db.Column(db.Integer, primary_key=True, comment="主键ID")
    # 外键 -在另一模型中添加外键
    name = db.Column(db.String(250), unique=True, comment="课程名称")
    price = db.Column(db.Numeric(6, 2))
    teacher_id = db.Column(db.Integer, db.ForeignKey(Teacher.id), comment="教职人员id")
    student_list = db.relationship('Strudent', secondary=achievement, backref='course_list', lazy='dynamic')

    def __repr__(self):
        return self.own.name


class Config:
    DENUG = True
    JSON_AS_ASCII = False
    SQLALCHEMY_DATABASE_URL = "mysql://root:123456@localhost:3306/flask"
    SQLALCHEMY_TRACK_MODIFICATIONS = True
    SQLALCHEMY_ECHO = True


if __name__ == "__name__":
    # 创建当前应用中声明的所有模型类对应的数据表,db.drop_all()是删除表
    app.config.from_object(Config)
    db = SQLAlchemy(app)
    db.init_app(app)

你可能感兴趣的:(Flask,flask,python,后端)