How to serialize SqlAlchemy result to JSON?

后端 未结 27 1484
说谎
说谎 2020-11-22 09:59

Django has some good automatic serialization of ORM models returned from DB to JSON format.

How to serialize SQLAlchemy query result to JSON format?

I tried

相关标签:
27条回答
  • 2020-11-22 10:13

    Flask-JsonTools package has an implementation of JsonSerializableBase Base class for your models.

    Usage:

    from sqlalchemy.ext.declarative import declarative_base
    from flask.ext.jsontools import JsonSerializableBase
    
    Base = declarative_base(cls=(JsonSerializableBase,))
    
    class User(Base):
        #...
    

    Now the User model is magically serializable.

    If your framework is not Flask, you can just grab the code

    0 讨论(0)
  • 2020-11-22 10:14

    You could just output your object as a dictionary:

    class User:
       def as_dict(self):
           return {c.name: getattr(self, c.name) for c in self.__table__.columns}
    

    And then you use User.as_dict() to serialize your object.

    As explained in Convert sqlalchemy row object to python dict

    0 讨论(0)
  • 2020-11-22 10:15

    following code will serialize sqlalchemy result to json.

    import json
    from collections import OrderedDict
    
    
    def asdict(self):
        result = OrderedDict()
        for key in self.__mapper__.c.keys():
            if getattr(self, key) is not None:
                result[key] = str(getattr(self, key))
            else:
                result[key] = getattr(self, key)
        return result
    
    
    def to_array(all_vendors):
        v = [ ven.asdict() for ven in all_vendors ]
        return json.dumps(v) 
    

    Calling fun,

    def all_products():
        all_products = Products.query.all()
        return to_array(all_products)
    
    0 讨论(0)
  • 2020-11-22 10:18

    The AlchemyEncoder is wonderful but sometimes fails with Decimal values. Here is an improved encoder that solves the decimal problem -

    class AlchemyEncoder(json.JSONEncoder):
    # To serialize SQLalchemy objects 
    def default(self, obj):
        if isinstance(obj.__class__, DeclarativeMeta):
            model_fields = {}
            for field in [x for x in dir(obj) if not x.startswith('_') and x != 'metadata']:
                data = obj.__getattribute__(field)
                print data
                try:
                    json.dumps(data)  # this will fail on non-encodable values, like other classes
                    model_fields[field] = data
                except TypeError:
                    model_fields[field] = None
            return model_fields
        if isinstance(obj, Decimal):
            return float(obj)
        return json.JSONEncoder.default(self, obj)
    
    0 讨论(0)
  • 2020-11-22 10:19

    Python 3.7+ and Flask 1.1+ can use the built-in dataclasses package

    from dataclasses import dataclass
    from datetime import datetime
    from flask import Flask, jsonify
    from flask_sqlalchemy import SQLAlchemy
    
    
    app = Flask(__name__)
    db = SQLAlchemy(app)
    
    
    @dataclass
    class User(db.Model):
      id: int
      email: str
    
      id = db.Column(db.Integer, primary_key=True, auto_increment=True)
      email = db.Column(db.String(200), unique=True)
    
    
    @app.route('/users/')
    def users():
      users = User.query.all()
      return jsonify(users)  
    
    
    if __name__ == "__main__":
      users = User(email="user1@gmail.com"), User(email="user2@gmail.com")
      db.create_all()
      db.session.add_all(users)
      db.session.commit()
      app.run()
    

    The /users/ route will now return a list of users.

    [
      {"email": "user1@gmail.com", "id": 1},
      {"email": "user2@gmail.com", "id": 2}
    ]
    

    Auto-serialize related models

    @dataclass
    class Account(db.Model):
      id: int
      users: User
    
      id = db.Column(db.Integer)
      users = db.relationship(User)  # User model would need a db.ForeignKey field
    

    The response from jsonify(account) would be this.

    {  
       "id":1,
       "users":[  
          {  
             "email":"user1@gmail.com",
             "id":1
          },
          {  
             "email":"user2@gmail.com",
             "id":2
          }
       ]
    }
    

    Overwrite the default JSON Encoder

    from flask.json import JSONEncoder
    
    
    class CustomJSONEncoder(JSONEncoder):
      "Add support for serializing timedeltas"
    
      def default(o):
        if type(o) == datetime.timedelta:
          return str(o)
        elif type(o) == datetime.datetime:
          return o.isoformat()
        else:
          return super().default(o)
    
    app.json_encoder = CustomJSONEncoder      
    
    0 讨论(0)
  • 2020-11-22 10:19

    Under Flask, this works and handles datatime fields, transforming a field of type
    'time': datetime.datetime(2018, 3, 22, 15, 40) into
    "time": "2018-03-22 15:40:00":

    obj = {c.name: str(getattr(self, c.name)) for c in self.__table__.columns}
    
    # This to get the JSON body
    return json.dumps(obj)
    
    # Or this to get a response object
    return jsonify(obj)
    
    0 讨论(0)
提交回复
热议问题