2016-04-05 6 views
6

私はSQLAlchemyのコアライブラリを使用していくつかのPostgreSQLデータベースにアクセスしています。SQLAlchemyのPostgreSQL JSONB実装にカスタムJSONエンコーダを使用する

create table foo (j jsonb); 

そして、次のpythonコード:

StatementError("(builtins.TypeError) Decimal('2') is not JSON serializable",) 

私はこれを求めています理由:この最後の文は、次のエラーで失敗し

​​

私は、次の表を持って考えてみましょう質問:PostgreSQLの方言にjsonデータをエンコードするときに使用するSQLAchemy用のカスタムエンコーダを指定する方法はありますか?

答えて

11

sqlalchemy.dialects.postgresql.JSONの下に記載されているようにこれは、create_enginejson_serializerキーワード引数を経由してサポートされています。

def _default(val): 
    if isinstance(val, Decimal): 
     return str(val) 
    raise TypeError() 

def dumps(d): 
    return json.dumps(d, default=_default) 

engine = create_engine(..., json_serializer=dumps) 
+0

恐ろしいです。ドキュメントのその部分を逃した。明日それを試し、それに応じて答えを受け入れます。ありがとう!! –

3

あなたは、私のように、フラスコSQLAlchemyので、このランニングを取得するための良い方法を見つけている場合は、これは何ですかやった。標準ライブラリjsonモジュールの代わりにflask.jsonをインポートして渡すと、日付、日付時刻、uuid.UUIDインスタンスの自動逆シリアル化が行われます。

class HackSQLAlchemy(SQLAlchemy): 
    """ Ugly way to get SQLAlchemy engine to pass the Flask JSON serializer 
    to `create_engine`. 

    See https://github.com/mitsuhiko/flask-sqlalchemy/pull/67/files 

    """ 

    def apply_driver_hacks(self, app, info, options): 
     options.update(json_serializer=json.dumps) 
     super(HackSQLAlchemy, self).apply_driver_hacks(app, info, options) 
1

あなたはフラスコを使用している場合、あなたはすでにUUIDを扱うflask.jsonで定義された拡張JSONEncoderを持っていますが、ないDecimal。これは、@ univerioの答えのようにjson_serializerのparamとSQLAlchemyのエンジンにマップすることができます。

from flask import json 

engine = create_engine(
    app.config['SQLALCHEMY_DATABASE_URI'], 
    convert_unicode=True, 
    json_serializer=json.dumps, 
) 

あなたは、さらに次のようにdecimal.Decimalをサポートするために、フラスコJSONEncoderを拡張することができます

import decimal 

from flask import json 

class CustomJSONEncoder(json.JSONEncoder): 
    """ 
    Override Flask's JSONEncoder with the single method `default`, which 
    is called when the encoder doesn't know how to encode a specific type. 
    """ 
    def default(self, obj): 
     if type(obj) is decimal.Decimal: 
      return str(obj) 
     else: 
      # raises TypeError: obj not JSON serializable 
      return json.JSONEncoder.default(self, obj) 

def init_json(app): 
    """ 
    Use custom JSON encoder with Flask 
    """ 
    app.json_encoder = CustomJSONEncoder 
関連する問題