web-dev-qa-db-ja.com

cx_Oracle:各行を辞書として受け取るにはどうすればよいですか?

デフォルトでは、cx_Oracleは各行をタプルとして返します。

>>> import cx_Oracle
>>> conn=cx_Oracle.connect('scott/tiger')
>>> curs=conn.cursor()
>>> curs.execute("select * from foo");
>>> curs.fetchone()
(33, 'blue')

各行を辞書として返すにはどうすればよいですか?

12
Mark Harrison

カーソルのrowfactoryメソッドをオーバーライドできます。クエリを実行するたびにこれを行う必要があります。

これが標準クエリの結果であるタプルです。

curs.execute('select * from foo')
curs.fetchone()
    (33, 'blue')

名前付きタプルを返す:

def makeNamedTupleFactory(cursor):
    columnNames = [d[0].lower() for d in cursor.description]
    import collections
    Row = collections.namedtuple('Row', columnNames)
    return Row

curs.rowfactory = makeNamedTupleFactory(curs)
curs.fetchone()
    Row(x=33, y='blue')

辞書を返す:

def makeDictFactory(cursor):
    columnNames = [d[0] for d in cursor.description]
    def createRow(*args):
        return dict(Zip(columnNames, args))
    return createRow

curs.rowfactory = makeDictFactory(curs)
curs.fetchone()
    {'Y': 'brown', 'X': 1}

Amaury Forgeot d'Arcのクレジット: http://sourceforge.net/p/cx-Oracle/mailman/message/27145597

16
Mark Harrison

非常に短いバージョン:

curs.rowfactory = lambda *args: dict(Zip([d[0] for d in curs.description], args))

Python 3.7.0&cx_Oracle7.1.2でテスト済み

2
maelcum73

古い質問ですが、Pythonレシピ

_cx_Oracle_のドキュメントによると:

Cursor.rowfactory

この読み取り/書き込み属性は、データベースから取得される各行を呼び出すメソッドを指定します。 通常、行ごとにタプルが返されますが、この属性が設定されている場合、メソッドは次のタプルで呼び出されます。通常は返され、代わりにメソッドの結果が返されます

cx_Oracle-Python Oracle Databaseのインターフェース また、GitHubリポジトリを指し、多くの役立つ サンプル 例を示しています。 GenericRowFactory .py

Googled:これはPPTさらに役立つ可能性があります: [PDF]CON6543 PythonおよびOracleデータベース-RainFocus

レシピ

内部のOracle用のDjangoデータベースバックエンドはcx_Oracleを使用します。以前のバージョン(Django 1.11-)では _rowfactory(cursor, row) これは、cx_Oracleの数値データ型を関連するPythonデータと文字列をUnicodeにキャストします。

Djangoをインストールした場合は、次のようにbase.pyを確認してください。

_$ Django_DIR="$(python -c 'import Django, os; print(os.path.dirname(Django.__file__))')"
$ vim $Django_DIR/db/backends/Oracle/base.py
_

_$Django_DIR/db/backends/Oracle/base.py_から_rowfactory()を借りて、デコレータnamingの下に適用して、単純なnamedtupleの代わりにTupleを返すことができます。

mybase.py

_import functools
from itertools import izip, imap
from operator import itemgetter
from collections import namedtuple
import cx_Oracle as Database
import decimal

def naming(rename=False, case=None):
    def decorator(rowfactory):
        @functools.wraps(rowfactory)
        def decorated_rowfactory(cursor, row, typename="GenericRow"):
            field_names = imap(case, imap(itemgetter(0), cursor.description))
            return namedtuple(typename, field_names)._make(rowfactory(cursor, row))
        return decorated_rowfactory
    return decorator
_

次のように使用します。

_@naming(rename=False, case=str.lower)
def rowfactory(cursor, row):
   casted = []
   ....
   ....
   return Tuple(casted)
_

Oracle.py

_import cx_Oracle as Database
from cx_Oracle import *
import mybase

class Cursor(Database.Cursor):

    def execute(self, statement, args=None):
        prepareNested = (statement is not None and self.statement != statement)
        result = super(self.__class__, self).execute(statement, args or [])
        if prepareNested:
            if self.description:
                self.rowfactory = lambda *row: mybase.rowfactory(self, row)
        return result

    def close(self):
        try:
            super(self.__class__, self).close()
        except Database.InterfaceError:
            "already closed"

class Connection(Database.Connection):

    def cursor(self):
        Cursor(self)

connect = Connection
_

ここで、cx_Oracleをインポートする代わりに、ユーザースクリプトでOracleを次のようにインポートします。

user.py

_import Oracle

dsn = Oracle.makedsn('HOSTNAME', 1521, service_name='dev_server')
db = connect('username', 'password', dsn)
cursor = db.cursor()
cursor.execute("""
  SELECT 'Grijesh' as FirstName, 
         'Chauhan' as LastName,
         CAST('10560.254' AS NUMBER(10, 2)) as Salary
  FROM DUAL
""")
row = cursor.fetchone()
print ("First Name is %s" % row.firstname) # => Grijesh
print ("Last Name is %s" % row.lastname) # => Chauhan
print ("Salary is %r" % row.salary) # => Decimal('10560.25')
_

試してみる!!

0
Grijesh Chauhan