newLion  

1. 什么是ORM

  对象关系映射(Object Relational Mapping,简称ORM)是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中。

  它的作用是在关系型数据库和对象之间作一个映射,这样,我们在具体的操作数据库的时候,就不需要再去和复杂的SQL语句打交道,只要像平时操作对象一样操作它就可以了 。

  持久(Persistence),即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的数据存储在关系型的数据库中,当然也可以存储在磁盘文件中、XML数据文件中等等。

  持久层(Persistence Layer),即专注于实现数据持久化应用领域的某个特定系统的一个逻辑层面,将数据使用者和数据实体相关联。

2. flask-sqlalchemy

    Flask-SQLAlchemy 是一个Flask 扩展,简化了在Flask 程序中使用SQLAlchemy 的操作。SQLAlchemy 是一个很强大的关系型数据库框架,支持多种数据库后台。

    SQLAlchemy 提供了高层ORM,也提供了使用数据库原生SQL 的低层功能。

3. flask-sqlalchemy配置

  数据库URI :SQLALCHEMY_DATABASE_URI

  URI参数格式:

        Postgres:postgresql://scott:tiger@localhost/mydatabase

        MySQL:mysql://scott:tiger@localhost/mydatabase

        Oracle: oracle://scott:tiger@127.0.0.1:1521/sidname

        SQLite:sqlite:////absolute/path/to/foo.db

  

  多个数据库支持 :

          SQLALCHEMY_BINDS = {

            'db1': 'mysqldb://localhost/users',

            'db2': 'sqlite:////path/to/appmeta.db'

          }

4. 数据库模型设计

  绑定到Flask对象 :db = SQLAlchemy(app)

  ORM模型创建:

          class User(db.Model):

            id = db.Column(db.Integer, primary_key=True)

  指定表的名称:__tablename__ = 'mall_product'

  创建和删除表

    手动创建数据库: 

      创建表 :db.create_all(bind=‘db1’)

      删除表: db.drop_all()

    数据库迁移框架:Flask 程序还可使用Flask-Migrate扩展。这个扩展对SQLAlchemy中的Alembic 做了轻量级包装,并集成到Flask-Script 中,所有操作都通过Flask-Script 命令完成。

      创建迁移仓库:

        配置Flask-Migrate:

          migrate = Migrate(app, db)

          manager.add_command('db', MigrateCommand)

        使用init 子命令创建迁移仓库:

          python xxx.py db init

      创建迁移脚本:自动创建的迁移会根据模型定义和数据库当前状态之间的差异生成upgrade() 和downgrade() 函数的内容。

        migrate 子命令用来自动创建迁移脚本:

          python xxx.py db migrate -m "initial migration"

      更新数据库:

        python xxx.py db upgrade 

  ORM模型字段类型支持

    

  一对多关系,外键关联

    addresses = db.relationship('UserAddress', backref='person', lazy=True)

    大多数情况下,db.relationship() 都能自行找到关系中的外键,但有时却无法决定把哪一列作为外键,如果无法决定外键,你就要为db.relationship() 提供额外参数,从而确定所用外键。

    backref :在关系的另一个模型中添加反向引用 

    lazy : 指定如何加载相关记录。可选值有select(首次访问时按需加载)、immediate(源对象加载后就加载)、joined(加载记录,但使用联结)、subquery(立即加载,但使用子查询),

        noload(永不加载)和dynamic(不加载记录,但提供加载记录的查询) 

    secondary:指定多对多关系中关系表的名字

    order_by: 指定关系中记录的排序方式

  多对多关联

    tags = db.Table('mall_product_tags',db.Column('tag_id', db.Integer, db.ForeignKey('tag.id')), db.Column('product_id', db.Integer,db.ForeignKey('product.id')) )

5. 使用ORM入,修改,删除数据

  新增/修改数据

    构造ORM模型对象:

      user = User('admin', 'admin@example.com')

    添加到db.session(备注:可添加多个对象):

      db.session.add(user)

    提交到数据库:

      db.session.commit()

  物理删除数据

    查询ORM模型对象

      user=User.query.filter_by(username='zhangsan').first()

    添加到db.session

      db.session. delete(user)

    提交到数据库

      db.session.commit()

6. 使用ORM询数据并展示

  ORM查询

    返回结果集(list)

      查询所有数据

        User.query.all()

      按条件查询

        User.query.filter_by(username='zhangsan') User.query.filter(User.nicknae.endswith('三')).all()

      排序

        User.query.order_by(User.username)

      查询TOP10

        User.query.limit(10).all()

    返回单个ORM对象

      根据pk查询

        User.query.get(1)

      获取第一条记录

        User.query.first()

    视图快捷函数: 有则返回,无则返回404

      first() vs first_or_404()

      get() vs get_or_404()

    多表关联查询

      db.session.query(User).join(Address)

      User.query.join(Address)

7. 分页

  方式一:使用offset 和limit

    .offset(offset).limit(limit)

  方式二:paginate分页支持

    .paginate(page=2, per_page=4)返回Pagination的对象

  Pagination对象

    has_prev/has_next——是否有上一页/下一页

    items——当前页的数据列表

    prev_num/next_num——上一页/下一页的页码

    total——总记录数

    pages——总页数

8. 结合模板实现分页

  第一步:准备数据

    list_user = User.query.filter_by(is_valid=1)

  第二步:分页

    list_user.paginate(page=2, per_page=4)

  第三步:在模板中实现分页操作

 

实战:ORM的使用

以上介绍关键代码:

flasker.py:

from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
# 配置数据库的连接参数
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:woxiangni55@127.0.0.1/test_flask'
db = SQLAlchemy(app)


class User(db.Model):
    """ 用户ID """
    __tablename__ = 'weibo_user'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), nullable=False)
    password = db.Column(db.String(255), nullable=False)
    birth_date = db.Column(db.Date, nullable=True)
    age = db.Column(db.Integer, default=0)

class UserAddress(db.Model):
    """ 用户地址 """
    __tablename__ = 'weibo_user_addr'

    id = db.Column(db.Integer, primary_key=True)
    addr = db.Column(db.String(64), nullable=False)

    user_id = db.Column(db.Integer, db.ForeignKey('weibo_user.id'), nullable=False)
    user = db.relationship('User', backref=db.backref('address', lazy=True))

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/user/<int:page>/')
def page_user(page):
    """ 分页操作 """
    page_size = 10   # 每一页10条数据
    page_data = User.query.paginate(page=page, per_page=page_size)
    return render_template('page_user.html', page_data=page_data)

 page_user.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户分页操作</title>
</head>
<body>
    <h3>总共有数据{{ page_data.total }}; 总页数{{ page_data.pages }}</h3>
    <ul>
        {% for user in page_data.items %}
        <li>{{ user.username }}-{{ user.password }}</li>
        {% endfor %}
    </ul>
    {% if page_data.has_prev %}
    <a href="{{ url_for('page_user', page=page_data.prev_num) }}">上一页</a>
    {% endif %}
    {% if page_data.has_next %}
    <a href="{{ url_for('page_user', page=page_data.next_num) }}">下一页</a>
    {% endif %}
</body>
</html>

 

 

下图数据库模型设计:

商品、分类、标签模型如下:

class Tag(db.Model):
    """ 商品标签 """
    __tablename__ = 'product_tag'
    id = db.Column(db.Integer, primary_key=True)  # 主键
    # UID
    uid = db.Column(db.String(128), nullable=False, default=uuid.uuid4, unique=True)
    # 标签名称
    name = db.Column(db.String(128), nullable=False)
    # 标签编码
    code = db.Column(db.String(32))
    # 标签的描述
    desc = db.Column(db.String(256))
    # 逻辑删除
    is_valid = db.Column(db.Boolean, default=True)
    # 排序
    reorder = db.Column(db.Integer, default=0)
    # 创建时间
    created_at = db.Column(db.DateTime)
    # 最后修改的时间
    updated_at = db.Column(db.DateTime)


class Classify(db.Model):
    """ 商品分类 """
    __tablename__ = 'product_classify'
    id = db.Column(db.Integer, primary_key=True)  # 主键
    # UID
    uid = db.Column(db.String(128), nullable=False, default=uuid.uuid4, unique=True)
    # 关联父级的ID
    parent_id = db.Column(db.Integer, db.ForeignKey('product_classify.id'))
    img = db.Column(db.String(256))
    # 分类名称
    name = db.Column(db.String(128), nullable=False)
    # 分类编码
    code = db.Column(db.String(32))
    # 分类的描述
    desc = db.Column(db.String(256))
    # 逻辑删除
    is_valid = db.Column(db.Boolean, default=True)
    # 排序
    reorder = db.Column(db.Integer, default=0)
    # 创建时间
    created_at = db.Column(db.DateTime)
    # 最后修改的时间
    updated_at = db.Column(db.DateTime)


class Product(db.Model):
    """ 商品类 """
    __tablename__ = 'product'
    id = db.Column(db.Integer, primary_key=True)  # 主键
    # UID
    uid = db.Column(db.String(128), nullable=False, default=uuid.uuid4, unique=True)
    # 商品标题
    name = db.Column(db.String(128), nullable=False)
    # 商品描述(富文本)
    content = db.Column(db.Text, nullable=False)
    # 商品推荐语
    desc = db.Column(db.String(256))
    # 类型
    types = db.Column(db.Enum('实物商品', '虚拟商品'))
    # 价格
    price = db.Column(db.Integer, nullable=False)
    # 原价¥
    origin_price = db.Column(db.Float)
    # 主图
    img = db.Column(db.String(256), nullable=False)
    # 渠道
    channel = db.Column(db.String(32))
    # 链接
    buy_link = db.Column(db.String(256))
    # 商品状态
    status = db.Column(db.Enum('销售中', '已售完', '未开始'))
    # 库存
    sku_count = db.Column(db.Integer, default=0)
    # 剩余库存
    remain_count = db.Column(db.Integer, default=0)
    # 浏览次数
    view_count = db.Column(db.Integer, default=0)
    # 评分
    score = db.Column(db.Float, default=10)

    # 逻辑删除
    is_valid = db.Column(db.Boolean, default=True)
    # 排序
    reorder = db.Column(db.Integer, default=0)
    # 创建时间
    created_at = db.Column(db.DateTime)
    # 最后修改的时间
    updated_at = db.Column(db.DateTime)


class ProductClasses(db.Model):
    """ 商品与分类的关系 """
    __tablename__ = 'product_classify_rel'

    id = db.Column(db.Integer, primary_key=True)  # 主键
    product_id = db.Column(db.Integer, db.ForeignKey('product.id'))
    cls_id = db.Column(db.Integer, db.ForeignKey('product_classify.id'))


class ProductTags(db.Model):
    """ 商品与标签的关系 """
    __tablename__ = 'product_tag_rel'

    id = db.Column(db.Integer, primary_key=True)  # 主键
    product_id = db.Column(db.Integer, db.ForeignKey('product.id'))
    tag_id = db.Column(db.Integer, db.ForeignKey('product_tag.id'))

 

posted on 2021-07-07 09:51  newLion  阅读(209)  评论(0编辑  收藏  举报