Zetknąłem się z tym problemem, gdy próbowałem zapisać model Peewee w PostgreSQL JSONField
.
Po krótkich zmaganiach oto ogólne rozwiązanie.
Kluczem do mojego rozwiązania jest przejrzenie kodu źródłowego Pythona i uświadomienie sobie, że dokumentacja kodu (opisana tutaj ) już wyjaśnia, jak rozszerzyć istniejący, json.dumps
aby obsługiwał inne typy danych.
Załóżmy, że masz model, który zawiera niektóre pola, które nie są serializowane do JSON, a model zawierający pole JSON początkowo wygląda następująco:
class SomeClass(Model):
json_field = JSONField()
Po prostu zdefiniuj niestandardowy JSONEncoder
taki sposób:
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)
A potem po prostu użyj go JSONField
jak poniżej:
class SomeClass(Model):
json_field = JSONField(dumps=CustomJsonEncoder.json_dumper)
Kluczem jest default(self, obj)
powyższa metoda. Do każdej ... is not JSON serializable
skargi otrzymywanej od Pythona wystarczy dodać kod, aby obsłużyć typ, który nie może zostać przekształcony w JSON (taki jak Enum
lub datetime
)
Na przykład oto, jak popieram klasę dziedziczącą z 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)
Wreszcie, dzięki zaimplementowanemu kodowi, jak powyżej, możesz po prostu przekonwertować dowolne modele Peewee na obiekt, który może być seriazowalny w JSON, jak poniżej:
peewee_model = WhateverPeeweeModel()
new_model = SomeClass()
new_model.json_field = model_to_dict(peewee_model)
Chociaż powyższy kod był (nieco) specyficzny dla Peewee, ale myślę:
- Dotyczy to ogólnie innych ORM (Django itp.)
- Ponadto, jeśli rozumiesz, jak to
json.dumps
działa, to rozwiązanie działa również ogólnie z Pythonem (bez ORM)
Wszelkie pytania prosimy pisać w sekcji komentarzy. Dzięki!