• Flask-SQLAlchemy 与 SQL Alchemy 的区别、联系


    最近看项目,又是sqlalchemy,又有flask_sqlalchemy,两者的一些用法差点搞混了。这里总结一下。


    一、SQL Alchemy

    SQL Alchemy是python中最著名的ORM(Object Relationship Mapping)框架。ORM:对象关系映射。即将用户定义的Python类与数据库表相关联,并将这些类(对象)的实例与其对应表中的行相关联。


    1. SQL Alchemy 基本操作

    1.1 连接数据库

    from sqlalchemy import create_engine
    
    # 创建数据库引擎
    engine = create_engine("mysql+pymysql://root:123456@127.0.0.1:3306/my_db?charset=utf8mb4")
    
    

    create_engine()函数中的字符串的意义是,数据库+数据库连接框架://用户名:密码@IP地址:端口号/数据库名称?连接参数。

    解释:

    连接mysql数据库,采用的pymysql框架连接(当然还有其他的连接框架),登陆数据库的用户和密码是root和123456,mysql数据库系统地址时127.0.0.1:3306,连接的具体数据库是my_db,并设置了字符编码是utf8mb4。

    1.2 声明映射(建立数据库表的模型)

    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import Column, Integer, String
    
    # 声明性基类
    Base = declarative_base()
    
    # 构建数据库表的模型类
    class User(Base):
        __tablename__ = 'users'
    
        id = Column(Integer, primary_key=True)
        name = Column(String)
        fullname = Column(String)
    
        # 这个是可选的方法,这里自定义在显示User对象时的格式
        def __repr__(self):
            return "<User(name='%s', fullname='%s', nickname='%s')>" % (
                                 self.name, self.fullname, self.nickname)
    
    

    解释:

    使用Declarative系统映射的类是根据基类定义的,该基类维护相对于该基类的类和表的目录 - 这称为声明性基类。我们的应用程序通常在一个常用的模块中只有一个这个基础的实例。我们使用declarative_base() 函数创建基类。

    __tablename__变量声明了在根据这个类创建表时表的名字。

    现在我们有了一个类“Base”,我们可以根据它定义任意数量的映射类。上面我们根据它定义了一个users表,表中含有字段id、name、fullname

    1.3 创建映射类的实例

    
    user1 = User(name='ed', fullname='Ed Jones')
    user2 = User(name='ed2', fullname='Ed2 Jones2')
    
    

    1.4 创建会话

    上面我们创建了连接数据库的引擎,这里需要引擎来创建一个session,后面才能通过session与数据库进行交互。

    
    Session = sessionmaker(engine)
    db_session = Session()
    
    

    1.5 单表的增删改查

    from sqlalchemy.orm import sessionmaker
    from sqlalchemy import create_engine
    from Model import User
    
    # 通常我们把数据库表模型统一放到一个模块里,所以这里需要导入
    
    # 准备工作
    engine = create_engine("mysql+pymysql://root:123456@127.0.0.1:3306/SQLAlchemy_Pro?charset=utf8mb4")
    
    Session = sessionmaker(engine)
    db_session = Session()
    
    # 1. 增加数据add(创建表结构的类名(字段名=添加的数据))
    db_session.add(User(name="ZWQ", fullname="ZWQ zzzzz"))  # 相当于建立一条添加数据的sql语句
    db_session.commit()  # 执行
    
    # 批量添加
    user1 = User(name='ed', fullname='Ed Jones')
    user2 = User(name='ed2', fullname='Ed2 Jones2')
    db_session.add_all([user1, user2])
    db_session.commit()
    
    
    # 2.查询 query(表结构的类名)
    res = db_session.query(User)
    print(res)  # 直接翻译输出对应的SQL查询语句
    
    res = db_session.query(User).all()  # 返回表中所有数据对象
    print(res)
    
    
    for u in res:
        print(u.id, u.name, u.fullname)
    
    res = db_session.query(Users).first()  # 取第一个,返回是对象
    print(res.id, res.name)
    
    res = db_session.query(User).filter(Users.id == 3).first()  # 返回符合条件查询结果
    print(res.name)
    
    res = db_session.query(User).filter(User.id <= 2, User.name == "ZWQ").all() # filter中的条件可以是模糊条件,多个条件
    for u in res:
        print(u.id,u.name)
    
    # 3.更改数据 update({k:v})
    res = db_session.query(Users).filter(Users.id == 1).update({"name":"DragonFire"})
    print(res)
    db_session.commit()
    
    res = db_session.query(User).update({"name":"ZWQ"})  # 全部修改,返回修改的数据个数
    print(res)
    db_session.commit()
    
    # 4.删除 delete()结合查询条件删除
    res = db_session.query(User).filter(User.id == 1).delete()  # 删除否合条件的数据,返回删除数量
    print(res)
    db_session.commit()
    
    res = db_session.query(User).delete()  # 删除表中所有数据,返回删除数量
    print(res)
    db_session.commit()
    
    # 关闭session
    db_session.close()
    
    

    回滚:如果我们通过db_session.add()不小心把错误的信息添加进去了,可以使用de_session.rollback()回滚操作。

    2. SQL Alchemy之(一对多)(多对多)

    参考文章:

    https://blog.csdn.net/tianpingxian/article/details/82720442

    看见了一片不错的文章,就不自己写了。当个参考好了。这篇文章有一对多,多对一,单向多对多(我有点懵),双向多对多,以及他们的查询等等,很详细。


    二、Flask-SQLAlchemy

    Flask-SQLAlchemy 是一个为您的 Flask 应用增加 SQLAlchemy 支持的扩展。它需要 SQLAlchemy 0.6 或者更高的版本。它致力于简化在 Flask 中 SQLAlchemy 的使用,提供了有用的默认值和额外的助手来更简单地完成常见任务。


    1. Flask-SQLAlchemy基本操作

    1.1 一个简单的示例:

    
    from flask import Flask
    from flask_sqlalchemy import SQLAlchemy
    
    # 实例化SQLAlchemy
    db = SQLAlchemy()
    # PS : 实例化SQLAlchemy的代码必须要在引入蓝图之前
    
    app = Flask(__name__)
    
    # 配置数据库连接
    app.config[”SQLALCHEMY_DATABASE_URI“] = “mysql+pymysql://root:123456@127.0.0.1:3306/SQLAlchemy_Pro?charset=utf8mb4”
    
    # 初始化SQLAlchemy , 本质就是将以上的配置读取出来
    db.init_app(app)
    
    # 一个简单的模型
    class User(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        username = db.Column(db.String(80), unique=True)
        email = db.Column(db.String(120), unique=True)
    
        def __init__(self, username, email):
            self.username = username
            self.email = email
    
        def __repr__(self):
            return '<User %r>' % self.username
    
    # 根据模型在数据库中生成相应的表
    db.create_all()
    
    

    1.2 简单的增删改查

    # 导入模型
    from your_application import User
    
    
    # 创建数据
    admin = User('admin', 'admin@example.com')
    guest = User('guest', 'guest@example.com')
    
    
    # 写入到数据库表中
    db.session.add(admin)
    db.session.add(guest)
    db.session.commit()
    
    # 查询
    users = User.query.all()
    # [<User u'admin'>, <User u'guest'>]
    
    admin = User.query.filter_by(username='admin').first()
    # <User u'admin'>
    
    

    2. Flask-SQLAlchemy的(一对多)(多对多)

    2.1 一对多(one-to-many)关系

    
    class Person(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(50))
        addresses = db.relationship('Address', backref='person',
                                    lazy='dynamic')
    
    class Address(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        email = db.Column(db.String(50))
        person_id = db.Column(db.Integer, db.ForeignKey('person.id'))
    
    

    **db.relationship() ** 这个函数返回一个可以做许多事情的新属性。在本案例中,我们让它指向 Address 类并加载多个地址。它如何知道会返回不止一个地址?因为 SQLALchemy 从您的声明中猜测了一个有用的默认值。 如果您想要一对一关系,您可以把 uselist=False 传给 relationship() 。

    backref 是一个在 Address 类上声明新属性的简单方法。您也可以使用 my_address.person 来获取使用该地址(address)的人(person)。lazy 决定了 SQLAlchemy 什么时候从数据库中加载数据它的值有:

    • 'select' :(默认值) 就是说 SQLAlchemy 会使用一个标准的 select 语句必要时一次加载数据。
    • 'joined' :告诉 SQLAlchemy 使用 JOIN 语句作为父级在同一查询中来加载关系。
    • 'subquery' :类似 'joined' ,但是 SQLAlchemy 会使用子查询。
    • 'dynamic' :不直接加载这些数据,SQLAlchemy 会返回一个查询对象,在加载数据前您可以过滤(提取)它们。

    详细用法参见:(Flask - SQLalchemy 之 lazy 属性)[https://www.jianshu.com/p/8427da16729a]

    为反向引用(backrefs)定义惰性(lazy)状态:使用 backref() 函数:

    
    class User(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(50))
        addresses = db.relationship('Address', backref=db.backref('person', lazy='joined'), lazy='dynamic')
    
    

    2.2 多对多(many-to-many)关系

    如果想要用多对多关系,需要定义一个用于关系的辅助表。对于这个辅助表, 强烈建议不使用模型,而是采用一个实际的表:

    
    # 辅助表
    post_tag = db.Table('post_tag',
        db.Column('tag_id', db.Integer, db.ForeignKey('tag.id')),
        db.Column('post_id', db.Integer, db.ForeignKey('post.id'))
    )
    
    # 文章模型
    class Post(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        title = db.Column(db.String(100), nullable = False)
        # 假如拿到了一个标签Tag,怎么拿到标签下的所有文章呢.反向引用Article这时用backref
        tags = db.relationship('Tag', secondary=post_tag, backref=db.backref('posts', lazy='dynamic'))
    
    # 标签模型
    class Tag(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(100), nullable = False)
    
    

    其他操作:

    
    article1 = Post(title = 'aaa')
    article2 = Article(title = 'bbb')
    tag1 = Tag(name = '111')
    tag2 = Tag(name = '222')
    
    #实现多对多关系,一个post有两个标签
    article1.tags.append(tag1)
    article1.tags.append(tag2)
    article2.tags.append(tag1)
    article2.tags.append(tag2)
    
    # 增加
    db.session.add(article1)
    db.session.add(article2)
    db.session.add(tag1)
    db.session.add(tag2)
    
    db.session.commit()
    
    # 查询
    article1 = Post.query.filter(Post.title == 'aaa').first()
    
    tags = article1.tags
    for tag in tags:
        print(tag.name)
    
    
  • 相关阅读:
    将元素平分成差值最小的两个集合(DP)
    新年趣事之打牌(01背包+唯一路径)
    offer(背包问题、DP)
    整数划分(完全背包)
    饭卡(DP)
    等和的分隔子集(dp)
    LaunchPad(思维)
    The flower(寻找出现m次以上,长度为k的子串)
    Morse code(多模式串匹配)
    平分娃娃(多重背包+二进制枚举)
  • 原文地址:https://www.cnblogs.com/ChangAn223/p/11272532.html
Copyright © 2020-2023  润新知