Flask API throws TypeError: Object of type is not JSON serializable

Flask API throws TypeError: Object of type is not JSON serializable

我正在构建一个 Flask API w/a Postgresql 数据库。我有两个主要模型,Contacts 和 Outlets 具有多对多关联。一切正常,直到我尝试使用关联 return 给定联系人的出口。我正在使用 flask-sqlalchemy 作为 ORM。下面的路线旨在检索单个联系人抛出:TypeError: Object of type Outlet is not JSON serializable

@contacts.get("/<int:id>")
@jwt_required()
def get_contact(id):
    contact = Contact.query.filter_by(id=id).first()

    print('contact-outlets are: ', contact.outlets[0])

    if not contact:

        return jsonify({'message':'Item not found'}), HTTP_404_NOT_FOUND

    return jsonify({
        'id':contact.id,
        'name':contact.name,
        'email':contact.email,
        'bio':contact.bio,
        'image_url':contact.image_url,
        'outlets':contact.outlets,
        'created_at':contact.created_at,
        'updated_at':contact.updated_at,
    }), HTTP_200_OK

如果有帮助,这里是数据库模式的相关部分:

from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
from sqlalchemy.orm import relationship

db = SQLAlchemy()

class Contact(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)
    bio = db.Column(db.Text, nullable=True)
    image_url = db.Column(db.Text)
    visits = db.Column(db.Integer, default=0)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    created_at = db.Column(db.DateTime, default=datetime.now())
    updated_at = db.Column(db.DateTime, onupdate=datetime.now())
    calls = db.relationship("Call", backref="call_contact", lazy="joined")
    outlets = db.relationship("Outlet", secondary="contact_outlet", backref="contact", lazy="joined")

    def __repr__(self) -> str:
        return 'Contact>>> {self.name}'

class Outlet(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), unique=True, nullable=False)
    website = db.Column(db.Text)
    description = db.Column(db.Text)
    image_url = db.Column(db.Text)
    created_at = db.Column(db.DateTime, default=datetime.now())
    updated_at = db.Column(db.DateTime, onupdate=datetime.now())
    calls = db.relationship("Call", backref="outlet", lazy="joined")
    contacts = db.relationship("Contact", secondary="contact_outlet", lazy="joined")

    def __repr__(self) -> str:
        return 'Outlet>>> {self.name}'

    def to_json(self):
        return {
            "id": self.id,
            "name": self.name,
            "website": self.website,
            "description": self.description,
            "image_url": self.image_url,
            "contacts": self.contacts
        }

contact_outlet = db.Table('contact_outlet',
    db.Column('contactId', db.Integer, db.ForeignKey("contact.id"), primary_key=True),
    db.Column('outletId', db.Integer, db.ForeignKey("outlet.id"), primary_key=True)
)

错误是直接的,您的响应中没有 JSON 准备好的值。

您的 dict 中有一个项目 'outlets':contact.outlets,,根据您的模型定义,它最好是 Outlet 个对象的列表。您需要告诉 flask-jsonify,如何使该对象成为 JSON

在正常的 json.dumps 操作中,您可以通过传递自定义编码器或默认方法来实现。您可以通过在 flask 中设置编码器选项来做到这一点。

首先,您为 JSON 创建一个自定义模型编码器。示例可能如下所示

from flask import json
class ModelEncoder(json.JSONEncoder):
    def default(self, o: Any) -> Any:
        if hasattr(o, 'to_json'):
            return o.to_json()
        else:
            return super(ModelEncoder, self).default(o)

现在,请 flask 使用此编码器将模型转换为 JSON。为此,您可以设置 Flask 应用程序配置。

app.json_encoder = ModelEncoder

如果您的模型中有一个 to_json 方法,它将调用该方法来序列化这些方法。否则它遵循默认值。是的,这是一个简单的实现,您可以通过类型检查或变体即兴创作。