python sqlalchemy 查询最佳实践

整理了一下 python sqlalchemy的使用方法

一个Query对象使用所建立的 query()上方法 Session。此函数采用可变数量的参数,这些参数能够是类和类检测描述符的任意组合。下面,咱们指出 Query哪一个加载User实例。在迭代上下文中计算时,将User返回存在的对象列表:python

for instance in session.query(User).order_by(User.id):
···    print(instance.name, instance.fullname)
ed Ed Jones
wendy Wendy Williams
mary Mary Contrary
fred Fred Flintstone
复制代码

该Query还接受ORM,仪表描述做为参数。每当多个类实体或基于列的实体表示为函数的参数时 query(),返回结果表示为元组:sql

for name, fullname in session.query(User.name, User.fullname):
...     print(name, fullname)
ed Ed Jones
wendy Wendy Williams
mary Mary Contrary
fred Fred Flintstone
复制代码

返回的元组Query被命名为 元组,由KeyedTuple类提供,而且能够像普通的Python对象同样对待。名称与属性的属性名称以及类的类名称相同:数据库

for row in session.query(User, User.name).all():
...    print(row.User, row.name)
<User(name='ed', fullname='Ed Jones', nickname='eddie')> ed
<User(name='wendy', fullname='Wendy Williams', nickname='windy')> wendy
<User(name='mary', fullname='Mary Contrary', nickname='mary')> mary
<User(name='fred', fullname='Fred Flintstone', nickname='freddy')> fred
复制代码

您可使用label()构造控制各个列表达式的名称,该 构造能够从任何ColumnElement派生对象得到,也能够映射到一个(例如User.name)的任何类属性:express

for row in session.query(User.name.label('name_label')).all():
...    print(row.name_label)
ed
wendy
mary
fred
复制代码

给予完整实体的名称,例如User,假设调用中存在多个实体query(),可使用aliased()如下方法控制 :数组

from sqlalchemy.orm import aliased
>>> user_alias = aliased(User, name='user_alias')

>>> for row in session.query(user_alias, user_alias.name).all():
...    print(row.user_alias)
<User(name='ed', fullname='Ed Jones', nickname='eddie')>
<User(name='wendy', fullname='Wendy Williams', nickname='windy')>
<User(name='mary', fullname='Mary Contrary', nickname='mary')>
<User(name='fred', fullname='Fred Flintstone', nickname='freddy')>
复制代码

基本操做Query包括发出LIMIT和OFFSET,最方便的是使用Python数组切片,一般与ORDER BY结合使用:bash

for u in session.query(User).order_by(User.id)[1:3]:
...    print(u)
<User(name='wendy', fullname='Wendy Williams', nickname='windy')>
<User(name='mary', fullname='Mary Contrary', nickname='mary')>
复制代码

和过滤结果,使用 filter_by(),使用关键字参数完成:session

for name, in session.query(User.name).\
...             filter_by(fullname='Ed Jones'):
...    print(name)
ed
复制代码

或者filter(),它使用更灵活的SQL表达式语言结构。这些容许您使用常规Python运算符和映射类的类级属性:函数

for name, in session.query(User.name).\
...             filter(User.fullname=='Ed Jones'):
...    print(name)
ed
复制代码

该Query对象是彻底生成的,这意味着大多数方法调用返回一个新Query 对象,能够在其上添加进一步的标准。例如,要查询名为“ed”且名称为“Ed Jones”的用户,能够调用 filter()两次,使用AND如下命令链接条件 :ui

for user in session.query(User).\
...          filter(User.name=='ed').\
...          filter(User.fullname=='Ed Jones'):
...    print(user)
<User(name='ed', fullname='Ed Jones', nickname='eddie')>
复制代码

公共过滤运算符

如下是一些最经常使用的运算符的概述 filter():spa

  • equals:

    query.filter(User.name == 'ed')
    复制代码
  • not equals:

    query.filter(User.name != 'ed')
    复制代码
  • LIKE:

    query.filter(User.name.like('%ed%'))
    复制代码
  • ILIKE (不区分大小写的LIKE):

    query.filter(User.name.ilike('%ed%'))
    复制代码
  • IN:

    query.filter(User.name.in_(['ed', 'wendy', 'jack']))
    
    # works with query objects too:
    query.filter(User.name.in_(
        session.query(User.name).filter(User.name.like('%ed%'))
    ))
    复制代码
  • NOT IN:

    query.filter(~User.name.in_(['ed', 'wendy', 'jack']))
    复制代码
  • IS NULL:

    query.filter(User.name == None)
    
    # alternatively, if pep8/linters are a concern
    query.filter(User.name.is_(None))
    复制代码
  • IS NOT NULL:

    query.filter(User.name != None)
    
    # alternatively, if pep8/linters are a concern
    query.filter(User.name.isnot(None))
    复制代码
  • AND:

    # use and_()
    from sqlalchemy import and_
    query.filter(and_(User.name == 'ed', User.fullname == 'Ed Jones'))
    
    # or send multiple expressions to .filter()
    query.filter(User.name == 'ed', User.fullname == 'Ed Jones')
    
    # or chain multiple filter()/filter_by() calls
    query.filter(User.name == 'ed').filter(User.fullname == 'Ed Jones')
    复制代码
  • OR:

    from sqlalchemy import or_
    query.filter(or_(User.name == 'ed', User.name == 'wendy'))
    复制代码
  • MATCH:

    query.filter(User.name.match('wendy'))
    复制代码

返会列表和常量

有许多方法能够Query 当即发出SQL并返回包含已加载数据库结果的值。这是一个简短的旅游:

  • all() 返回一个列表:

    >>> query = session.query(User).filter(User.name.like('%ed')).order_by(User.id)
    >>> query.all()
    [<User(name='ed', fullname='Ed Jones', nickname='eddie')>,
     <User(name='fred', fullname='Fred Flintstone', nickname='freddy')>]
    复制代码
  • first() 应用限制为1并将第一个结果做为标量返回:

    >>> query.first()
    <User(name='ed', fullname='Ed Jones', nickname='eddie')>
    复制代码
  • one()彻底提取全部行,若是结果中不存在一个对象标识或复合行,则会引起错误。找到多行:

    >>> user = query.one()
    Traceback (most recent call last):
    ...
    MultipleResultsFound: Multiple rows were found for one()
    复制代码

    找不到行:

    >>> user = query.filter(User.id == 99).one()
    Traceback (most recent call last):
    ...
    NoResultFound: No row was found for one()
    复制代码

    该one()方法适用于但愿处理“找不到任何项目”而不是“找到多个项目”的系统; 例如RESTful Web服务,可能但愿在找不到结果时引起“未找到404”,但在找到多个结果时引起应用程序错误。

  • one_or_none()就像one(),除非没有找到结果,它不会引发错误; 它只是回来了None。像 one(),可是,它若是有多个结果发现引起错误。

  • scalar()调用该one()方法,并在成功时返回该行的第一列:

    >>> query = session.query(User.id).filter(User.name == 'ed').\
    ...    order_by(User.id)
    SQL>>> query.scalar()
    1
    复制代码

使用文本

Query经过指定它们与text()构造的使用,能够灵活地使用文字字符串 ,这是大多数适用方法所接受的。例如, filter()和 order_by():

>>> from sqlalchemy import text
>>> for user in session.query(User).\
...             filter(text("id<224")).\
...             order_by(text("id")).all():
...     print(user.name)
ed
wendy
mary
fred
复制代码

可使用冒号使用基于字符串的SQL指定绑定参数。要指定值,请使用如下params() 方法:

>>> session.query(User).filter(text("id<:value and name=:name")).\
...     params(value=224, name='fred').order_by(User.id).one()
<User(name='fred', fullname='Fred Flintstone', nickname='freddy')>
复制代码

要使用彻底基于字符串的语句,text()能够将表示完整语句的构造传递给 from_statement()。若是没有其余说明符,字符串SQL中的列将根据名称与模型列匹配,例以下面咱们只使用星号表示加载全部列:

>>> session.query(User).from_statement(
...                     text("SELECT * FROM users where name=:name")).\
...                     params(name='ed').all()
[<User(name='ed', fullname='Ed Jones', nickname='eddie')>]
复制代码

匹配名称上的列适用于简单的状况,但在处理包含重复列名的复杂语句或使用不易与特定名称匹配的匿名ORM构造时可能会变得难以处理。此外,咱们的映射列中存在键入行为,咱们在处理结果行时可能会发现这些行为。对于这些状况,text()构造容许咱们在位置上将其文本SQL连接到Core或ORM映射的列表达式; 咱们能够经过将列表达式做为位置参数传递给TextClause.columns()方法来实现这一点 :

>>> stmt = text("SELECT name, id, fullname, nickname "
...             "FROM users where name=:name")
>>> stmt = stmt.columns(User.name, User.id, User.fullname, User.nickname)
SQL>>> session.query(User).from_statement(stmt).params(name='ed').all()
[<User(name='ed', fullname='Ed Jones', nickname='eddie')>]
复制代码

从text()构造中进行选择时,Query 仍然能够指定要返回的列和实体; 而不是 query(User)咱们也能够单独要求列,如在任何其余状况下:

>>> stmt = text("SELECT name, id FROM users where name=:name")
>>> stmt = stmt.columns(User.name, User.id)
SQL>>> session.query(User.id, User.name).\
...          from_statement(stmt).params(name='ed').all()
[(1, u'ed')]
复制代码

计数

Query包括一种方便的计数方法count():

>>> session.query(User).filter(User.name.like('%ed')).count()
2
复制代码

该count()方法用于肯定SQL语句将返回多少行。查看上面生成的SQL,SQLAlchemy老是将咱们查询的内容放入子查询中,而后从中计算行数。在某些状况下,这能够简化为更简单,但SQLAlchemy的现代版本不会尝试猜想什么时候合适,由于可使用更明确的方法发出确切的SQL。

SELECT count(*) FROM table
复制代码

对于须要具体指出“要计数的东西”的状况,咱们能够直接使用构造中func.count()可用 的表达式指定“计数”函数func。下面咱们用它来返回每一个不一样用户名的计数:

>>> from sqlalchemy import func
>>> session.query(func.count(User.name), User.name).group_by(User.name).all()
[(1, u'ed'), (1, u'fred'), (1, u'mary'), (1, u'wendy')]
复制代码

为了实现咱们的简单,咱们能够将其应用为:SELECT count(*) FROM table

>>> session.query(func.count('*')).select_from(User).scalar()
4
复制代码

select_from()若是咱们User直接用主键表示计数,则能够删除用法:

>>> session.query(func.count(User.id)).scalar()
4
复制代码
相关文章
相关标签/搜索