【问题标题】:Python converting mysql query result to jsonPython将mysql查询结果转换为json
【发布时间】:2017-10-03 10:22:45
【问题描述】:

我正在尝试实现 REST API,其中一部分是将数据格式化为 json。我能够从 mysql 数据库中检索数据,但是我收到的对象不是我所期望的。这是我的代码

from flask import Flask
from flask.ext.mysqldb import MySQL

app = Flask(__name__)
app.config['MYSQL_HOST'] = '127.0.0.1'
app.config['MYSQL_USER'] = 'root'
app.config['MYSQL_PASSWORD'] = 'password'
app.config['MYSQL_DB'] = 'hello_db'
mysql = MySQL(app)

@app.route('/hello')
def index():
   cur = mysql.connection.cursor()
   cur.execute('''SELECT * FROM Users WHERE id=1''')
   rv = cur.fetchall()
   return str(rv)

if __name__ == '__main__':
   app.run(debug=True)

结果:

((1L, u'my_username', u'my_password'),)

如何实现返回这样的 json 格式:

{
 "id":1, 
 "username":"my_username", 
 "password":"my_password"
}

【问题讨论】:

    标签: python mysql json


    【解决方案1】:

    以下是我通过设置 app.config['MYSQL_CURSORCLASS'] 并使用 jsonify 解决此问题的方法

    from flask import Flask, jsonify
    from flask_mysqldb import MySQL
    
    app = Flask(__name__)
    app.config['MYSQL_HOST'] = '127.0.0.1'
    app.config['MYSQL_USER'] = 'root'
    app.config['MYSQL_PASSWORD'] = 'password'
    app.config['MYSQL_DB'] = 'hello_db'
    app.config['MYSQL_CURSORCLASS'] = 'DictCursor' # line of code you require
    
    mysql = MySQL(app)
    
    @app.route('/hello')
    def index():
       cur = mysql.connection.cursor()
       cur.execute("SELECT * FROM Users WHERE id=1")
       rv = cur.fetchall()
       return jsonify(rv) # use jsonify here
    
    if __name__ == '__main__':
       app.run(debug=True)
    

    【讨论】:

      【解决方案2】:

      也许有一种更简单的方法可以做到这一点:返回一个字典并将其转换为 JSON。

      只需将dictionary=True 传递给MySQL's documents 中提到的游标构造函数。

      import json
      import mysql.connector
      
      db = mysql.connector.connect(host='127.0.0.1',
                                   user='admin',
                                   passwd='password',
                                   db='database',
                                   port=3306)
      
      # This line is that you need
      cursor = db.cursor(dictionary=True)
      
      name = "Bob"
      cursor.execute("SELECT fname, lname FROM table WHERE fname=%s;", (name))
      
      result = cursor.fetchall()
      
      print(f"json: {json.dumps(result)}")
      

      哪个会打印 -

      json: [{'fname': "Bob", 'lname': "Dole"}, {'fname': "Bob", 'lname': "Marley"}]
      

      (假设这些 Bob 在表中。)

      请注意,以这种方式保留类型,这是一件好事,但需要将其转换、解析或序列化为字符串;例如,如果有日期,SQL 查询可能会返回一个datetime 对象,这将需要根据您的下一步进行解析或序列化。一个很好的序列化方法是在this answer

      【讨论】:

        【解决方案3】:

        如果你想将更多的select query results转换成JSON文件,下面的简单程序代码就可以了。对于more 的详细信息,您在github 上有三个解决方案。

        鉴于已经澄清了很多。简单介绍一下方法:

        • class DateTimeEncoder(JSONEncoder) - 支持日期时间的编码器 - doc
        • get_current_date_time - 区分是否使用可变数据的当前时间
        • query_db - 使用游标描述来提取行标题,你会得到一个字典对象数组 headers:values。
        • write_json(query_path) - 在已创建的 output 文件夹中读取 SQL 并生成 JSON
        • convertion_mysql - 使用 glob 在扩展名为 .sql 的目录中查找所有文件并调用描述和定义的方法 write_json
        import json
        from json import JSONEncoder
        import datetime
        import os
        import glob
        
        class DateTimeEncoder(JSONEncoder):
                def default(self, obj):
                    if isinstance(obj, (datetime.date, datetime.datetime)):
                        return obj.isoformat()
        
        def get_current_date_time():
            return datetime.datetime.now().strftime('%a_%d.%b.%Y_%H.%M.%S')
        
        def query_db(query):
            cur = mysql.connection.cursor()
            cur.execute(query)
            r = [dict((cur.description[i][0], value) for i, value in enumerate(row)) for row in cur.fetchall()]
            cur.connection.close()
            return r
        
        def write_json(query_path):
            with open(f"{query_path}", 'r') as f:
                sql = f.read().replace('\n', ' ')
            file_name = os.path.splitext(os.path.basename(f"{query_path}"))[0]
            with open(f"../output/{file_name}_{get_current_date_time()}.json", 'w', encoding='utf-8') as f:
                json.dump(query_db(sql), f, ensure_ascii=False, indent=4, cls=DateTimeEncoder)
        
        def convertion_mysql():
            mysql_query = [f for f in glob.glob("../myqls/*.sql")]
            for sql in mysql_query:
                write_json(sql)
        
        if __name__ == "__main__":
            convertion_mysql()
        

        【讨论】:

          【解决方案4】:

          对于使用 Django 的用户,您可以从 django.http 导入 JsonResponse 来完成您的工作。

          示例代码sn-p:

          from django.http import JsonResponse
          from django.db import connection
          
          def home(request):
              with connection.cursor() as cursor:
                  cursor.execute("select * from YOUR_TABLE")
                  columns = [col[0] for col in cursor.description]
                  return JsonResponse([
                      dict(zip(columns, row))
                      for row in cursor.fetchall()
                  ], safe=False)
          

          注意:已添加 safe=False 以将字典列表转换为 Json。

          【讨论】:

            【解决方案5】:

            您可以使用游标描述来提取行标题: row_headers=[x[0] for x in cursor.description] 在执行语句之后。然后你可以用 sql 的结果压缩它来生成 json 数据。 所以你的代码会是这样的:

            from flask import Flask
            from flask.ext.mysqldb import MySQL
            import json
            app = Flask(__name__)
            app.config['MYSQL_HOST'] = '127.0.0.1'
            app.config['MYSQL_USER'] = 'root'
            app.config['MYSQL_PASSWORD'] = 'password'
            app.config['MYSQL_DB'] = 'hello_db'
            mysql = MySQL(app)
            
            @app.route('/hello')
            def index():
               cur = mysql.connection.cursor()
               cur.execute('''SELECT * FROM Users WHERE id=1''')
               row_headers=[x[0] for x in cur.description] #this will extract row headers
               rv = cur.fetchall()
               json_data=[]
               for result in rv:
                    json_data.append(dict(zip(row_headers,result)))
               return json.dumps(json_data)
            
            if __name__ == '__main__':
               app.run(debug=True)
            

            在返回语句中,您可以使用 jsonify 而不是 json.dumps,正如 RickLan 在 cmets 中所建议的那样。

            【讨论】:

            • 我得到了`Decimal('0.00') is not JSON serializable`错误
            • mysql 结果中可能有十进制数。十进制对象需要转换为浮点数。 try this
            • return jsonify(json_data) 不是比return json.dumps(json_data) 更干净的方法吗?
            • 我认为jsonify 是一个外部库。考虑尝试使用默认库。
            • 你是对的,但这里引用Flask Docs API JSON Supportjsonify():This function wraps dumps() to add a few enhancements that make life easier. It turns the JSON output into a Response object with the application/json mimetype.
            【解决方案6】:

            从你的输出看来你得到了一个元组?在这种情况下,您应该能够只映射它。

            from flask import Flask, jsonify
            from flask.ext.mysqldb import MySQL
            
            app = Flask(__name__)
            app.config['MYSQL_HOST'] = '127.0.0.1'
            app.config['MYSQL_USER'] = 'root'
            app.config['MYSQL_PASSWORD'] = 'password'
            app.config['MYSQL_DB'] = 'hello_db'
            mysql = MySQL(app)
            
            @app.route('/hello')
            def index():
               cur = mysql.connection.cursor()
               cur.execute('''SELECT * FROM Users WHERE id=1''')
               rv = cur.fetchall()
               payload = []
               content = {}
               for result in rv:
                   content = {'id': result[0], 'username': result[1], 'password': result[2]}
                   payload.append(content)
                   content = {}
               return jsonify(payload)
            
            if __name__ == '__main__':
               app.run(debug=True)
            

            【讨论】:

            • 对于那些期待动态响应的人来说,这不是一个正确的方法
            猜你喜欢
            • 2017-10-15
            • 2013-07-18
            • 1970-01-01
            • 2016-12-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-08-22
            • 1970-01-01
            相关资源
            最近更新 更多