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
複製代碼
相關文章
相關標籤/搜索