How to serialize SqlAlchemy result to JSON?

后端 未结 27 1482
说谎
说谎 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:07
    def alc2json(row):
        return dict([(col, str(getattr(row,col))) for col in row.__table__.columns.keys()])
    

    I thought I'd play a little code golf with this one.

    FYI: I am using automap_base since we have a separately designed schema according to business requirements. I just started using SQLAlchemy today but the documentation states that automap_base is an extension to declarative_base which seems to be the typical paradigm in the SQLAlchemy ORM so I believe this should work.

    It does not get fancy with following foreign keys per Tjorriemorrie's solution, but it simply matches columns to values and handles Python types by str()-ing the column values. Our values consist Python datetime.time and decimal.Decimal class type results so it gets the job done.

    Hope this helps any passers-by!

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

    When using sqlalchemy to connect to a db I this is a simple solution which is highly configurable. Use pandas.

    import pandas as pd
    import sqlalchemy
    
    #sqlalchemy engine configuration
    engine = sqlalchemy.create_engine....
    
    def my_function():
      #read in from sql directly into a pandas dataframe
      #check the pandas documentation for additional config options
      sql_DF = pd.read_sql_table("table_name", con=engine)
    
      # "orient" is optional here but allows you to specify the json formatting you require
      sql_json = sql_DF.to_json(orient="index")
    
      return sql_json
    
    
    0 讨论(0)
  • 2020-11-22 10:09

    For security reasons you should never return all the model's fields. I prefer to selectively choose them.

    Flask's json encoding now supports UUID, datetime and relationships (and added query and query_class for flask_sqlalchemy db.Model class). I've updated the encoder as follows:

    app/json_encoder.py

        from sqlalchemy.ext.declarative import DeclarativeMeta
        from flask import json
    
    
        class AlchemyEncoder(json.JSONEncoder):
            def default(self, o):
                if isinstance(o.__class__, DeclarativeMeta):
                    data = {}
                    fields = o.__json__() if hasattr(o, '__json__') else dir(o)
                    for field in [f for f in fields if not f.startswith('_') and f not in ['metadata', 'query', 'query_class']]:
                        value = o.__getattribute__(field)
                        try:
                            json.dumps(value)
                            data[field] = value
                        except TypeError:
                            data[field] = None
                    return data
                return json.JSONEncoder.default(self, o)
    

    app/__init__.py

    # json encoding
    from app.json_encoder import AlchemyEncoder
    app.json_encoder = AlchemyEncoder
    

    With this I can optionally add a __json__ property that returns the list of fields I wish to encode:

    app/models.py

    class Queue(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        song_id = db.Column(db.Integer, db.ForeignKey('song.id'), unique=True, nullable=False)
        song = db.relationship('Song', lazy='joined')
        type = db.Column(db.String(20), server_default=u'audio/mpeg')
        src = db.Column(db.String(255), nullable=False)
        created_at = db.Column(db.DateTime, server_default=db.func.now())
        updated_at = db.Column(db.DateTime, server_default=db.func.now(), onupdate=db.func.now())
    
        def __init__(self, song):
            self.song = song
            self.src = song.full_path
    
        def __json__(self):
            return ['song', 'src', 'type', 'created_at']
    

    I add @jsonapi to my view, return the resultlist and then my output is as follows:

    [
    
    {
    
        "created_at": "Thu, 23 Jul 2015 11:36:53 GMT",
        "song": 
    
            {
                "full_path": "/static/music/Audioslave/Audioslave [2002]/1 Cochise.mp3",
                "id": 2,
                "path_name": "Audioslave/Audioslave [2002]/1 Cochise.mp3"
            },
        "src": "/static/music/Audioslave/Audioslave [2002]/1 Cochise.mp3",
        "type": "audio/mpeg"
    }
    
    ]
    
    0 讨论(0)
  • 2020-11-22 10:11

    You can convert a RowProxy to a dict like this:

     d = dict(row.items())
    

    Then serialize that to JSON ( you will have to specify an encoder for things like datetime values ) It's not that hard if you just want one record ( and not a full hierarchy of related records ).

    json.dumps([(dict(row.items())) for row in rs])
    
    0 讨论(0)
  • 2020-11-22 10:11

    While using some raw sql and undefined objects, using cursor.description appeared to get what I was looking for:

    with connection.cursor() as cur:
        print(query)
        cur.execute(query)
        for item in cur.fetchall():
            row = {column.name: item[i] for i, column in enumerate(cur.description)}
            print(row)
    
    0 讨论(0)
  • 2020-11-22 10:12

    The built in serializer chokes with utf-8 cannot decode invalid start byte for some inputs. Instead, I went with:

    def row_to_dict(row):
        temp = row.__dict__
        temp.pop('_sa_instance_state', None)
        return temp
    
    
    def rows_to_list(rows):
        ret_rows = []
        for row in rows:
            ret_rows.append(row_to_dict(row))
        return ret_rows
    
    
    @website_blueprint.route('/api/v1/some/endpoint', methods=['GET'])
    def some_api():
        '''
        /some_endpoint
        '''
        rows = rows_to_list(SomeModel.query.all())
        response = app.response_class(
            response=jsonplus.dumps(rows),
            status=200,
            mimetype='application/json'
        )
        return response
    
    0 讨论(0)
提交回复
热议问题