精华内容
下载资源
问答
  • sqlalchemy用法
    千次阅读
    2018-09-10 05:57:46

     

    一,SQLAlchemy的安装 
    使用

    $ easy_install sqlalchemy
    或
    $ pip install sqlalchemy

    如果出现什么错,就进去root用户下进行安装试试,或者网上查查

    >>> import sqlalchemy
    >>> 
    • 这样说明成功了,切记是小写哦 
      二,使用 
      理论我也不懂,自己查查资料,现在用一个小的案例说一下使用步骤 
      1,在进行数据操作之前要先连上数据库。
    >>> from sqlalchemy import create_engine
    >>> from sqlalchemy.orm import sessionmaker  
    >>> DB_CONNECT = 'mysql+mysqldb://root:102@localhost/mydb'
    >>> engine = create_engine(DB_CONNECT, echo=True)
    >>> DB_Session = sessionmaker(bind=engine)
    >>> session = DB_Session()
    

    from 是从sqlalchemy中插入必须的模板,DB_CONNECT 是构造数据库的路径 ,mysql+mysqldb是说明使用MySQL-Python 来连接,root是数据库用户名,102是密码,localhost表示是数据库在本机上,mydb是要连接的数据库名字,设置字符集的charset可以省了 
    create_engine() 会返回一个数据库引擎,echo 参数为 True 时,会显示每条执行的 SQL 语句,生产环境下可关闭。 
    sessionmaker(bind=engine)会生成一个数据库会话类。这个类的实例可以当成一个数据库连接,它同时还记录了一些查询的数据,并决定什么时候执行 SQL 语句。由于 SQLAlchemy 自己维护了一个数据库连接池(默认 5 个连接),也可以自己设置。 
    得到session 后,就可以执行 SQL 了: 
    2,在进行操作前先把表给建立了,由于SQLAlchemy 可以和变进行建立连接并且可以通过语言进行见表

    mysql> show tables;
    Empty set (0.00 sec)
    mysql> 

    此时是没有表的,现在我们建立一个学生便stu,一个课程表cla和一个成绩表grade

    >>> from sqlalchemy import Column
    >>> from sqlalchemy.types import CHAR, Integer, String
    >>> from sqlalchemy.ext.declarative import declarative_base
    >>> from random import randint
    >>> from sqlalchemy import ForeignKey
    >>> BaseModel = declarative_base()
    >>> def init_db():
    ...     BaseModel.metadata.create_all(engine)
    ... 
    >>> def drop_db():
    ...     BaseModel.metadata.drop_all()
    ... 
    >>> class Stu(BaseModel):
    ...     __tablename__='stu'
    ...     id = Column(Integer,primary_key = True)
    ...     name = Column(CHAR(30))
    ... 
    >>> class Cla(BaseModel):
    ...     __tablename__='cla'
    ...     id = Column(Integer,primary_key = True)设置主键
    ...     cname = Column(CHAR(30))
    ... 
    >>> class Grade(BaseModel):
    ...     __tablename__ = 'grade'
    ...     uid = Column(Integer,ForeignKey('stu.id'))设置外键
    ...     cid = Column(Integer,ForeignKey('cla.id'))
    ...     id = Column(Integer,primary_key=True)
    ...     gre=Column(Integer)
    ... 

    declarative_base() 创建了一个 BaseModel 类,这个类的子类可以自动与一个表关联。以 Stu 类为例,它的 tablename 属性就是数据库中该表的名称,它有 id 和 name 这两个字段,分别为整型和 30 个定长字符。Column 还有一些其他的参数,我就不解释了。 
    最后,BaseModel.metadata.create_all(engine) 会找到 BaseModel 的所有子类,并在数据库中建立这些表;drop_all() 则是删除这些表。 
    现在执行init_db()进行建立表,对应语句如下

    >>> init_db()
    CREATE TABLE stu (
        id INTEGER NOT NULL AUTO_INCREMENT, 
        name CHAR(30), 
        PRIMARY KEY (id)
    )
    
    CREATE TABLE cla (
        id INTEGER NOT NULL AUTO_INCREMENT, 
        cname CHAR(30), 
        PRIMARY KEY (id)
    )
    CREATE TABLE grade (
        id INTEGER NOT NULL AUTO_INCREMENT, 
        uid INTEGER, 
        cid INTEGER, 
        gre INTEGER, 
        PRIMARY KEY (id), 
        FOREIGN KEY(uid) REFERENCES stu (id), 
        FOREIGN KEY(cid) REFERENCES cla (id)
    )
    COMMIT
    >>> 

    以上就是执行时对应的建表语句,现在去数据库看看表是否存在,并查看一个表结构

    mysql> show tables;
    +----------------+
    | Tables_in_mydb |
    +----------------+
    | cla            |
    | grade          |
    | stu            |
    +----------------+
    3 rows in set (0.00 sec)
    

    表已经建立成功了,现在看一下表结构

    mysql> desc grade;
    +-------+---------+------+-----+---------+----------------+
    | Field | Type    | Null | Key | Default | Extra          |
    +-------+---------+------+-----+---------+----------------+
    | id    | int(11) | NO   | PRI | NULL    | auto_increment |
    | uid   | int(11) | YES  | MUL | NULL    |                |
    | cid   | int(11) | YES  | MUL | NULL    |                |
    | gre   | int(11) | YES  |     | NULL    |                |
    +-------+---------+------+-----+---------+----------------+
    4 rows in set (0.00 sec)

    可以看出 使用SQLAlchemy中的语句和使用SQL语句的结果一样。接下来就可以插入数据了

    >>> stu = Stu(name='a')
    >>> session.add(stu)
    >>> stu = Stu(name='b')
    >>> session.add(stu)
    >>> stu = Stu(name='c')
    >>> session.add(stu)
    >>> stu = Stu(name='d')
    >>> session.add(stu)
    >>> stu = Stu(name='e')
    >>> session.add(stu)
    >>> 
    

    手动插入了五条记录,但此时还没有提交,没有真正的写入数据库 
    或者使用非ORM方式进行插入

    >>>session.execute(Stu.__table__.insert(),[{'name':randint(1,100)} for i in xrange(10000)])
    >>>session.commit()
    #可以速度更快的插入更多的数据
    •  
    >>> session.commit()
    2016-05-09 18:22:16,839 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
    2016-05-09 18:22:16,840 INFO sqlalchemy.engine.base.Engine INSERT INTO stu (name) VALUES (%s)
    2016-05-09 18:22:16,840 INFO sqlalchemy.engine.base.Engine ('a',)
    2016-05-09 18:22:16,841 INFO sqlalchemy.engine.base.Engine INSERT INTO stu (name) VALUES (%s)
    2016-05-09 18:22:16,841 INFO sqlalchemy.engine.base.Engine ('b',)
    2016-05-09 18:22:16,841 INFO sqlalchemy.engine.base.Engine INSERT INTO stu (name) VALUES (%s)
    2016-05-09 18:22:16,841 INFO sqlalchemy.engine.base.Engine ('c',)
    2016-05-09 18:22:16,842 INFO sqlalchemy.engine.base.Engine INSERT INTO stu (name) VALUES (%s)
    2016-05-09 18:22:16,842 INFO sqlalchemy.engine.base.Engine ('d',)
    2016-05-09 18:22:16,842 INFO sqlalchemy.engine.base.Engine INSERT INTO stu (name) VALUES (%s)
    2016-05-09 18:22:16,842 INFO sqlalchemy.engine.base.Engine ('e',)
    2016-05-09 18:22:16,843 INFO sqlalchemy.engine.base.Engine COMMIT
    >>> 

    此时真的写入数据库了哦。向课程表插入五条

    >>> cla = Cla(cname='yuwen')
    >>> session.add(cla)
    >>> cla = Cla(cname='shuxue')
    >>> session.add(cla)
    >>> cla = Cla(cname='yingyu')
    >>> session.add(cla)
    >>> cla = Cla(cname='wuli')
    >>> session.add(cla)
    >>> cla = Cla(cname='huaxue')
    >>> session.add(cla)
    >>> session.commit()

    3,现在开始操作数据

    >>> query = session.query(Stu)
    >>> for st in query:
    ...     print st.name
    ... 
    对应的SQL语句
    SELECT stu.id AS stu_id, stu.name AS stu_name 
    FROM stu
    2016-05-09 18:56:07,084 INFO sqlalchemy.engine.base.Engine ()
    a
    b
    c
    d
    e
    >>> print query.all()# # 返回的是一个类似列表的对象
    SELECT stu.id AS stu_id, stu.name AS stu_name 
    FROM stu
    2016-05-09 18:58:16,085 INFO sqlalchemy.engine.base.Engine ()
    [<__main__.Stu object at 0xb66b3f4c>, <__main__.Stu object at 0xb5e4202c>, <__main__.Stu object at 0xb66b3f8c>, <__main__.Stu object at 0xb5e4206c>, <__main__.Stu object at 0xb6688c0c>]
    
    >>> print query.first().name# 有数据时返回第一条记录,没有数据时会返回 None
    SELECT stu.id AS stu_id, stu.name AS stu_name 
    FROM stu 
     LIMIT %s
    2016-05-09 18:59:43,149 INFO sqlalchemy.engine.base.Engine (1,)
    a
    # print query.one().name# 不存在,或有多行记录时会抛出异常
    
    >>> print query.filter(Stu.id == 2).first().name
    SELECT stu.id AS stu_id, stu.name AS stu_name 
    FROM stu 
    WHERE stu.id = %s 
     LIMIT %s
    2016-05-09 19:04:54,363 INFO sqlalchemy.engine.base.Engine (2, 1)
    b
    >>> print query.filter('id = 2').first().name # 支持字符串
    SELECT stu.id AS stu_id, stu.name AS stu_name 
    FROM stu 
    WHERE id = 2 
     LIMIT %s
    2016-05-09 19:07:02,016 INFO sqlalchemy.engine.base.Engine (1,)
    b
    >>> print query.get(2).name # 以主键获取,等效于上句
    2016-05-09 19:07:40,007 INFO sqlalchemy.engine.base.Engine SELECT stu.id AS stu_id, stu.name AS stu_name 
    FROM stu 
    WHERE stu.id = %s
    2016-05-09 19:07:40,007 INFO sqlalchemy.engine.base.Engine (2,)
    b
    >>> print query.get(2).id
    SELECT stu.id AS stu_id, stu.name AS stu_name 
    FROM stu 
    WHERE stu.id = %s
    2016-05-09 19:08:46,009 INFO sqlalchemy.engine.base.Engine (2,)
    2
    •  
    >>> print quer2.limit(1).all() #只返回一条
    2016-05-09 19:11:23,383 INFO sqlalchemy.engine.base.Engine SELECT stu.name AS stu_name 
    FROM stu 
     LIMIT %s
    2016-05-09 19:11:23,383 INFO sqlalchemy.engine.base.Engine (1,)
    [('a',)]
    
    >>> print quer2.limit(2).all()#只返回两条
    SELECT stu.name AS stu_name 
    FROM stu 
     LIMIT %s
    2016-05-09 19:11:29,480 INFO sqlalchemy.engine.base.Engine (2,)
    [('a',), ('b',)]
    >>> print quer2.offset(1).all() #跳过一条,从第二条数据开始查询
    SELECT stu.name AS stu_name 
    FROM stu 
     LIMIT %s, 18446744073709551615
    2016-05-09 19:13:25,734 INFO sqlalchemy.engine.base.Engine (1,)
    [('b',), ('c',), ('d',), ('e',)]
    >>> print quer2.offset(3).all() #从第四条数据开始
    SELECT stu.name AS stu_name 
    FROM stu 
     LIMIT %s, 18446744073709551615
    2016-05-09 19:13:39,629 INFO sqlalchemy.engine.base.Engine (3,)
    [('d',), ('e',)]
    #按name降序排序
    >>> print quer2.order_by(Stu.name.desc()).all()
    SELECT stu.name AS stu_name 
    FROM stu ORDER BY stu.name DESC
    2016-05-09 19:16:56,022 INFO sqlalchemy.engine.base.Engine ()
    [('e',), ('d',), ('c',), ('b',), ('a',)]
    
    >>> print quer2.order_by('name desc').all()
    SELECT stu.name AS stu_name 
    FROM stu ORDER BY name desc
    2016-05-09 19:17:09,851 INFO sqlalchemy.engine.base.Engine ()
    [('e',), ('d',), ('c',), ('b',), ('a',)]
    #按name降序,有重复的按id升序排序
    >>> print session.query(Stu.id).order_by('name desc','id').all()
    SELECT stu.id AS stu_id 
    FROM stu ORDER BY name desc, stu.id
    2016-05-09 19:20:34,818 INFO sqlalchemy.engine.base.Engine ()
    [(5L,), (4L,), (3L,), (2L,), (1L,)]
    #scalar()在有多条数据时使用报出异常,all()可以使用多条也可以使用一条
    #>>> print quer2.filter(Stu.id>2).scalar()
    >>> print quer2.filter(Stu.id>2).all()
    SELECT stu.name AS stu_name 
    FROM stu 
    WHERE stu.id > %s
    2016-05-09 19:56:47,760 INFO sqlalchemy.engine.base.Engine (2,)
    [('c',), ('d',), ('e',)]
    
    >>> print quer2.filter(Stu.id==2).all()
    SELECT stu.name AS stu_name 
    FROM stu 
    WHERE stu.id = %s
    2016-05-09 19:57:47,901 INFO sqlalchemy.engine.base.Engine (2,)
    [('b',)]
    
    
    >>> print quer2.filter(Stu.id==2).scalar()
    SELECT stu.name AS stu_name 
    FROM stu 
    WHERE stu.id = %s
    2016-05-09 19:23:38,761 INFO sqlalchemy.engine.base.Engine (2,)
    b
    
    >>> print quer2.filter('id=2').scalar()
    SELECT stu.name AS stu_name 
    FROM stu 
    WHERE id=2
    2016-05-09 19:43:47,797 INFO sqlalchemy.engine.base.Engine ()
    b
    
    #在此中‘,’等价于and
    >>> print query2.filter(Stu.id>1,Stu.name !='a').first()
    SELECT stu.name AS stu_name 
    FROM stu 
    WHERE stu.id > %s AND stu.name != %s 
     LIMIT %s
    2016-05-09 19:51:14,571 INFO sqlalchemy.engine.base.Engine (1, 'a', 1)
    ('b',)
    >>> 
    
    #此种迭代也类似与and
    >>> query3 = query2.filter(Stu.id>1)
    >>> query3 = query3.filter(Stu.name != 'a')
    >>> query3.first()
    2016-05-09 19:53:50,150 INFO sqlalchemy.engine.base.Engine SELECT stu.name AS stu_name 
    FROM stu 
    WHERE stu.id > %s AND stu.name != %s 
     LIMIT %s
    2016-05-09 19:53:50,151 INFO sqlalchemy.engine.base.Engine (1, 'a', 1)
    ('b',)
    
    •  
    #or_就是类似or
    >>> print query2.filter(or_(Stu.id == 1,Stu.id==2)).all()
    2016-05-09 19:55:59,383 INFO sqlalchemy.engine.base.Engine SELECT stu.name AS stu_name 
    FROM stu 
    WHERE stu.id = %s OR stu.id = %s
    2016-05-09 19:55:59,383 INFO sqlalchemy.engine.base.Engine (1, 2)
    [('a',), ('b',)]
    
    •  
    # in的用法
    >>> print query2.filter(Stu.id.in_((1,2,3))).all()
    SELECT stu.name AS stu_name 
    FROM stu 
    WHERE stu.id IN (%s, %s, %s)
    2016-05-09 20:01:01,729 INFO sqlalchemy.engine.base.Engine (1, 2, 3)
    [('a',), ('b',), ('c',)]
    >>> 
    
    •  
    #修改数据
    >>> query.filter(Stu.id==1).update({Stu.name:'li'})
    UPDATE stu SET name=%s WHERE stu.id = %s
    2016-05-09 20:12:57,027 INFO sqlalchemy.engine.base.Engine ('li', 1)
    1L
    
    #删除数据
    >>> query = session.query(Grade)
    >>> query.filter(Grade.id == 1).delete()
    DELETE FROM grade WHERE grade.id = %s
    2016-05-09 20:28:18,638 INFO sqlalchemy.engine.base.Engine (1,)
    1L
    >>> 
    此时没有提交,在数据库中环视存在的
    mysql> select * from grade;
    +----+------+------+------+
    | id | uid  | cid  | gre  |
    +----+------+------+------+
    |  1 |    1 |    1 |   60 |
    |  2 |    2 |    1 |   66 |
    |  3 |    5 |    1 |   66 |
    |  4 |    5 |    5 |   96 |
    |  5 |    5 |    3 |   96 |
    |  6 |    3 |    2 |   96 |
    |  7 |    3 |    4 |   76 |
    |  8 |    4 |    4 |   76 |
    |  9 |    4 |    3 |   76 |
    | 10 |    4 |    5 |   76 |
    | 11 |    1 |    4 |   76 |
    | 12 |    1 |    5 |   76 |
    | 13 |    2 |    5 |   76 |
    | 14 |    3 |    3 |   60 |
    | 15 |    2 |    3 |   50 |
    +----+------+------+------+
    15 rows in set (0.00 sec)
    #开始提交
    >>> session.commit()
    2016-05-09 20:31:02,461 INFO sqlalchemy.engine.base.Engine COMMIT
    >>> 
    mysql> select * from grade;
    +----+------+------+------+
    | id | uid  | cid  | gre  |
    +----+------+------+------+
    |  2 |    2 |    1 |   66 |
    |  3 |    5 |    1 |   66 |
    |  4 |    5 |    5 |   96 |
    |  5 |    5 |    3 |   96 |
    |  6 |    3 |    2 |   96 |
    |  7 |    3 |    4 |   76 |
    |  8 |    4 |    4 |   76 |
    |  9 |    4 |    3 |   76 |
    | 10 |    4 |    5 |   76 |
    | 11 |    1 |    4 |   76 |
    | 12 |    1 |    5 |   76 |
    | 13 |    2 |    5 |   76 |
    | 14 |    3 |    3 |   60 |
    | 15 |    2 |    3 |   50 |
    +----+------+------+------+
    14 rows in set (0.00 sec)
    
    也获取不到对象了
    >>> print query.get(1)
    SELECT grade.id AS grade_id, grade.uid AS grade_uid, grade.cid AS grade_cid, grade.gre AS grade_gre 
    FROM grade 
    WHERE grade.id = %s
    2016-05-09 20:32:20,742 INFO sqlalchemy.engine.base.Engine (1,)
    None
    >>> 
    更多相关内容
  • 主要介绍了python orm 框架中sqlalchemy用法,结合实例形式详细分析了Python orm 框架基本概念、原理及sqlalchemy相关使用技巧,需要的朋友可以参考下
  • flask-sqlalchemy用法详解

    2019-09-24 11:41:56
    $ pip install flask-sqlalchemy 二. 配置 配置选项列表 : 选项说明 SQLALCHEMY_DATABASE_URI 用于连接的数据库 URI 。例如:sqlite:////tmp/test.db 或 mysql://username:password@server/db ...

    一. 安装

    $ pip install flask-sqlalchemy
    

    二. 配置

    配置选项列表 :

    选项说明
    SQLALCHEMY_DATABASE_URI用于连接的数据库 URI 。例如:sqlite:tmp/test.db 或 mysql://username:password@server/db
    SQLALCHEMY_BINDS一个映射 binds 到连接 URI 的字典。更多 binds 的信息见 用 Binds 操作多个数据库 。
    SQLALCHEMY_ECHO如果设置为 Ture , SQLAlchemy 会记录所有 发给 stderr 的语句,这对调试有用。
    SQLALCHEMY_RECORD_QUERIES可以用于显式地禁用或启用查询记录。查询记录 在调试或测试模式自动启用。更多信息见 get_debug_queries() 。

    SQLALCHEMY_NATIVE_UNICODE | 可以用于显式禁用原生 unicode 支持。当使用 不合适的指定无编码的数据库默认值时,这对于 一些数据库适配器是必须的(比如 Ubuntu 上某些版本的 PostgreSQL )。|
    | SQLALCHEMY_POOL_SIZE | 数据库连接池的大小。默认是引擎默认值(通常 是 5 ) |
    | SQLALCHEMY_POOL_TIMEOUT | 设定连接池的连接超时时间。默认是 10 。 |
    | SQLALCHEMY_POOL_RECYCLE | 多少秒后自动回收连接。这对 MySQL 是必要的, 它默认移除闲置多于 8 小时的连接。注意如果 使用了 MySQL , Flask-SQLALchemy 自动设定这个值为 2 小时。|

    1.  
      app.config[ "SQLALCHEMY_DATABASE_URI"] = DATABASE_URI
    2.  
      app.config[ "SQLALCHEMY_COMMIT_ON_TEARDOWN"] = True/False # 每次请求结束后都会自动提交数据库中的变动.
    3.  
       
    4.  
      app.config[ ""] =
    5.  
      app.config[ ""] =
    6.  
      app.config[ ""] =
    7.  
      app.config[ ""] =
    8.  
       
    9.  
      DATABASE_URI :
    10.  
      mysql : mysql://username:password@hostname/database
    11.  
       
    12.  
      pgsql : postgresql://username:password@hostname/database
    13.  
       
    14.  
      sqlite(linux) : sqlite:////absolute/path/to/database
    15.  
       
    16.  
      sqlite(windows) : sqlite:///c:/absolute/path/to/database

    三. 初始化示例

    1.  
      from flask import Flask
    2.  
      from flask_sqlalchemy import SQLAlchemy
    3.  
      base_dir = os.path.abspath(os.path.dirname(__file__))
    4.  
       
    5.  
      app = Flask(__name__)
    6.  
       
    7.  
      app.config[ "SQLALCHEMY_DATABASE_URI"] = 'sqlite:///' + os.path.join(base_dir, 'data.sqlite')
    8.  
      app.config[ "SQLALCHEMY_COMMIT_ON_TEARDOWN"] = True
    9.  
       
    10.  
      db = SQLAlchemy(app)

    四. 定义模型

    模型 表示程序使用的持久化实体. 在 ORM 中, 模型一般是一个 Python 类, 类中的属性对应数据库中的表.

    Flaks-SQLAlchemy 创建的数据库实例为模型提供了一个基类以及一些列辅助类和辅助函数, 可用于定义模型的结构.

    1.  
      db.Model # 创建模型,
    2.  
      db.Column # 创建模型属性.

    模型属性类型 :

    类型名Python类型说明
    Integerint普通整数,一般是 32 位
    SmallIntegerint取值范围小的整数,一般是 16 位
    Big Integerint 或 long不限制精度的整数
    Floatfloat浮点数
    Numericdecimal.Decimal定点数
    Stringstr变长字符串
    Textstr变长字符串,对较长或不限长度的字符串做了优化
    Unicodeunicode变长 Unicode 字符串
    Unicode Textunicode变长 Unicode 字符串,对较长或不限长度的字符串做了优化
    Booleanbool布尔值
    Datedatetime.date日期
    Timedatetime.time时间
    DateTimedatetime.datetime日期和时间
    Intervaldatetime.timedelta时间间隔
    Enumstr一组字符串
    PickleType任何 Python 对象自动使用 Pickle 序列化
    LargeBinarystr二进制文件

    常用 SQLAlchemy 列选项

    选项名说明
    primary_key如果设为 True,这列就是表的主键
    unique如果设为 True,这列不允许出现重复的值
    index如果设为 True,为这列创建索引,提升查询效率
    nullable如果设为 True,这列允许使用空值;如果设为 False,这列不允许使用空值
    default为这列定义默认值

    Flask-SQLAlchemy 要求每个模型都要定义主键, 这一列通常命名为 id .

    示例 :

    1.  
      class Role(db.Model):
    2.  
      __tablename__ = "roles"
    3.  
      id = db.Column(db.Integer, primary_key= True)
    4.  
      name = db.Column(db.String( 64), unique=True)
    5.  
       
    6.  
      def __repr__(self):
    7.  
      """非必须, 用于在调试或测试时, 返回一个具有可读性的字符串表示模型."""
    8.  
      return '<Role %r>' % self.name
    9.  
       
    10.  
      class User(db.Model):
    11.  
      __tablename__ = 'users'
    12.  
      id = db.Column(db.Integer, primary_key= True)
    13.  
      username = db.Column(db.String( 64), unique=True, index=True)
    14.  
       
    15.  
      def __repr__(self):
    16.  
      """非必须, 用于在调试或测试时, 返回一个具有可读性的字符串表示模型."""
    17.  
      return '<Role %r>' % self.username

    五. 关系

    关系型数据库使用关系把不同表中的行联系起来.

    常用 SQLAlchemy 关系选项 :

    选项名说明
    backref在关系的另一个模型中添加反向引用
    primaryjoin明确指定两个模型之间使用的联结条件。只在模棱两可的关系中需要指定.
    lazy指定如何加载相关记录。可选值如下 :
     select(首次访问时按需加载)
     immediate(源对象加载后就加载)
     joined(加载记录,但使用联结)
     subquery(立即加载,但使用子查询)
     noload(永不加载)
     dynamic(不加载记录,但提供加载记录的查询)
    uselist如果设为 Fales,不使用列表,而使用标量值
    order_by指定关系中记录的排序方式
    secondary指定多对多关系中关系表的名字
    secondaryjoinSQLAlchemy 无法自行决定时,指定多对多关系中的二级联结条件

    1) 一对多

    原理 : 在 “多” 这一侧加入一个外键, 指定 “一” 这一侧联结的记录.

    示例代码 : 一个角色可属于多个用户, 而每个用户只能有一个角色.

    1.  
      class Role(db.Model):
    2.  
      # ...
    3.  
      users = db.relationship( 'User', backref='role')
    4.  
       
    5.  
      class User(db.Model):
    6.  
      # ...
    7.  
      role_id = db.Column(db.Integer, db.ForeignKey( 'roles.id')) # 外键关系.
    8.  
       
    9.  
       
    10.  
      ###############
    11.  
      db.ForeignKey( 'roles.id') : 外键关系,
    12.  
       
    13.  
      Role.users = db.relationship( 'User', backref='role') : 代表 外键关系的 面向对象视角. 对于一个 Role 类的实例, 其 users 属性将返回与角色相关联的用户组成的列表.
    14.  
      db.relationship() 第一个参数表示这个关系的另一端是哪个模型.
    15.  
      backref 参数, 向 User 模型添加了一个 role 数据属性, 从而定义反向关系. 这一属性可替代 role_id 访问 Role 模型, 此时获取的是模型对象, 而不是外键的值.

    2) 多对多

    最复杂的关系类型, 需要用到第三章表, 即 关联表 , 这样多对多关系可以分解成原表和关联表之间的两个一对多关系.

    查询多对多关系分两步 : 遍历两个关系来获取查询结果.

    代码示例:

    1.  
      registrations = db.Table( "registrations",
    2.  
      db.Column( "student_id", db.Integer, db.ForeignKey("students.id")),
    3.  
      db.Column( "class_id", db.Integer, db.ForeignKey("classes.id"))
    4.  
      )
    5.  
       
    6.  
      class Student(db.Model):
    7.  
      __tablename__ = "students"
    8.  
      id = db.Column(db. Integer, primary_key=True)
    9.  
      name = db.Column(db. String)
    10.  
      classes = db.relationship( "Class",
    11.  
      secondary=registrations,
    12.  
      backref=db.backref( "students", lazy="dynamic"),
    13.  
      lazy= "dynamic")
    14.  
       
    15.  
      class Class(db.Model):
    16.  
      __tablename__ = "classes"
    17.  
      id = db.Column(db. Integer, primary_key=True)
    18.  
      name = db.Column(db. String)

    多对多关系仍然使用定义一对多关系的 db.relationship() 方法进行定义, 但在多对多关系中, 必须把 secondary 参数设为 关联表.

    多对多关系可以在任何一个类中定义, backref 参数会处理好关系的另一侧.

    关联表就是一个简单的表, 不是模型, SQLAlchemy 会自动接管这个表.

    classes 关系使用列表语义, 这样处理多对多关系比较简单.

    Class 模型的 students 关系有 参数 db.backref() 定义. 这个关系还指定了 lazy 参数, 所以, 关系两侧返回的查询都可接受额外的过滤器.

    自引用关系
    自引用关系可以理解为 多对多关系的特殊形式 : 多对多关系的两边由两个实体变为 一个实体.

    高级多对多关系
    使用多对多关系时, 往往需要存储所联两个实体之间的额外信息. 这种信息只能存储在关联表中. 对用户之间的关注来说, 可以存储用户关注另一个用户的日期, 这样就能按照时间顺序列出所有关注者.

    为了能在关系中处理自定义的数据, 必须提升关联表的地位, 使其变成程序可访问的模型.

    关注关联表模型实现:

    1.  
      class Follow(db.Model):
    2.  
      __tablename__ = "follows"
    3.  
      follower_id = db.Column(db. Integer, db.ForeignKey("users.id"), primary_key=True)
    4.  
      followed_id = db.Column(db. Integer, db.ForeignKey("users.id"), primary_key=True)
    5.  
      timestamp = db.Column(db.DateTime, default=datetime.utcnow)
    6.  
       
    7.  
      # SQLAlchemy 不能直接使用这个关联表, 因为如果这个做程序就无法访问其中的自定义字段. 相反的, 要把这个多对多关系的左右两侧拆分成两个基本的一对多关系, 而且要定义成标准的关系.

    使用两个一对多关系实现的多对多关系:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    
    class User(UserMixin, db.Model):
        # ...
        followd = db.relationship("Follow",
                                  foreign_keys=[Follow.follower_id],
                                  backref=db.backref("follower", lazy="joined"),
                                  lazy="dynamic",
                                  cascade="all, delete-orphan")
        followrs = db.relationship("Follow",
                                  foreign_keys=[Follow.followed_id],
                                  backref=db.backref("followed", lazy="joined"),
                                  lazy="dynamic",
                                  cascade="all, delete-orphan")
    
    # 这段代码中, followed 和 follower 关系都定义为 单独的 一对多关系. 
    # 注意: 为了消除外键歧义, 定义关系是必须使用可选参数 foreign_keys 指定的外键. 而且 db.backref() 参数并不是指定这两个关系之间的引用关系, 而是回引 Follow 模型. 回引中的 lazy="joined" , 该模式可以实现立即从连接查询中加载相关对象.
    # 这两个关系中, user 一侧设定的 lazy 参数作用不一样. lazy 参数都在 "一" 这一侧设定, 返回的结果是 "多" 这一侧中的记录. dynamic 参数, 返回的是查询对象.
    # cascade 参数配置在父对象上执行的操作相关对象的影响. 比如, 层叠对象可设定为: 将用户添加到数据库会话后, 要自定把所有关系的对象都添加到会话中. 删除对象时, 默认的层叠行为是把对象联结的所有相关对象的外键设为空值. 但在关联表中, 删除记录后正确的行为是把执行该记录的实体也删除, 因为这样才能有效销毁联结. 这就是 层叠选项值 delete-orphan 的作用. 设为 all, delete-orphan 的意思是启动所有默认层叠选项, 并且还要删除孤儿记录.
    

    3) 一对一

    可以看做特殊的 一对多 关系. 但调用 db.relationship() 时 要把 uselist 设置 False, 把 多变为 一 .

    4) 多对一

    将 一对多 关系,反过来即可, 也是 一对多关系.

    六. 数据库操作

    1) 创建数据库及数据表

    创建数据库

    db.create_all()
    

    示例 :
    $ python myflask.py shell
    > from myflask import db
    > db.create_all()

    如果使用 sqlite , 会在 SQLALCHEMY_DATABASE_URI 指定的目录下 多一个文件, 文件名为该配置中的文件名.

    如果数据库表已经存在于数据库中, 那么 db.create_all() 不会创建或更新这个表.

    更新数据库
    方法一 :
    先删除, 在创建 –> 原有数据库中的数据, 都会消失.

    1.  
      > db.drop_all()
    2.  
      > db.create_all()

    方法二 :
    数据库迁移框架 : 可以跟自动数据库模式的变化, 然后增量式的把变化应用到数据库中.

    SQLAlchemy 的主力开发人员编写了一个 迁移框架 Alembic, 除了直接使用 Alembic wait, Flask 程序还可使用 Flask-Migrate 扩展, 该扩展对 Alembic 做了轻量级包装, 并集成到 Flask-Script 中, 所有操作都通过 Flaks-Script 命令完成.

    ① 安装 Flask-Migrate
    $ pip install flask-migrate

    ② 配置

    1.  
      from flask_migrate import Migrate, MigrateCommand
    2.  
       
    3.  
      # ...
    4.  
      migrate = Migrate(app, db)
    5.  
      manager.add_command( 'db', MigrateCommand)

    ③ 数据库迁移
    a. 使用 init 自命令创建迁移仓库.
    $ python myflask.py db init # 该命令会创建 migrations 文件夹, 所有迁移脚本都存在其中.

    1.  
      b. 创建数据路迁移脚本.
    2.  
      $ python myflask.py db revision # 手动创建 Alemic 迁移
    3.  
      创建的迁移只是一个骨架, upgrade() 和 downgrade() 函数都是空的. 开发者需要使用 Alembic 提供的 Operations 对象指令实现具体操作.
    4.  
       
    5.  
      $ python myflask.py db migrate -m COMMONT # 自动创建迁移.
    6.  
      自动创建的迁移会根据模型定义和数据库当前的状态之间的差异生成 upgrade() 和 downgrade() 函数的内容.
    7.  
       
    8.  
      ** 自动创建的迁移不一定总是正确的, 有可能漏掉一些细节, 自动生成迁移脚本后一定要进行检查.
    9.  
       
    10.  
       
    11.  
      c. 更新数据库
    12.  
      $ python myflask.py db upgrade # 将迁移应用到数据库中.

    2) 插入行

    模型的构造函数, 接收的参数是使用关键字参数指定的模型属性初始值. 注意, role 属性也可使用, 虽然他不是真正的数据库列, 但却是一对多关系的高级表示. 这些新建对象的 id 属性并没有明确设定, 因为主键是由 Flask-SQLAlchemy 管理的. 现在这些对象只存在于 Python 解释器中, 尚未写入数据库.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    
    >> from myflask import db, User, Role
    
    >> db.create_all()
    
    >> admin_role = Role(name="Admin")
    
    >> mod_role = Role(name="Moderator")
    
    >> user_role = Role(name="User")
    
    >> user_john = User(username="john", role=admin_role)
    
    >> user_susan = User(username="susan", role=mod_role)
    
    >> user_david = User(username="david", role=user_role)
    
    >> admin_role.name
    'Admin'
    
    >> admin_role.id
    None
    
    ---------
    
    >> db.session.add_all([admin_role, mod_role, user_role, user_john, user_susan, user_david])   # 把对象添加到会话中.
    >> db.session.commit()      # 把对象写入数据库, 使用 commit() 提交会话.
    

     

    3) 修改行

    1.  
      >> admin_role = "Administrator"
    2.  
      >> db.session.add(admin_role)
    3.  
      >> db.session.commit()

    4) 删除行

    1.  
      >> db.session.delete(mod_role)
    2.  
      >> db.session.commit()

    5) 查询行

    Flask-SQLAlchemy 为每个模型类都提供了 query 对象.

    获取表中的所有记录

    1.  
      >> Role.query.all()
    2.  
      [<Role u'Admin'>, <Role u'Moderator'>, <Role u'User'>]
    3.  
      >> User.query.all()
    4.  
      [<Role u'john'>, <Role u'susan'>, <Role u'david'>]

    查询过滤器

    filter_by() 等过滤器在 query 对象上调用, 返回一个更精确的 query 对象. 多个过滤器可以一起调用, 直到获取到所需的结果.

    1.  
      >> User.query.filter_by(role=user_role).all() # 以列表形式,返回所有结果,
    2.  
      >> User.query.filter_by(role=user_role).first() # 返回结果中的第一个.

    filter() 对查询结果过滤,比”filter_by()”方法更强大,参数是布尔表达式

    1.  
      # WHERE age< 20
    2.  
      users = User.query.filter(User.age< 20)
    3.  
      # WHERE name LIKE 'J%' AND age<20
    4.  
      users = User.query.filter(User. name.startswith('J'), User.age<20)

    查询过滤器 :

    过滤器说明
    filter()把过滤器添加到原查询上, 返回一个新查询
    filter_by()把等值过滤器添加到原查询上, 返回一个新查询
    limit()使用是zing的值限制原查询返回的结果数量, 返回一个新查询
    offset()偏移原查询返回的结果, 返回一个新查询
    order_by()根据指定条件对原查询结果进行排序, 返回一个新查询
    group_by()根据指定条件对原查询结果进行分组, 返回一个新查询

    查询执行函数 :

    方法说明
    all()以列表形式返回查询的所有结果
    first()返回查询的第一个结果,如果没有结果,则返回 None

    first_or_404() | 返回查询的第一个结果,如果没有结果,则终止请求,返回 404 错误响应 | |
    | get() | 返回指定主键对应的行,如果没有对应的行,则返回 None |
    get_or_404() | 返回指定主键对应的行,如果没找到指定的主键,则终止请求,返回 404 | |错误响应
    | count() | 返回查询结果的数量 |
    | paginate() | 返回一个 Paginate 对象,它包含指定范围内的结果 |

    6) 会话管理, 事务管理

    单个提交

    1.  
      >> db.session.add(ONE)
    2.  
      >> db.session.commit()

    多个提交

    1.  
      >> db.session.add_all([LIST_OF_MEMBER])
    2.  
      >> db.session.commit()

    删除会话

    1.  
      >> db.session.delete(mod_role)
    2.  
      >> db.session.commit()

    事务回滚 : 添加到数据库会话中的所有对象都会还原到他们在数据库时的状态.

    >> db.session.rollback()
    

    七. 视图函数中操作数据库

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    @app.route('/', methods=['GET', 'POST'])
    def index():
        form = NameForm()
        if form.validate_on_submit():
            user = User.query.filter_by(username=form.name.data).first()
            if user is None:
                user = User(username=form.name.data)
                db.session.add(user)
                session["known"] = False
            else:
                session["known"] = True
    
            session["name"] = form.name.data
            form.name.data = ""             # why empty it ?
            return redirect(url_for("index"))
        return render_template("index.html", current_time=datetime.utcnow(), form=form, name=session.get("name"), known=session.get("known"))
    

    八. 分页对象 Pagination

    1. paginate() 方法

    paginate() 方法的返回值是一个 Pagination 类对象, 该类在 Flask-SQLAlchemy 中定义, 用于在模板中生成分页链接.

    1.  
      paginate(页数[,per_page= 20, error_out=True])
    2.  
      页数 : 唯一必须指定的参数,
    3.  
      per_page : 指定每页现实的记录数量, 默认 20.
    4.  
      error_out : True 如果请求的页数超出了返回, 返回 404 错误; False 页数超出范围时返回一个,空列表.

    示例代码:

    1
    2
    3
    4
    5
    6
    7
    8
    
    @main.route("/", methods=["GET", "POST"])
    def index():
        # ...
        page = request.args.get('page', 1, type=int)    # 渲染的页数, 默认第一页, type=int 保证参数无法转换成整数时, 返回默认值.
        pagination = Post.query.order_by(Post.timestamp.desc()).paginate(page, per_page=current_app.config["FLASKY_POSTS_PER_PAGE"], error_out=False)
    
        posts = pagination.items
        return render_template('index.html', form=form, posts=posts,pagination=pagination)
    

     

    2. 分页对象的属性及方法:

    Flask_SQLAlchemy 分页对象的属性:

    属性说明
    items当前分页中的记录
    query分页的源查询
    page当前页数
    prev_num上一页的页数
    next_num下一页的页数
    has_next如果有下一页, 返回 True
    has_prev如果有上一页, 返回 True
    pages查询得到的总页数
    per_page每页显示的记录数量
    total查询返回的记录总数

    在分页对象可调用的方法:

    方法说明
    iter_pages(left_edge=2,left_current=2,right_current=5,right_edge=2)一个迭代器, 返回一个在分页导航中显示的页数列表. 这个列表的最左边显示 left_edge 页, 当前页的左边显式 left_current 页, 当前页的右边显示 right_currnt 页, 最右边显示 right_edge 页. 如 在一个 100 页的列表中, 当前页为 50 页, 使用默认配置, 该方法返回以下页数 : 1, 2, None, 48,49,50,51,52,53,54,55, None, 99 ,100. None 表示页数之间的间隔.
    prev()上一页的分页对象
    next()下一页的分页对象

    3. 在模板中与 BootStrap 结合使用示例

    使用 Flaks-SQLAlchemy 的分页对象与 Bootstrap 中的分页 CSS, 可以轻松的构造出一个 分页导航.

    分页模板宏 _macros.html : 创建一个 Bootstrap 分页元素, 即一个有特殊样式的无序列表.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    
    {% macro pagination_widget(pagination,endpoint) %}
    <ul class="pagination">
        <li {% if not pagination.has_prev %} class="disabled" {% endif %}>
            <a href="{% if pagination.has_prev %}{{url_for(endpoint, page=paginatin.page - 1, **kwargs)}}{% else %}#{% endif %}">
                &laquo;
            </a>
        </li>
        {% for p in pagination,.iter_pages() %}
            {% if p %}
                {% if p == pagination.page %}
                <li class="active">
                    <a href="{{ url_for(endpoint, page=p, **kwargs) }}">{{p}}</a>
                </li>
                {% else %}
                <li>
                    <a href="{{ url_for(endpoint, page = p, **kwargs) }}">{{p}}</a>
                </li>
                {% endif %}
            {% else %}
            <li class="disabled"><a href="#">&hellip;</a> </li>
            {% endif %}
        {% endfor %}
        <li {% if not pagination.has_next %} class="disabled" {% endif%}>
            <a href="{% if paginatin.has_next %}{{ url_for(endpoint, page=pagination.page+1, **kwargs) }}{% else %}#{% endif %}">
                &raquo;
            </a>
        </li>
    </ul>
    {% endmacro %}
    

    导入使用分页导航

    1
    2
    3
    4
    5
    6
    
    {% extends "base.html" %}
    {% import "_macros.html" as macros %}
    ...
    <div class="pagination">
        {{ macro.pagination_widget(pagination, ".index")}}
    </div>
    

     

    九. 监听事件

    1. set 事件

    示例代码 :

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    from markdown import markdown
    import bleach
    
    class Post(db.Model):
        # ...
        body = db.Colume(db.Text)
        body_html = db.Column(db.Text)
        # ...
    
        @staticmethod
        def on_changeed_body(target, value, oldvalue, initiator):
            allowed_tags = ["a", "abbr", "acronym", "b", "blockquote", "code", "em",
                            "i", "li", "ol", "pre", "strong", "ul", "h1", "h2","h3","h4","p"]
            target.body_html = bleach.linkify(bleach.clean(markdown(value, output_format="html"), tags=allowed_tags, strip=True))
    
    db.event.listen(Post.body, "set", Post.on_changeed_body) 
    # on_changed_body 函数注册在 body 字段上, 是 SQLIAlchemy "set" 事件的监听程序, 
    # 这意味着只要这个类实例的 body 字段设了新值, 函数就会自动被调用. 
    # on_changed_body 函数把 body 字段中的文本渲染成 HTML 格式, 
    # 结果保存在 body_html 中, 自动高效的完成 Markdown 文本到 HTML 的转换.
    

     

    十. 记录慢查询.

    十一. Binds 操作多个数据库

    十二. 其他

    1. ORM 在查询时做初始化操作

    当 SQLIAlchemy ORM 从数据库查询数据时, 默认不调用__init__ 方法, 其底层实现了 Python 类的 __new__() 方法, 直接实现 对象实例化, 而不是通过 __init__ 来实例化对象.

    如果需要在查询时, 依旧希望实现一些初始化操作, 可以使用 orm.reconstructor() 装饰器或 实现 InstanceEvents.load() 监听事件.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    # orm.reconstructor
    from sqlalchemy import orm
    
    class MyMappedClass(object):
        def __init__(self, data):
            self.data = data
    
            # we need stuff on all instances, but not in the database.
            self.stuff = []
    
        @orm.reconstructor
        def init_on_load(self):
            self.stuff = []
    
    # InstanceEvents.load()
    from sqlalchemy import event
    ## standard decorator style
    
    @event.listens_for(SomeClass, 'load')
    def receive_load(target, context):
        "listen for the 'load' event"
    
        # ... (event handling logic) ...
    

     

    如果只是希望在从数据库查询生成的对象中包含某些属性, 也可以使用 property 实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    class AwsRegions(db.Model):
        name=db.Column(db.String(64))
        ...
    
        @property
        def zabbix_api(self):
            return ZabbixObj(zabbix_url)
    
        @zabbix_api.setter
        def zabbix_api(self):
            raise ValueError("zabbix can not be setted!")

    转载于:https://www.cnblogs.com/aibabel/p/11571196.html

    展开全文
  • Flask:flask_sqlalchemy使用方法一、在__init__.py中创建db对象二、在__init__.py将app传入到db中三、写flask app数据库配置文件settings.py四、定义models.py五、创建数据库表create_table.py六、在视图函数中使用...
    展开全文
  • Flask扩展:Flask-SQLAlchemy用法 【注意】本文在python3.7下环境下实际验证通过,操作过程中请注意python版本。 1、扩展介绍 SQLAlchemy是Python SQL工具箱和对象关系映射器,为应用程序提供了SQL的全部功能和灵活...

    Flask扩展:Flask-SQLAlchemy用法

    【注意】本文在python3.7下环境下实际验证通过,操作过程中请注意python版本。

    1、扩展介绍

    SQLAlchemy是Python SQL工具箱和对象关系映射器,为应用程序提供了SQL的全部功能和灵活性。SQLAlchemy提供了一整套知名的企业级持久性模型,旨在高效,高性能的访问数据库,并被适配为简单的Pythonic语言。SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API至上,使用关系映射进行数据库操作,简而言之:将对象转换成SQL,然后使用数据库API执行SQL并获取执行结果,下图为SQLAlchemy模型:

    在这里插入图片描述

    ORM方法论的三个核心原则;

    • 简单:已最基本的形式建数据模型;
    • 传达性:数据库结构被任何人都能理解的语言文档化;
    • 精确性:基于数据库模型创建正确标准化的结构。

    可以通过三种方式来使用SQLAlchemy

    • 使用SQL Expression,通过SQLAlchemy提供的方法写sql表达式,简介的写sql;
    • 使用原生SQL,直接写sql语句;
    • 使用ORM对象映射,将类映射到数据库,通过对象来操作数据库(本文重点说明)。

    之所以先介绍SQLAlchemy,是因为本文的主角Flask-SQLAlchemy是一个简化了的SQLAlchemy操作的flask扩展,先理解SQLAlchemy,能够更好的学习Flask-SQLAlchemy

    2、操作方法介绍

    字段类型说明

    类型名Python中的类型说明
    Integerint普通整数,一般为32位
    SmallIntegerint取值范围小的整数,一般是16位
    BigIntegerint或long不限制精度的整数
    Floatfloat浮点数
    Numericdecimal.Decimal普通整数,一般是32位
    Stringstr变长字符串
    Textstr变长字符串,对较长或不限长度的字符串做了优化
    Unicodeunicode变长Unicode字符串
    UnicodeTextunicode变长Unicode字符串,对较长或不限长度的字符串做了优化
    Booleanbool布尔值
    Datedatetime.date时间
    Timedatetime.datetime日期和时间
    LargeBinarystr二进制文件

    常用的SQLAlchemy列选项

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

    常用的SQLAlchemy关系选项

    选项名说明
    backref在关系的另一模型中添加反向引用,用于设置外键名称
    primary join明确指定两个模型之间使用的联结条件
    uselist如果为False,不使用列表,而是用标量值
    order_by指定关系中记录的排序方式
    secondary指定多对多关系中关系表的名字
    secondary join在SQLAlchemy中无法自行决定时,指定多对多关系中的二级联结条件

    数据库基本操作

    • Flask-SQLAlchemy中,插入、修改、删除操作,均有数据库会话管理。会话用db.session表示,在准备把数据写入数据库前,要先将数据添加到会话中然后调用commit()方法提交会话。
    • Flask-SQLAlchemy中,查询操作通过query对象操作数据,最基本的查询操作是返回表中的所有数据,可以通过过滤器进行更精确的数据库查询。

    常用的SQLAlchemy查询过滤器

    过滤器说明
    filter()把过滤器添加到原查询上,返回一个新查询
    filter_by()把等值过滤器添加到原查询上,返回一个新查询
    limit()使用指定的值限定原查询返回的结果
    offset()偏移原查询返回的结果,返回一个新查询
    order_by()根据指定条件对原查询结果进行排序,返回一个新查询
    group_by()根据指定条件对原查询结果进行分组,返回一个新查询

    常用的SQLAlchemy查询结果的方法

    方法说明
    all()以列表形式返回查询的所有结果
    first()返回查询的第一个结果,如果无数据,返回None
    first_or_404()返回查询的第一个结果,如果无数据,返回404
    get()返回指定主键对应的行,如不存在,返回None
    get_or_404()返回指定主键对应的行,如不存在,返回404
    count()返回查询结果的数量
    paginate()返回一个Paginate对象,它包含指定范围内的结果

    重点介绍一下paginate对象的常用方法:

    • has_next:是否还有下一页
    • has_prev:是否还有上一页
    • items:以列表形式返回当前页的所有内容
    • next(error_out=False):返回上一页的Pagination对象
    • prev(error_out=False):返回下一页的Pagination对象
    • page:当前页的页码(从1开始)
    • pages:总页数
    • per_page:每页显示的数量
    • prev_num:上一页页码数
    • next_num:下一页页码数
    • query:返回创建这个Pagination对象的查询对象
    • total:查询返回的记录总数

    3、安装Flask-SQLAlchemy

    使用以下语句安装扩展:

    sudo pip install flask-sqlalchemy
    

    SQLAlchemy本身无法操作数据库,必须通过pymysql等第三方插件,本文使用的为pymysql,所以还需要安装:

    sudo pip install pymysql
    

    SQLAlchemy模型中的Dialect用于和数据API进行交流,根据配置文件的不同调用不同的数据库API,从而实现对数据库的操作,以下为使用不同插件连接数据库的URL语句:

    # '数据库类型+数据库驱动名称://用户名:口令@机器地址:端口号/数据库名'
    # pymysql
    mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>]
    # MySQL-Python
    mysql+mysqldb://<user>:<password>@<host>[:<port>]/<dbname>
    # MySQL-Connector
    mysql+mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname>
    # cx_Oracle
    oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...]
    

    Flask-SQLAlchemy中,也是用同样的方式,数据库使用URL指定,而且程序使用的数据库必须保存到Flask配置对象的SQLALCHEMY_DATABASE_URI中:

    app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>]'
    
    # 其他设置
    # 动态追踪修改设置,如未设置只会提示警告
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
    # 查询时会显示原始SQL语句
    app.config['SQLALCHEMY_ECHO'] = True
    

    4、基本操作

    使用官方示例代码,使用过程中注意将数据库连接语句修改为自己的数据库:

    • test1.py
    from flask import Flask
    from flask_sqlalchemy import SQLAlchemy
    
    app = Flask(__name__)
    app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>]'
    # 动态追踪修改设置,如未设置只会提示警告
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
    # 查询时会显示原始SQL语句
    app.config['SQLALCHEMY_ECHO'] = True
    db = SQLAlchemy(app)
    
    # 创建的用户模型,有id、username、email三个字段
    class User(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        username = db.Column(db.String(80), unique=True, nullable=False)
        email = db.Column(db.String(120), unique=True, nullable=False)
    	
        # 便于查看
        def __repr__(self):
            return '<User %r>' % self.username
    

    表操作

    创建所有表(注意:该方法需要放在模型之后 ,创建完成之后需要去掉,否则可能会报错,但是在Flask中不建议这种建库方式,推荐使用Flask-Migrate扩展):

    # 将上述例程文件保存为test1.py  然后使用python进入python命令行,注意为python3环境
    # 导入删除文件,没有报错表示成功,否则需要检查test1.py文件是否正确
    from test1 import db
    # 创建表 操作完成后会在对应数据库中创建一个名称为User的数据表
    db.create_all()
    

    删除所有表:

    db.drop_all()
    

    插入数据

    # 导入User模型
    from test1 import User
    
    # 单条数据添加 执行完成会在数据库中看到添加的数据
    admin = User(username='admin', email='admin@example.com')
    db.session.add(admin)# 添加
    db.session.commit()# 提交
    
    # 多条数据添加
    user1 = User(username='user1', email='user1@example.com')
    user2 = User(username='user2', email='user2@example.com')
    user3 = User(username='user3', email='user3@example.com')
    db.session.add_all([user1,user2,user3])# 添加
    db.session.commit()# 提交
    

    查询数据

    # 查询到的数据一般以列表形式展示,如果查找了5条数据,需要获取第二条数据的用户名:
    # users[1].username
    
    # 返回查询到的所有对象
    User.query.all()
    # [<User 'admin'>, <User 'user1'>, <User 'user2'>, <User 'user3'>]
    
    # 使用filter_by精确查找姓名为“admin”的用户
    User.query.filter_by(username='admin').all()
    #[<User 'admin'>]
    
    # 返回查询到的第一个对象
    User.query.first()
    #<User 'admin'>
    
    # filter模糊查询,返回名字结尾字符为“1”的所有数据。
    User.query.filter(User.username.endswith('1')).all()
    #[<User 'user1'>]
    
    # 参数为主键,如果主键不存在没有返回内容
    User.query.get(1)
    #<User 'admin'>
    
    # 逻辑非,返回名字不等于“admin”的所有数据
    User.query.filter(User.username!='admin').all()
    #[<User 'user1'>, <User 'user2'>, <User 'user3'>]
    
    # not_ 相当于取反
    from sqlalchemy import not_
    User.query.filter(not_(User.username=='admin')).all()
    #[<User 'user1'>, <User 'user2'>, <User 'user3'>]
    
    # 逻辑与,需要导入and,返回and()条件满足的所有数据
    from sqlalchemy import and_
    User.query.filter(and_(User.username!='admin',User.email.endswith('example.com'))).all()
    #[<User 'user1'>, <User 'user2'>, <User 'user3'>]
    
    # 逻辑或,需要导入or_
    from sqlalchemy import or_
    User.query.filter(or_(User.username!='admin',User.email.endswith('example.com'))).all()
    #[<User 'admin'>, <User 'user1'>, <User 'user2'>, <User 'user3'>]
    

    删除数据

    # 获取所有数据
    User.query.all()
    # [<User 'admin'>, <User 'user1'>, <User 'user2'>, <User 'user3'>]
    
    # 查询第一条数据
    user = User.query.first()
    # 删除
    db.session.delete(user)
    # 提交
    db.session.commit()
    # 重新查询
    User.query.all()
    #[<User 'user1'>, <User 'user2'>, <User 'user3'>]
    

    更新数据

    # 更新数据 修改查询的第一条数据姓名为“sworld”
    user = User.query.first()
    user.username = 'sworld'
    db.session.commit()
    User.query.first()
    #<User 'sworld'>
    

    【注意】:在官方文档中提及了一点,是关于为什们在User类中没有定义__init__方法,解释原因是SQLAlchemy向所有模型类添加了一个隐式构造函数,该构造函数为其所有列和关系接受关键字参数。如果出于任何原因决定重写构造函数,请确保继续接受`** kwargs并使用这些** kwargs``调用超级构造函数以保留此行为:

    # Foo 为类名
    class Foo(db.Model):
        # ...
        def __init__(**kwargs):
            super(Foo, self).__init__(**kwargs)
            # 需要增加的部分
            # ...
    

    5、进阶操作

    分页查询

    # 分页查询 接着上一步
    # 第一页,每页20条数据。 默认第一页。
    # 参数:error_out 设为True表示页数不是int或超过总页数时,会报错,并返回404状态码。 默认True
    paginate_obj = User.query.paginate(page=1, per_page=20, error_out=False)  
    
    # 获取查询出来的数据。 (error_out设为False,页数不合法时会返回空列表)
    user_list = paginate_obj.items
    # print(user_list)
    # [<User 'sworld'>, <User 'user2'>, <User 'user3'>]
     
    # 获取总页数
    total_page = paginate_obj.pages
    # print(total_page)
    # 1
    

    关联查询

    还是使用官方例程,在同级文件夹中添加下述文件:

    • test2.py
    from datetime import datetime
    # 引入test1.py中的db和User
    from test1 import db,User
    
    class Post(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        title = db.Column(db.String(80), nullable=False)
        body = db.Column(db.Text, nullable=False)
        pub_date = db.Column(db.DateTime, nullable=False,
            default=datetime.utcnow)
    	
        # 添加外键声明
        category_id = db.Column(db.Integer, db.ForeignKey('category.id'),
            nullable=False)
        # 添加关联,其中backref表示在关系的另一模型中添加反向引用,用于设置外键名称
        category = db.relationship('Category',
            backref=db.backref('posts', lazy=True))
    
        def __repr__(self):
            return '<Post %r>' % self.title
    
    class Category(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(50), nullable=False)
    
        def __repr__(self):
            return '<Category %r>' % self.name
    

    关联的使用方法如下:

    # 退出重新进入python命令行,引入test2.py,在test2.py中,会引入test1.py中的内容
    from test2 import db,User,Post,Category
    # 重新创建表
    db.create_all()
    
    # 分下述六步演示关联使用
    py = Category(name='Python')
    Post(title='Hello Python!', body='Python is pretty cool', category=py)
    p = Post(title='Snakes', body='Ssssssss')
    py.posts.append(p)
    db.session.add(py)
    db.session.commit()
    

    这是官方提供的比较经典的关联用法,分六步进行说明:

    • 第一步创建了一个name='Python'Category对象;
    • 第二步使用关联创建了一个Post对象,关联上一个创建的py
    • 第三步又创建了一个名为pPost对象;
    • 第四步调用py对象的posts方法将第三步创建的p添加至pyposts在Post类中添加了反向引用);
    • 第五步通过会话添加;
    • 第六步提交会话。

    通过上面几个步骤就在Category表中添加一条数据,在Post表中添加两条数据,查询可得:

    # 查询Category表全部数据
    Category.query.all()
    # [<Category 'Python'>]
    
    # 查询Post表全部数据
    Post.query.all()
    # [<Post 'Hello Python!'>, <Post 'Snakes'>]
    
    # 也可以使用Category模型中的posts关联获取对应的Post数据
    Category.query.first().posts
    # [<Post 'Hello Python!'>, <Post 'Snakes'>]
    

    多表查询

    join查询

    还是继续上文中的示例,多表查询可以使用join进行查询,以下展示的是使用filter过滤查询:

    db.session.query(Category,Post).filter(Category.id==Post.category_id).all()
    # [(<Category 'Python'>, <Post 'Hello Python!'>), (<Category 'Python'>, <Post 'Snakes'>)]
    
    # for打印出来
    for ctg,pst in db.session\
    	.query(Category,Post)\
    	.filter(Category.id==Post.category_id).all():
        print(ctg,pst)
    # <Category 'Python'> <Post 'Hello Python!'>
    # <Category 'Python'> <Post 'Snakes'>
    

    使用join示例如下:

    # 指定外键情况下可适用下述方法
    db.session.query(Category,Post).join(Post).all()
    # [(<Category 'Python'>, <Post 'Hello Python!'>), (<Category 'Python'>, <Post 'Snakes'>)]
    
    # 没有指定外键则需要在join后面添加过滤参数
    db.session.query(Category,Post).join(Post,Category.id==Post.category_id).all()
    # [(<Category 'Python'>, <Post 'Hello Python!'>), (<Category 'Python'>, <Post 'Snakes'>)]
    

    子查询(subquery)

    子查询示例如下:

    # 需要查询Category某条数据在Post表中对应的数据条数:
    # 对Post进行子查询
    # 添加引用
    from sqlalchemy.sql import func
    spst=db.session\
    	.query(Post.category_id,func.count('*')\
        .label('post_count'))\
        .group_by(Post.category_id).subquery()
    db.session\
    	.query(Category,spst.c.post_count)\
        .outerjoin(spst,Category.id==spst.c.category_id).all()
    # [(<Category 'Python'>, 2)]
    

    使用别名(aliased)

    SQLAlchemy 使用 aliased() 方法表示别名,当我们需要把同一张表连接多次的时候,常常需要用到别名。以下为其他文章的用法,可以做一个参考:

    from sqlalchemy.orm import aliased
    
    # 把 Address 表分别设置别名
    adalias1 = aliased(Address)
    adalias2 = aliased(Address)
    
    for username, email1, email2 in \
        session.query(User.name, adalias1.email_address, adalias2.email_address).\
        join(adalias1, User.addresses).\
        join(adalias2, User.addresses).\
        filter(adalias1.email_address=='jack@google.com').\
        filter(adalias2.email_address=='j25@yahoo.com'):
        
        print(username, email1, email2)
    
    # 执行结果
    jack jack@google.com j25@yahoo.com
    

    【参考链接】

    展开全文
  • SQLAlchemy使用方法

    2019-07-28 21:42:09
    SQLAlchemy学习记录 一、关系定义 (一)一对多关系 onetomany 表示一对多的关系时,在子表类中通过 foreign key (外键)引用父表类。 然后,在父表类中通过 relationship() 方法来引用子表的类: class User(Base): ...
  • SQLAlchemy用法

    2018-09-19 15:12:08
    链接:https://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/0014021031294178f993c85204e4d1b81ab032070641ce5000
  • SQLAlchemy使用教程

    2022-07-31 00:51:50
    ORM(ObjectRelationalMapping,对象关系映射)可以绕过SQL语句,把数据库的table(表)映射为编程语言的class(类),可以直接使用编程语言的对象模型操作数据库,而不使用SQL语句。ORM把表映射成类,把行作为实例,...
  • 1.2、为什么要使用SQLAlchemy? 它将你的代码从底层数据库及其相关的SQL特性中抽象出来。 1.3、SQLAlchemy提供了两种主要的使用模式 SQL表达式语言(SQLAlchemy Core) ORM 1.4、应该选择哪种模式? 虽然你使用的...
  • from sqlalchemy import create_engine import pandas as pd # 不同数据库使用不同引擎 # mysql 需安装pymysql engine = create_engine('mysql+pymysql://用户名:密码@hostIP:端口号/数据库名') # postgre 需安装...
  • Flask-SQLAlchemy使用方法

    2018-07-03 18:37:00
    Flask-SQLAlchemy使用起来非常有趣,对于基本应用十分容易使用,并且对于大型项目易于扩展。有关完整的指南,请参阅 SQLAlchemy 的 API 文档。 常见情况下对于只有一个 Flask 应用,所有我们需要做的事情就是创建 ...
  • 1.初始化连接from sqlalchemy import create_enginefrom sqlalchemy.orm import sessionmakerengine = create_engine('mysql://pass@localhost/test'echo=True)DBSession = sessionmaker(bind=engine)session = ...
  • 文章目录连接数据库(mysql)通过已有表,生成对应model 连接数据库(mysql) 通过已有表,生成对应model
  • sqlalchemy的基本使用

    2022-06-24 10:59:27
    基本使用 更多数据库操作 附录 1.链接:Session、sessionmaker、scoped_session相关资料 2.接近原生的sqlalchemy操作 链接-查询:sqlalchemy-查询 链接-更新,插入,删除:sqlalchemy-更新,插入,删除 3.会话通过...
  • SQLALCHEMY的简单使用

    2020-10-26 22:19:37
    SQLAlchemy 声明 写这篇文章的目的只是为了自己在遇到问题时方便查找,文中会有SqlAlchemy官方文档...使用SQLAlchemy的第一步是创建一个数据库连接,这里使用的是mysql数据库 from sqlalchemy import create_engine eng
  • Flask-SQLAlchemy使用

    2021-08-27 20:46:11
    Flask-SQLAlchemy使用_对SQLAlchemy进行了封装和优化: Flask-SQLAlchemy是一个插件 Flask-SQLAlchemy是对SQLAlchemy进行了一个简单的封装的一个插件, flask中使用sqlalchemy更加的简单。 1.安装: pip ...
  • SQLAlchemy的基本用法

    千次阅读 2019-06-29 22:12:22
    增删改查简单查询改状态删除复杂查询(AND条件,OR条件,NOT条件,IN条件,Like条件),用到了过滤器排序分页 (limit)消费者方法聚合,分组(分组其实就是按字段查询)总结 ORM ORM,对象关系映射,对象和关系之间的映射,使用...
  • 缓存池超过使用的范围,连接超时 sqlalchemy.exc.TimeoutError: QueuePool limit of size 10 overflow 10 reached, connection timed out, timeout 10 (Background on this error at: http://sqlalche.me/e/3o7r) ...
  • flask-sqlalchemy用法简介

    2019-05-26 21:38:27
    # -*- coding: utf-8 -*- # @Time : 2019/5/26 20:54 # @Author : dailinqing # @Email : dailinqing@126.com # @File : flask_db.py # @Software: PyCharm from flask_sqlalchemy import SQLAlchemy fro...
  • 本文将以Mysql举例,介绍sqlalchemy的基本用法。其中,Python版本为2.7,sqlalchemy版本为1.1.6。 一. 介绍 SQLAlchemy是Python中最有名的ORM工具。 关于ORM: 全称Object Relational Mapping(对象关系映射)。 ...
  • 1 ORM框架SQLAlchemy SQLAlchemy作用是提供简单的规则,自动转换成SQL语句 2 ORM框架两种模式 DB first: 手动创建数据库以及表 -> ORM框架 -> 自动生成类 code first: 手动创建类、和数据库 ->...
  • SqlAlchemy使用

    2021-03-10 09:15:44
    Title:20.Python笔记之SqlAlchemy使用 Tags:python Category:Python 作者:刘耀 博客:www.liuyao.me 一、SQLAlchemy SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射...
  • SQLAlchemy 简单用法

    2019-10-22 16:11:51
    安装SQLAlchemy ...使用 SQLAlchemy 1. 创建连接 engine = create_engine(r'sqlite:///C:\test.db') 2. 声明映射 from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Integ...
  • Flask-SQLAlchemy安装和建表操作请参考这里。 复制代码 代码如下:# Role表class Role(db.Model): id=db.Column(db.Integer,primary_key=True) name=db.Column(db.String(80))# RoleType表class Role_type(db....
  • 主要介绍了python数据库操作mysql:pymysql、sqlalchemy常见用法,结合实例形式分析了Python mysql操作库pymysql、sqlalchemy基本使用技巧与操作注意事项,需要的朋友可以参考下

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 15,741
精华内容 6,296
关键字:

sqlalchemy用法