第四课 Flask数据模型Model

Flask 第四课Flask数据模型Model

tags:

  • Flask
  • 2019千锋教育

categories:

  • flask
  • model
  • 数据模型
  • flask-caching

第一节 flask的模型

Flask默认并没有提供任何数据库操作的API,我们可以选择任何适合自己项目的数据库来使用Flask中可以自己的选择数据,用原生语句实现功能,也可以选择ORM ( SQLAIchemy,MongoEngine)

  1. 原生SQL缺点
    • 代码利用率低,条件复杂代码语句越长,有很多相似语句
    • 一些SQL是在业务逻辑中拼出来的,修改需要了解业务逻辑
    • 直接写SQL容易忽视SQL问题
  2. ORM将对对象的操作转换为原生SQL优点
    • 性能损耗少
    • 设计灵活,可以轻松实现复杂查询
    • 移植性好
      python的ORM (SQLAIchemy)针对于Flask的支持: pip install flask-sqlalchemy -i https://pypi.douban.com/simple

第二节 数据库连接

1. mysql连接

dialect+driver://usermame:password@host:port/database
dialect数据库实现 driver数据库的驱动
例子:
app.config[‘SQLALCHEMY_DATABASE_URI’]=‘mysql+pymysql://root:[email protected]:3306/flask_test’

2. Sqlite连接

app.config[‘SQLALCHEMY_ DATABASE_ URI’]= DB URI
aDD.configI’SQLALCHEMY_ TRAKE_ MODIFICATIONS’]=False 禁止对象追踪修改
SQLite数据库连接不需要额外驱动,也不需要用户名和密码
SQLite连接的URI:DB_ URI = sglite:///sqlite3.db

第三节 ORM字段类型

常用字段: Smalllnteger BigInteger Float
Numeric String Text Unicode
Unicode Text Boolean Date Time
DateTime Interval LargeBinary
  1. 初始化:python manage.py db init
  2. 升级:python manage.py db upgrade
  3. 降级回退:python manage.py db downgrade
  4. 生成迁移文件:python manage.py db migrate
  5. 生成迁移数据库前要看一下模型类,有没有注册到views文件中。from App.models import models, User
  6. models.create_all()创建表, models.drop_all()删除表
  7. 常用约束
    • primary key autoincrement unique index
    • nullable default ForeignKey()

1. 继承自己的定义的模型类

  1. 表名: _tablename
  2. 模型继承
    • 默认继承并不会报错,它会将多个模型的数据映射到一张表中,导致数据混乱,不能满足基本使用
    • 抽象的模型是不会在数据库中产性映射的: abstract =True
  3. 文档
    • flask-sqlalchemy
    • sqlalchemy
  4. 实际案例
# 会员数据模型
# 修改完模型后:python manage.py db migrate
# 修改完模型后:python manage.py db upgrade
class User(models.Model):
    # 修改表名
    __tablename__ = 'UserModel'
    id = models.Column(models.Integer, primary_key=True)  # 编号
    username = models.Column(models.String(100), unique=True)  # 昵称
    password = models.Column(models.String(100))  # 密码
    desc = models.Column(models.String(128), nullable=True)
  1. 如果继承类,只生成一张Animal表。不生成dog和cat表。dog和cat的字段集成在Animal表中。如果对cat和dog表添加数据。一些字段会默认赋值,数据就混乱了。解决方法见6.
# 如果继承类,只生成一张Animal表。不生成dog和cat表。dog和cat的字段集成在Animal表中。
class Animal(models.Model):
    id = models.Column(models.Integer, primary_key=True)
    u_name = models.Column(models.String(100), unique=True)


class Dog(Animal):
    d_tags = models.Column(models.Integer, default=4)


class Cat(Animal):
    c_tags = models.Column(models.String(32), default='fish')
  1. 降级表,把Animal变成抽象表。然后重新生成表结构。发现生成dog表和cat表
	# 降级表:1. python manage.py db downgrade
	# 降级表:2. 删除对应的表py文件
	# 降级表:3. python manage.py db migrate
	# 降级表:4. python manage.py db upgrade
class Animal(models.Model):
    # Django 中可以把类变成抽象类处理,这里也把类变为抽象类
    __abstract__= True
    id = models.Column(models.Integer, primary_key=True)
    u_name = models.Column(models.String(100), unique=True)


class Dog(Animal):
    d_tags = models.Column(models.Integer, default=4)


class Cat(Animal):
    c_tags = models.Column(models.String(32), default='fish')

2. 项目中数据库优化

  1. 怎么优化
  2. 连接多少次(mysql默认最大连接数目是100个)
  3. 其实无论是Django还是flask都是有数据库连接池的
    • SQLALCHEMY_POOL_SIZE (连接池大小默认5个)
    • SQLALCHEMY_POOL_TIMEOUT 超时时间
    • SQLALCHEMY_POOL_RECYCLE (回收时间默认两小时)

第四节 ORM数据操作

1. 添加数据

  1. 下面导入的models = SQLAlchemy(),也常常把models变为db。
  2. add()添加,add_all()添加多条数据
# 插入单条数据
@blue.route('/adduser')
def adduser():
    user = User()
    user.username = 'root'
    user.password = '123456'
    models.session.add(user)
    models.session.commit()
    print(models.session)
    print(type(models.session))
    return '添加成功'
    
    
@blue.route('/addusers')
def addusers():
    users = []
    for i in range(5):
        user = User()
        user.username = 'bili%d'% i
        user.password = '123456'
        users.append(user)
    models.session.add_all(users)
    models.session.commit()
    return '添加多条成功'

2. 查询数据

2.1 普通查询

  1. 查询数据结果集
  2. 语法: 类名.guery.xxx
  3. 获取单个对象
    • first() 或 first_or_404()
    • get() 或 get_or_404() 只支持id不支持其他字段
  4. 获取结果集
    • all() 比较特殊。返回一个列表
    • filter(类名.属性名.运算符(xxx’)) 返回BaseQuery对象。
    • filter(类名.属性数学运算符值)
      • 魔术方法:eq lt gt ge le
      • 操运算作符: == > <
      • contains startswith endswith in_ like
      • filter_by() offset()偏移 limit() order_ by() paginate()
      • offset和limit不区分顺序,怎么写都按offset先跳过在限制
      • order_by必须在offset和limit之前
    • BaseQuery对象后可以继续加条件,但是list后不可以
    • 所以如果在flask-sqlalchemy使用list, 要放在最后。
@blue.route('/getcat')
def getcat():
    #cats = Cat.query.filter(Cat.id.__gt__(2)).all()
    #cats = Cat.query.filter(Cat.id == (5)).all()
    #cats = Cat.query.filter(Cat.u_name.contains('猫')).all()
    #cats = Cat.query.filter(Cat.id.in_([1, 5, 6])).all()
    #cats = Cat.query.order_by(Cat.id.desc()).all()
    # offset和limit不区分顺序,怎么写都按offset先跳过在限制
    #cats = Cat.query.offset(1).limit(2).all()
    #cats = Cat.query.order_by("id").offset(1).limit(2).all()
    # BaseQuery的__str__方法, 会把它转为sql语句
    #cats = Cat.query.order_by("id").offset(1).limit(2).all()
    cats = Cat.query.filter_by(id=5).all()
    print(cats)
    print(type(cats))
    #render_template('cat.html', cat=cats)
    return "成功"


@blue.route('/getdog')
def getdog():
    from flask import request
    page = request.args.get('page', 1, type=int)
    per_page = request.args.get('per_page', 4, type=int)
    dogs = Dog.query.offset(per_page * (page - 1)).limit(per_page)
    print(dogs)
    print(type(dogs))
    return "成功"


@blue.route('/getdogwithpage/')
def getdogwithpage():
    #dogs = Dog.query.paginate().items
    #render_template('dog.html', dog=cdogs)
    # 传分页器过去而不是数据过去
    pagination = Dog.query.paginate()
    render_template('dog.html', pagination=pagination)

2.2 外键关联

  1. filter_by 通常用在级联数据查询上。直接手动获取如下
# 创建模型
class Customer(models.Model):
    id = models.Column(models.Integer, primary_key=True, autoincrement=True)
    c_name = models.Column(models.String(16))


class Address(models.Model):
    id = models.Column(models.Integer, primary_key=True, autoincrement=True)
    a_position = models.Column(models.String(20))
    a_customer_id = models.Column(models.Integer, models.ForeignKey(Customer.id))
@blue.route('/addcustomer')
def add_customer():
    import random
    costumer = Customer()
    costumer.c_name = '剁手党%d' % random.randrange(1000)
    models.session.add(costumer)
    models.session.commit()
    return "添加成功"


@blue.route('/addaddress')
def add_address():
    import random
    address = Address()
    address.a_position = '上海%d' % random.randrange(1000)
    address.a_customer_id = Customer.query.order_by(Customer.id.desc()).first().id
    models.session.add(address)
    models.session.commit()
    return "添加成功"


@blue.route('/get_customer')
def get_customer():
    # 获取id=1的地址的客户
    address = Address.query.get_or_404(1)
    customer = Customer.query.get(address.a_customer_id)
    return customer.c_name


@blue.route('/get_addr/')
def get_addr():
    # 客户1的所有地址
    customer = Customer.query.get(1)
    addresses = Address.query.filter_by(a_customer_id=customer.id)
    for addr in addresses:
        print(addr.a_position)
    return '获取成功'
  1. 使用关系Relationships获取: relationship 通过customer直接获取得到一个列表(address = models.relationship(‘Address’, backref=‘customer’, lazy=True))
class Customer(models.Model):
    id = models.Column(models.Integer, primary_key=True, autoincrement=True)
    c_name = models.Column(models.String(16))
    address = models.relationship('Address', backref='customer', lazy=True)


class Address(models.Model):
    id = models.Column(models.Integer, primary_key=True, autoincrement=True)
    a_position = models.Column(models.String(20))
    a_customer_id = models.Column(models.Integer, models.ForeignKey(Customer.id))
@blue.route('/get_addr/')
def get_addr():
    # 客户1的所有地址
    customer = Customer.query.get(1)
    #addresses = Address.query.filter_by(a_customer_id=customer.id)
    # relationship 通过customer直接获取得到一个列表
    addresses = customer.address
    print(addresses)
    for addr in addresses:
        print(addr.a_position)
    return '获取成功'
  1. 关系
    • 一对一:ForeignKey+Unique
    • 一对多:ForeignKey
    • M*N多对多:额外关系表 ForeignKey+ForeignKey
    • 一对一多对多 项目中不建议使用。自己手动维护官网也有生成中间表的写法。

2.3 逻辑运算

  1. 与 and_ filter(and_ (条件),条件…)
  2. 或 or_ filter(or_ (条件),条件…)
  3. 非 not_ filter(not_ (条件),条件…)
@blue.route('/get_addrwithconn/')
def get_addrwithconn():
    from sqlalchemy import and_,or_,not_
    #addresses = Address.query.filter(Address.a_customer_id.__eq__(1)).filter(Address.a_position.endswith('5'))
    # 逻辑符号and_
    #addresses = Address.query.filter(and_(Address.a_customer_id.__eq__(1), Address.a_position.endswith('5')))
    # 逻辑符号or_
    #addresses = Address.query.filter(or_(Address.a_customer_id.__eq__(1), Address.a_position.endswith('5')))
    # 逻辑符号not_
    #addresses = Address.query.filter(not_(Address.a_customer_id.__eq__(1)))
    addresses = Address.query.filter(not_(or_(Address.a_customer_id.__eq__(1), Address.a_position.endswith('5'))))
    print(addresses)
    for addr in addresses:
        print(addr.a_position)
    #return render_template('Address.hmtl', addresses=addresses)
    return '获取成功'

3. 删除修改数据

  1. 删除数据。delete
  2. models.session.delete() models.session.commit()
  3. 修改数据。add重新保存
@blue.route('/deleteuser')
def deleteuser():
    user = User.query.first()
    models.session.delete(user)
    models.session.commit()
    return '删除数据成功'


@blue.route('/updateuser')
def updateuser():
    user = User.query.first()
    user.username = 'root'
    # 修改数据后重新保存
    models.session.add(user)
    models.session.commit()
    return '修改数据成功'

第五节 缓存查询flask-caching

  1. 低版本的flask用flask-cache
  2. 高版本的flask用flask-caching(功能一样,都是做数据缓存的。重复请求从缓存中读数据).说明文档可能被墙。
  3. pip install flask-caching
  4. 导包from flask_caching import Cache
  5. 配置:可以配置null, simple, redis, memcached,filesystem
cache = Cache(config={
    "CACHE_TYPE": "simple"
})
  1. 注册cache.init_app(app=app)
  2. 使用如下
@blue.route('/get_addrwithconn/')
@cache.cached(timeout=60)
def get_addrwithconn():
    from sqlalchemy import not_,  or_
    addresses = Address.query.filter(not_(or_(Address.a_customer_id.__eq__(1), Address.a_position.endswith('5'))))
    print(addresses)
    print('从数据库中查询')
    for addr in addresses:
        print(addr.a_position)
    #return render_template('Address.hmtl', addresses=addresses)
    return '获取成功'
发布了61 篇原创文章 · 获赞 8 · 访问量 2811

猜你喜欢

转载自blog.csdn.net/aa18855953229/article/details/104176445