Peewee模型转JSON

35

我正在使用peewee作为ORM创建一个API,我需要将peewee模型对象转换成JSON对象并发送给用户。有没有好的方法可以做到这一点?


10
请考虑更改最佳答案。看一下投票情况... - coleifer
7个回答

113

Peewee在playhouse.shortcuts扩展模块中提供了model_to_dictdict_to_model助手。

您可以按以下方式使用它们:

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))

请注意,model_to_dict() 可以递归处理相关模型,包括被反向引用的模型,并排除某些字段不被序列化。


1
@coleifar!如何导入model_to_dict() - Zaaferani
1
from playhouse.shortcuts import * - Michael Dorner
6
from playhouse.shortcuts import model_to_dict, dict_to_model - Arel
3
@coleifer,您能否在具有多个项目的SelectQuery对象上以这种方式使用model_to_dict(即不使用.get())?我要么看到一个错误消息,如'SelectQuery' object has no attribute '_meta',要么如果表包含UUID字段,则会看到Object of type 'UUID' is not JSON serializable - AdjunctProfessorFalcon
1
在这种情况下,UUID错误不是peewee问题,而是uuid.UUID -> json.dumps没有默认调用str或repr来处理非字符串对象。 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
显示剩余2条评论

8

当单次获取时

user = User.select().where(User.id == 1).get()
model_to_dict(user)  #to Dict

当进行多个fetch时

users = list(User.select().where(User.name ** 'a%').dicts()) 

4
此外,您可以将模型作为字典获取,并使用正确的字段类型(布尔值、整数、浮点数等)转换为JSON:
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)

如果User模型有一个created = DateTimeField(),那么json.dumps(user)会报告datetime.datetime实例无法序列化为JSON。在这种情况下,我该如何处理datetime字段? - Roland Pish
1
@Roland 请尝试使用此答案中的解决方案:`from bson import json_util` `print json.dumps(user, default=json_util.default)` - kiba
问题在于我没有使用mongodb。尽管我尝试使用Python内置的bson,但得到了类似于'{"born": {"$date": 1399579518000}, "name": "John Smith"}'的东西。而尝试使用这个:https://pypi.python.org/pypi/bson/0.3.3 则导致应用程序崩溃。不过还是谢谢你的提示。 - Roland Pish

3

对于遇到类似 TypeError: Object of type date is not JSON serializable 的问题,这是我的解决方案(在 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))

用法1 - 单个模型

for person in Person.select():
    print_model(person)

用法2 - 多个模型

print_models(Person.select())

1
我曾遇到同样的问题,最终定义了自己的解析器扩展来处理无法自动序列化的JSON类型。目前,我使用字符串作为数据表示(虽然你可能可以使用不同的数据类型,但要注意使用浮点数时的近似值!)
在下面的示例中,我将其放入名为“json_serialize.py”的文件中,该文件位于“utils”文件夹中:
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)

然后,在我的应用程序中:
import json
from utils import json_serialize

...


json.dumps(model_to_dict(User.get()), default=json_serialize.more)

编辑以添加:这主要受到mongodb中发现的json_utils.default模块的启示,但主要依赖于json模块,不需要导入mongodb自己的bson / json_utils模块。

通常,我会在应用程序引发TypeError未能序列化的类型时立即更新它以支持新类型。


0

我通常实现模型到字典和字典到模型的函数,以获得最大的安全性和对代码内部工作的理解。Peewee做了很多魔法,你希望能够控制它。

明显的原因是为什么你不应该在字段上进行迭代而是明确指定它们,这是出于安全考虑。并非所有字段都可以暴露给用户,我假设你需要这个功能来实现某种REST API。

所以 - 你应该像这样做:

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']
        )

-8
你可以这样做:
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

1
记得执行 json.dumps(str(user)) 而不是 json.dumps(user) - Matthew Moisen
40
这种方法并不是一个很好的完成这个任务的方式。我强烈建议查看Peewee的model_to_dict()助手,它专门为此目的而设计。您可以在这里找到文档(http://docs.peewee-orm.com/en/latest/peewee/playhouse.html#model_to_dict)。它还有一个好处,就是能够递归或排除字段。 - coleifer
7
为什么这是推荐答案?StackOverflow失败了。 - coleifer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接