Ho riscontrato questo problema quando ho provato a memorizzare il modello di Peewee in PostgreSQL JSONField.
Dopo aver lottato per un po ', ecco la soluzione generale.
La chiave della mia soluzione sta passando attraverso il codice sorgente di Python e rendendosi conto che la documentazione del codice (descritta qui ) spiega già come estendere l'esistente json.dumpsper supportare altri tipi di dati.
Supponiamo che tu abbia attualmente un modello che contiene alcuni campi che non sono serializzabili su JSON e che il modello che contiene il campo JSON originariamente assomiglia a questo:
class SomeClass(Model):
json_field = JSONField()
Basta definire un'usanza JSONEncodercome questa:
class CustomJsonEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, SomeTypeUnsupportedByJsonDumps):
return < whatever value you want >
return json.JSONEncoder.default(self, obj)
@staticmethod
def json_dumper(obj):
return json.dumps(obj, cls=CustomJsonEncoder)
E poi usalo nel tuo JSONFieldlike qui sotto:
class SomeClass(Model):
json_field = JSONField(dumps=CustomJsonEncoder.json_dumper)
La chiave è il default(self, obj)metodo sopra. Per ogni singolo ... is not JSON serializablereclamo ricevuto da Python, basta aggiungere il codice per gestire il tipo non serializzabile-JSON (come Enumodatetime )
Ad esempio, ecco come supporto una classe che eredita da Enum:
class TransactionType(Enum):
CURRENT = 1
STACKED = 2
def default(self, obj):
if isinstance(obj, TransactionType):
return obj.value
return json.JSONEncoder.default(self, obj)
Infine, con il codice implementato come sopra, puoi semplicemente convertire qualsiasi modello Peewee in un oggetto seriazabile JSON come sotto:
peewee_model = WhateverPeeweeModel()
new_model = SomeClass()
new_model.json_field = model_to_dict(peewee_model)
Anche se il codice sopra era (in qualche modo) specifico di Peewee, ma penso:
- È applicabile ad altri ORM (Django, ecc.) In generale
- Inoltre, se hai capito come
json.dumpsfunziona, questa soluzione funziona anche con Python (sans ORM) in generale
Per qualsiasi domanda, si prega di pubblicare nella sezione commenti. Grazie!