I'm creating an API using peewee as the ORM and I need the ability to convert a peewee model object into a JSON object to send to the user. Does anyone know of a good way to do this?
-
10Please consider changing the best answer. Take a look at the votes... – coleifer Feb 17 '17 at 02:05
7 Answers
Peewee has a model_to_dict
and dict_to_model
helpers in the playhouse.shortcuts
extension module.
- http://docs.peewee-orm.com/en/latest/peewee/playhouse.html#model_to_dict
- http://docs.peewee-orm.com/en/latest/peewee/playhouse.html#dict_to_model
You could use these as follows:
from playhouse.shortcuts import model_to_dict, dict_to_model
user_obj = User.select().where(User.username == 'charlie').get()
json_data = json.dumps(model_to_dict(user_obj))
Also note that model_to_dict()
can recurse through related models, include back-referenced models, and exclude certain fields from being serialized.
-
1
-
1
-
6
-
3@coleifer can you use ```model_to_dict``` this way on a ```SelectQuery``` object that has multiple items (i.e. that doesn't use ```.get()``` ) ? I'm either seeing an error message like ```'SelectQuery' object has no attribute '_meta'``` or if the table contains a UUID field ```Object of type 'UUID' is not JSON serializable``` – AdjunctProfessorFalcon Nov 14 '17 at 19:23
-
@AdjunctProfessorFalcon did you work out how to get around the "'UUID' is not JSON serializable"? I'm having the same issue. – ranni rabadi Jan 14 '19 at 03:41
-
1In this case the UUID error is not a peewee issue but a uuid.UUID -> json.dumps not defaulting to call str or repr on a non string like object. `import json; import uuid; x = uuid.uuid4(); json.dumps(x);` `Traceback (most recent call last): ... TypeError: Object of type 'UUID' is not JSON serializable` – dingus9 May 24 '19 at 17:09
-
states = list(User.select().where(State.username ** 'a%').dicts() ) use this when you get multiple rows – Pramit Sawant Nov 19 '19 at 10:12
when single fetch
user = User.select().where(User.id == 1).get()
model_to_dict(user) #to Dict
when Multiple fetch
users = list(User.select().where(User.name ** 'a%').dicts())

- 682
- 1
- 9
- 17
also, you can get model as a dict, and then convert to json with correct field types (bool, int, float, etc.):
import peewee
import json
from bson import json_util
from datetime import datetime
class User(peewee.Model):
email = CharField()
status = BooleanField(default=True)
firstname = CharField()
lastname = CharField()
age = IntegerField()
created = DateTimeField(default=datetime.now())
class Meta:
database = db
user = User.select().dicts().get()
print json.dumps(user, default=json_util.default)

- 1,355
- 9
- 7
-
If the User model had a `created = DateTimeField()` then json.dumps(user) would complain about the datetime.datetime instance not be JSON serializable. What could I do in this case with datetime fields? – Roland Pish Aug 12 '14 at 02:10
-
1@Roland try solution from [this answer](http://stackoverflow.com/a/11875813/1270607): `from bson import json_util` `print json.dumps(user, default=json_util.default)` – kiba Aug 12 '14 at 23:05
-
The problem is that I'm not using mongodb. Even though, trying to use the python builtin bson I got something like `'{"born": {"$date": 1399579518000}, "name": "John Smith"}'`. And trying to use this: https://pypi.python.org/pypi/bson/0.3.3 crashed the application. Thanks for the tip though. – Roland Pish Aug 14 '14 at 03:57
For anybody having issues like TypeError: Object of type date is not JSON serializable
, this works for me (tested on Python 3.8.2).
from playhouse.shortcuts import model_to_dict
import json
def print_model(model):
print(json.dumps(model_to_dict(model), indent=4, sort_keys=True, default=str))
def print_models(models):
print(json.dumps(list(models.dicts()), indent=4, sort_keys=True, default=str))
Usage 1 - Single model
for person in Person.select():
print_model(person)
Usage 2 - Many models
print_models(Person.select())

- 10,044
- 7
- 34
- 64
I had this very same problem and ended up defining my own parser extension for JSON types that could not be automatically serialized. I'm fine for now in using strings as data represented (although you could possibly use different datatypes, but beware of approximation using floating points!
In the following example, I put this in a file called json_serialize.py
inside a utils
folder:
from decimal import Decimal
import datetime
try:
import uuid
_use_uuid = True
except ImportError:
_use_uuid = False
datetime_format = "%Y/%m/%d %H:%M:%S"
date_format = "%Y/%m/%d"
time_format = "%H:%M:%S"
def set_datetime_format(fmt_string):
datetime_format = fmt_string
def set_date_format(fmt_string):
date_format = fmt_string
def set_time_format(fmt_string):
time_format = fmt_string
def more(obj):
if isinstance(obj, Decimal):
return str(obj)
if isinstance(obj, datetime.datetime):
return obj.strftime(datetime_format)
if isinstance(obj, datetime.date):
return obj.strftime(date_format)
if isinstance(obj, datetime.time):
return obj.strftime(time_format)
if _use_uuid and isinstance(obj, uuid.UUID):
return str(obj.db_value())
raise TypeError("%r is not JSON serializable" % obj)
Then, in my app:
import json
from utils import json_serialize
...
json.dumps(model_to_dict(User.get()), default=json_serialize.more)
edit just to add: this is very largely inspired by json_utils.default
module found in mongodb but mainly relies on the json
module and needs no import of mongodb own bson/json_utils module.
Usually I update it to support new types as soon as my app raises the TypeError
for it found a type not able to serialize

- 49
- 6
I usually implement the model to dict and dict to model functions, for maximum security and understanding of the inner workings of the code. Peewee does a lot of magic and you want to be in control over it.
The most obvious argument for why you should not iterate on the fields but rather explicitly specify them is because of security considerations. Not all fields can be exposed to the user, and I assume you need this functionality to implement some sort of REST API.
So - you should do something like this:
class UserData(db.Model):
user = db.ForeignKeyField(User)
data = db.CharField()
def serialize():
# front end does not need user ID here
return {
'data': self.data
}
@classmethod
def from_json(cls, json_data):
UserData.create(
# we enforce user to be the current user
user=current_user,
data=json_data['data']
)

- 3,852
- 3
- 30
- 34
you can do something like that:
class MyModel(peewee.Model):
def __str__(self):
r = {}
for k in self._data.keys():
try:
r[k] = str(getattr(self, k))
except:
r[k] = json.dumps(getattr(self, k))
return str(r)
class User(MyModel):
email = CharField()
status = CharField(default="enabled")
firstname = CharField()
lastname = CharField()
class Meta:
database = db

- 6,404
- 8
- 39
- 56
-
1Remember to do `json.dumps(str(user))` and not `json.dumps(user)` – Matthew Moisen Mar 23 '14 at 21:13
-
40This is really not a very good way to accomplish this. I'd strongly recommend checking out Peewee's `model_to_dict()` helper that was designed exactly for this purpose. You can find the docs [here](http://docs.peewee-orm.com/en/latest/peewee/playhouse.html#model_to_dict). It also has the benefit of being able to recurse or exclude fields. – coleifer Mar 26 '15 at 20:46
-
7