2016-04-05 12 views
6

Ich benutze die SQLAlchemy-Core-Bibliothek, um auf einige PostgreSQL-Datenbanken zuzugreifen. Betrachte Ich habe die folgende Tabelle:Verwenden eines benutzerdefinierten JSON-Encoders für SQLAlchemy's PostgreSQL-JSONB-Implementierung

create table foo (j jsonb); 

Und den folgenden Python-Code:

from decimal import * 
from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey, DateTime 
from sqlalchemy.dialects.postgresql import JSONB 
metadata = MetaData(schema="public") 
foo = Table('foo', metadata,Column('f', JSONB)) 
d = Decimal(2) 
ins = foo.insert().values(j = {'d': d}) 
# assuming engine is a valid sqlalchemy's connection 
engine.execute(ins) 

Dieser letzte Satz mit dem folgenden Fehler fehl:

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

, weshalb ich dies zu fragen Frage: Gibt es eine Möglichkeit, einen benutzerdefinierten Encoder für SQLAchemy anzugeben, der beim Kodieren von JSON-Daten im PostgreSQL-Dialekt verwendet werden soll?

Antwort

11

Dies geschieht über das json_serializer Schlüsselwort-Argument unterstützt create_engine, wie unter sqlalchemy.dialects.postgresql.JSON dokumentiert:

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

Ehrfürchtig Es kann mit dem json_serializer param wie in @ univerio Antwort in den sqlalchemy Motor abgebildet werden. Habe diesen Teil der Dokumentation verpasst. Werde es morgen versuchen und die Antwort entsprechend akzeptieren. Vielen Dank!! –

3

Wenn Sie, wie ich, sind eine schöne Art und Weise zu finden, das mit Flask-SQLAlchemy zum Laufen zu bekommen, ist es das, was Ich tat. Wenn Sie flask.json anstelle des Standardmoduls json importieren und übergeben, erhalten Sie eine automatische Deserialisierung von Datumsangaben, Datumsangaben und uuid.UUID Instanzen.

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

Wenn Sie Flask verwenden, haben Sie bereits eine erweiterte JSONEncoder in flask.json definiert, die UUID Griffe, aber Decimal nicht.

from flask import json 

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

Sie können weiter ausbauen den Kolben JSONEncoder unterstützen decimal.Decimal mit folgendem:

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 
Verwandte Themen