zoukankan      html  css  js  c++  java
  • 数据模型

    # 数据模型
    
    ### 数据库回顾
    
    - 分类:
      - 关系型数据库:MySQL、sqlite、...
      - 非关系型数据库:Redis、MongoDB、...
    - 操作:
      - 执行原生SQL语句,没都需要拼接SQL语句,而且很容易出错。
      - ORM操作,使用ORM可以通过直接操作对象来完成对数据的操作。
    
    ### flask-sqlalchemy
    
    - 说明:提供了绝大多数关系型数据库的支持,而且提供了ORM(对象关系映射)。
    
    - 安装:`pip install flask-sqlalchemy`
    
    - 连接地址配置:
    
      - 名称:`SQLALCHEMY_DATABASE_URI`
      - 格式:
        - MySQL:`dialect+driver://username:password@host:port/database`
        - sqlite:`sqlite:/// + 数据库文件地址`
    
    - 使用:
    
      ```python
      from flask_sqlalchemy import SQLAlchemy
      import os
    
      # 当前文件所在目录
      base_dir = os.path.abspath(os.path.dirname(__file__))
      database_uri = 'sqlite:///' + os.path.join(base_dir, 'data.sqlite')
      # 配置数据库连接地址
      app.config['SQLALCHEMY_DATABASE_URI'] = database_uri
    
      # 创建数据库操作对象
      db = SQLAlchemy(app)
    
      # 设计数据模型
      class User(db.Model):
          # 表名默认是将数据模型类名转换为小写加下划线的风格
          # 如:UserModel => user_model
          # 用于指定表名
          __tablename__ = 'users'
          id = db.Column(db.Integer, primary_key=True)
          name = db.Column(db.String(20), unique=True)
          email = db.Column(db.String(50), unique=True)
      ```
    
    - 管理:
    
      ```python
      @app.route('/create/')
      def create():
          # 创建所有的表
          db.create_all()
          return '数据表已创建'
    
      @app.route('/drop/')
      def drop():
          # 删除用户数据表
          db.drop_all()
          return '数据表已删除'
    
      # 向终端添加命令创建数据表
      @manager.command
      def createall():
          # 先删除原来的数据表
          db.drop_all()
          # 然后再创建
          db.create_all()
          return '数据表已创建'
    
      # 向终端添加命令删除数据表
      def dropall():
          # 删库前给出用户提示信息
          if prompt_bool('您确定要删库跑路吗?'):
              db.drop_all()
              return '数据表已删除'
          return '删库有风险,操作需谨慎'
      ```
    
      > 说明:通过装饰器(@manager.command)修改的函数名就是终端的命令。
      >
      > 使用:python manage.py createall,就可以根据数据模型创建数据表
      >
      > 提示:若创建时数据表已经存在则会失败,可以通过先删除再创建的方式解决,只是副作用有点大。
    
    ### 数据库迁移
    
    - 说明:数据模型的更改应用到数据表中的操作叫数据库迁移。flask-migrate扩展就是专门用来数据库迁移的。
    
    - 安装:`pip install flask-migrate`
    
    - 使用:
    
      ```python
      # 导入类库
      from flask_migrate import Migrate, MigrateCommand
    
      # 创建数据库迁移对象
      migrate = Migrate(app, db)
    
      # 将数据库迁移命令添加到终端
      manager.add_command('db', MigrateCommand)
      ```
    
    - 迁移:
    
      - 初始化,只需要一次,创建一个目录用于存放迁移脚本
    
      ```shell
      python manage.py db init
      ```
    
      - 根据模型与数据表,生成迁移脚本
    
      ```shell
      python manage.py db migrate
      ```
    
      - 执行迁移脚本
    
      ```shell
      python manage.py db upgrade
      ```
    
    - 提示:
    
      - 初始化只需要一次,以后生成迁移脚本,然后执行迁移脚本循环操作即可。
      - 不是每次迁移都会成功,迁移出错时需要手动解决。
    
    ### 数据的CURD
    
    - 增加数据
    
      ```python
      # 设置自动提交操作,每次请求结束会自动提交操作
      app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
      # 禁止追踪数据的更改,会销毁额外的性能
      app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    
      @app.route('/insert/')
      def insert():
          # 创建对象
          # ming = User(name='ming', email='ming@163.com')
          # dong = User(name='dong', email='dong@163.com')
          # 保存单条数据到数据库
          # db.session.add(dong)
    
          yujie = User(name='yujie', email='yujie@163.com')
          baoxi = User(name='baoxi', email='baoxi@163.com')
          long = User(name='long', email='long@163.com')
          # 保存多条数据到数据库
          db.session.add_all([yujie, baoxi, long])
    
          # 提交操作
          # db.session.commit()
          return '数据已添加'
      ```
    
    - 查询数据
    
      ```python
      @app.route('/select/<uid>/')
      def select(uid):
          # 根据主键查询,查到返回对象,没有查到返回None
          u = User.query.get(uid)
          if u:
              return u.name
          return '查无此人'
      ```
    
    - 修改数据
    
      ```python
      @app.route('/update/<uid>/')
      def update(uid):
          u = User.query.get(uid)
          if u:
              u.email = 'xxx@163.com'
              # 下面这句是再次保存,ORM会自动区分更新和插入
              db.session.add(u)
              return '数据已修改'
          return '查无此人'
      ```
    
    - 删除数据
    
      ```python
      @app.route('/delete/<uid>/')
      def delete(uid):
          u = User.query.get(uid)
          if u:
              # 删除数据
              db.session.delete(u)
              return '数据已删除'
          return '查无此人'
      ```
    
    ### 模型设计参考
    
    - 常见字段类型
    
      | 类型名          | python类型           | 说明                   |
      | ------------ | ------------------ | -------------------- |
      | Integer      | int                | 整型(32)               |
      | SmallInteger | int                | 整型(16)               |
      | BigInteger   | int/long           | 整型(64)               |
      | Float        | float              | 浮点数                  |
      | String       | str                | 变长字符串                |
      | Text         | str                | 不受限制的文本              |
      | Boolean      | bool               | 布尔值,只有True/False     |
      | Date         | datetime.date      | 日期                   |
      | Time         | datetime.time      | 时间                   |
      | Datetime     | datetime.datetime  | 日期时间                 |
      | Interval     | datetime.timedelta | 时间间隔                 |
      | PickleType   | pikcle.dumps()     | 使用pickle处理后的python对象 |
      | LargeBinary  | bytes              | 任意大的二进制数据            |
    
    - 常见字段选项
    
      | 选项            | 说明                |
      | ------------- | ----------------- |
      | primary_key   | 是否作为主键索引,默认为False |
      | autoincrement | 是否设置字段自增,默认为False |
      | unique        | 是否作为唯一索引,默认为False |
      | index         | 是否作为普通索引,默认为False |
      | nullable      | 字段是否可以为空,默认为True  |
      | default       | 设置默认值             |
    
    - 总结:
    
      - 插入数据可以不传值的字段:自增的主键、有默认值的、可以为空的
      - 使用flask-sqlalchemy时要求每个模型都有一个主键,默认名字为id
      - 模型类名与数据表中的名字
        - 默认:将大驼峰格式的模型类名,转换为小写加下划线格式,如:`UserModel => user_model`
        - 指定:`__tablename__`,使用此类属性指定表名
    
    ### 各种查询
    
    - 说明:绝大多数的数据库操作都是查询,这些操作都是通过方法来体现的。
    
    - 常见操作:
    
      | 方法           | 说明                              |
      | ------------ | ------------------------------- |
      | get          | 根据主键进行查询,查到返回对象,没查到返回None       |
      | get_or_404   | 功能同上,查不到时,直接报404错               |
      | all          | 查询所有数据,返回一个列表(元素全是对象)           |
      | first        | 返回第一条数据,没有时返回None               |
      | first_or_404 | 功能同上,查不到时报404错                  |
      | limit        | 限制结果集数量,返回查询对象,可以继续进行链式查询操作     |
      | offset       | 设置偏移量,返回查询对象,可以继续进行链式查询操作       |
      | order_by     | 结果集排序,可以指定多个字段,asc升序(默认),desc降序 |
      | count        | 统计总数                            |
    
    - 聚合函数
    
      - 说明:`max、min、sum、avg、count`
      - 示例:
    
      ```python
      from sqlalchemy import func
    
      # 求最大值
      max_age = db.session.query(func.max(User.age)).scalar()
      return str(max_age)
      ```
    
    - 指定条件查询
    
      ```python
      # 等值条件查询
      users = User.query.filter_by(age=18).all()
      # 指定任意条件查询
      users = User.query.filter(User.age > 20).all()
      return ','.join(u.name for u in users)
      ```
    
    ### filter条件查询
    
    - 关系
    
      ```python
      >,    __gt__
      如:
          users = User.query.filter(User.age > 20).all()
          # 与上面等价
          users = User.query.filter(User.age.__gt__(20)).all()
      >=,    __ge__
      <,    __lt__
      <=, __le__
      ==,    __eq__
      !=, __ne__
      ```
    
    - 范围
    
      ```python
      # users = User.query.filter(User.id.between(1, 3)).all()
      # users = User.query.filter(User.id.in_((1, 3, 5))).all()
      users = User.query.filter(User.id.notin_((1, 3, 5))).all()
      ```
    
    - 内容
    
      ```
      startswith:以什么内容开头
      endswith:以什么内容结尾
      contains:包含什么内容
      like:模糊匹配
      notlike:模糊匹配相反的条件
      ```
    
    - 逻辑
    
      ```python
      from sqlalchemy import and_, or_
    
      # 默认就是逻辑与
      # users = User.query.filter(User.id > 2, User.age > 20).all()
      # 与上式等价
      # users = User.query.filter(and_(User.id > 2, User.age > 20)).all()
      # 逻辑或
      users = User.query.filter(or_(User.id > 2, User.age > 20)).all()
      ```
    
      ​
  • 相关阅读:
    db2 v11 安装测试
    DB2支持的三种表空间SMS、DMS、DMS的自动存储
    linux几种快速清空文件内容的方法
    修改文件或者文件夹权限
    db2start启动失败
    db2icrt创建实例,提示主机名无效
    浏览器内核以及在各个浏览器的前缀
    程序的三大结构(顺序结构、选择结构、循环结构)
    数组中元素的排序(常用的冒泡排序、选择排序、快速排序)
    数组的api以及api的简单使用
  • 原文地址:https://www.cnblogs.com/liangliangzz/p/10222007.html
Copyright © 2011-2022 走看看