【问题标题】:return SQL table as JSON in python在python中将SQL表作为JSON返回
【发布时间】:2011-03-18 05:21:25
【问题描述】:

我正在使用 web.py 中的一个小网络应用程序,并且正在设置一个 url 以返回一个 JSON 对象。使用 python 将 SQL 表转换为 JSON 的最佳方法是什么?

【问题讨论】:

  • 如果您使用 Postgres,请使用 to_json 功能,它将数据直接输出为 python 对象,您可以轻松地将其转储为 json 字符串。

标签: python sql json


【解决方案1】:

这是a pythonic way to do that 的一个非常好的例子:

import json
import psycopg2

def db(database_name='pepe'):
    return psycopg2.connect(database=database_name)

def query_db(query, args=(), one=False):
    cur = db().cursor()
    cur.execute(query, args)
    r = [dict((cur.description[i][0], value) \
               for i, value in enumerate(row)) for row in cur.fetchall()]
    cur.connection.close()
    return (r[0] if r else None) if one else r

my_query = query_db("select * from majorroadstiger limit %s", (3,))

json_output = json.dumps(my_query)

你得到一个 JSON 对象数组:

>>> json_output
'[{"divroad": "N", "featcat": null, "countyfp": "001",...

或使用以下内容:

>>> j2 = query_db("select * from majorroadstiger where fullname= %s limit %s",\
 ("Mission Blvd", 1), one=True)

你得到一个 JSON 对象:

>>> j2 = json.dumps(j2)
>>> j2
'{"divroad": "N", "featcat": null, "countyfp": "001",...

【讨论】:

  • 优秀的答案!阅读如此复杂的“转换为对象”类型的答案,这简直令人惊叹。谢谢!
  • 我完全同意上述评论。这是一个很好的解决方案。
  • 这不支持在具有一对多关系的表上很好地连接。您将获得包含重复数据的行。你需要一个像公认答案这样的 ORM 来获得可以解决这个问题的东西。不过,对于简单的 SQL 到 JSON,这可以正常工作。
  • 我收到错误datetime.datetime(1941, 10, 31, 0, 0) is not JSON serializable
  • 你让我学到了一个新东西,那就是 enumerate() 函数。太棒了
【解决方案2】:
import sqlite3
import json

DB = "./the_database.db"

def get_all_users( json_str = False ):
    conn = sqlite3.connect( DB )
    conn.row_factory = sqlite3.Row # This enables column access by name: row['column_name'] 
    db = conn.cursor()

    rows = db.execute('''
    SELECT * from Users
    ''').fetchall()

    conn.commit()
    conn.close()

    if json_str:
        return json.dumps( [dict(ix) for ix in rows] ) #CREATE JSON

    return rows

调用没有json的方法...

print get_all_users()

打印:

[(1, u'orvar', u'password123'), (2, u'kalle', u'password123')]

用json调用方法...

print get_all_users( json_str = True )

打印:

[{"password": "password123", "id": 1, "name": "orvar"}, {"password": "password123", "id": 2, "name": "kalle"}]

【讨论】:

    【解决方案3】:

    就我个人而言,我更喜欢SQLObject。我修改了一些我必须得到的快速而肮脏的测试代码:

    import simplejson
    
    from sqlobject import *
    
    # Replace this with the URI for your actual database
    connection = connectionForURI('sqlite:/:memory:')
    sqlhub.processConnection = connection
    
    # This defines the columns for your database table. See SQLObject docs for how it
    # does its conversions for class attributes <-> database columns (underscores to camel
    # case, generally)
    
    class Song(SQLObject):
    
        name = StringCol()
        artist = StringCol()
        album = StringCol()
    
    # Create fake data for demo - this is not needed for the real thing
    def MakeFakeDB():
        Song.createTable()
        s1 = Song(name="B Song",
                  artist="Artist1",
                  album="Album1")
        s2 = Song(name="A Song",
                  artist="Artist2",
                  album="Album2")
    
    def Main():
        # This is an iterable, not a list
        all_songs = Song.select().orderBy(Song.q.name)
    
        songs_as_dict = []
    
        for song in all_songs:
            song_as_dict = {
                'name' : song.name,
                'artist' : song.artist,
                'album' : song.album}
            songs_as_dict.append(song_as_dict)
    
        print simplejson.dumps(songs_as_dict)
    
    
    if __name__ == "__main__":
        MakeFakeDB()
        Main()
    

    【讨论】:

    • 非常感谢。这很好用,尽管我遇到了一个错误,列表和 dict 命名相同。刚刚将字典重命名为songs,一切正常。
    • 很高兴我能帮上忙。奇怪的是有一个错误——正如我所见,他们有(稍微)不同的名字——你能打错字吗?
    • 比答案 4 复杂得多,并且需要有关数据的知识——我更喜欢答案 4,因为它很简单。
    • @detly 您能否就这个问题提出建议:stackoverflow.com/questions/55737528/…
    【解决方案4】:

    有关在传输数据之前如何处理数据的更多信息将大有帮助。 json 模块提供了 dump(s) 和 load(s) 方法,如果您使用的是 2.6 或更高版本,它们会有所帮助:http://docs.python.org/library/json.html

    -- 已编辑--

    在不知道您正在使用哪些库的情况下,我无法确定您是否会找到这样的方法。通常,我会像这样处理查询结果(以 kinterbasdb 为例,因为这是我们目前正在使用的):

    qry = "Select Id, Name, Artist, Album From MP3s Order By Name, Artist"
    # Assumes conn is a database connection.
    cursor = conn.cursor()
    cursor.execute(qry)
    rows = [x for x in cursor]
    cols = [x[0] for x in cursor.description]
    songs = []
    for row in rows:
      song = {}
      for prop, val in zip(cols, row):
        song[prop] = val
      songs.append(song)
    # Create a string representation of your array of songs.
    songsJSON = json.dumps(songs)
    

    毫无疑问,有更好的专家可以通过列表解析来消除对写出循环的需要,但这很有效,并且应该是您可以适应任何用于检索记录的库的东西。

    【讨论】:

    • 该表是一个 mp3 文件列表,包括曲目名称、艺术家和 url,然后用于填充 HTML5 音频播放器。播放器通过 JSON 对象创建播放列表,所以我只是想将表格传递给 JSON。我查看了文档,但只是想知道 python 中是否有类似于 ruby​​ to_json 方法的内容。
    • @aaron-moodie - 我用更多示例代码更新了我的答案。希望对您有所帮助。
    • 不错的方法,但我必须进行两项更改才能使其适合我。歌曲应该是一个字典:“songs = {}”而不是songs.append(song),我使用songs[song['Id']] = song。否则 json.dumps(songs) 将停止并显示歌曲无法序列化的错误。
    【解决方案5】:

    我拼凑了一个简短的脚本,它将所有表中的所有数据转储为列名的字典:值。与其他解决方案不同,它不需要任何有关表或列的信息,它只是找到所有内容并将其转储。希望有人觉得它有用!

    from contextlib import closing
    from datetime import datetime
    import json
    import MySQLdb
    DB_NAME = 'x'
    DB_USER = 'y'
    DB_PASS = 'z'
    
    def get_tables(cursor):
        cursor.execute('SHOW tables')
        return [r[0] for r in cursor.fetchall()] 
    
    def get_rows_as_dicts(cursor, table):
        cursor.execute('select * from {}'.format(table))
        columns = [d[0] for d in cursor.description]
        return [dict(zip(columns, row)) for row in cursor.fetchall()]
     
    def dump_date(thing):
        if isinstance(thing, datetime):
            return thing.isoformat()
        return str(thing)
    
    
    with closing(MySQLdb.connect(user=DB_USER, passwd=DB_PASS, db=DB_NAME)) as conn, closing(conn.cursor()) as cursor:
        dump = {
            table: get_rows_as_dicts(cursor, table)
            for table in get_tables(cursor)
        }
        print(json.dumps(dump, default=dump_date, indent=2))
    

    【讨论】:

      【解决方案6】:

      最简单的方法,

      使用json.dumps,但如果它的日期时间需要将日期时间解析为json序列化器。

      这是我的,

      import MySQLdb, re, json
      from datetime import date, datetime
      
      def json_serial(obj):
          """JSON serializer for objects not serializable by default json code"""
      
          if isinstance(obj, (datetime, date)):
              return obj.isoformat()
          raise TypeError ("Type %s not serializable" % type(obj))
      
      conn = MySQLdb.connect(instance)
      curr = conn.cursor()
      curr.execute("SELECT * FROM `assets`")
      data = curr.fetchall()
      print json.dumps(data, default=json_serial)
      

      它将返回 json 转储

      另一种没有 json 转储的简单方法, 这里获取标头并使用 zip 映射每个最终都将其设置为 json 但这不是将日期时间更改为 json 序列化程序...

      data_json = []
      header = [i[0] for i in curr.description]
      data = curr.fetchall()
      for i in data:
          data_json.append(dict(zip(header, i)))
      print data_json
      

      【讨论】:

        【解决方案7】:

        似乎没有人提供使用 postgres JSON 功能直接从 Postgresql 服务器获取 JSON 的选项 https://www.postgresql.org/docs/9.4/static/functions-json.html

        在 python 端没有解析、循环或任何内存消耗,如果您要处理 100,000 行或数百万行,您可能真的需要考虑这些。

        from django.db import connection
        
        sql = 'SELECT to_json(result) FROM (SELECT * FROM TABLE table) result)'
        with connection.cursor() as cursor:
          cursor.execute(sql)
          output = cursor.fetchall()
        

        像这样的表格:

        id, value
        ----------
        1     3
        2     7
        

        将返回一个 Python JSON 对象

        [{"id": 1, "value": 3},{"id":2, "value": 7}]
        

        然后使用json.dumps 转储为 JSON 字符串

        【讨论】:

        • 这可以仅使用psycopg2 和PostgreSQL JSON 函数来完成吗?
        • psycopg2 连接和游标会做同样的事情
        • 感谢您的澄清!我确认它确实适用于 psycopg2。例如,我使用了json_agg() 函数,如here 所述
        【解决方案8】:

        我会用 psycopg2 版本补充The Demz 答案:

        import psycopg2 
        import psycopg2.extras
        import json
        connection = psycopg2.connect(dbname=_cdatabase, host=_chost, port=_cport , user=_cuser, password=_cpassword)
        cursor = connection.cursor(cursor_factory=psycopg2.extras.DictCursor) # This line allows dictionary access.
        #select some records into "rows"
        jsonout= json.dumps([dict(ix) for ix in rows])
        

        【讨论】:

          【解决方案9】:

          如果您使用的是 MSSQL Server 2008 及更高版本,则可以使用 FOR JSON AUTO 子句 E.G 执行 SELECT 查询以返回 json

          SELECT name, surname FROM users FOR JSON AUTO

          将返回 Json 为

          [{"name": "Jane","surname": "Doe" }, {"name": "Foo","surname": "Samantha" }, ..., {"name": "John", "surname": "boo" }]

          【讨论】:

          【解决方案10】:

          10 年后 :) 。没有列表理解

          从如下所示的选择查询中返回单行值。

          "select name,userid, address from table1 where userid = 1"
          

          json 输出

          { name : "name1", userid : 1, address : "adress1, street1" }

          代码

          cur.execute(f"select name,userid, address from table1 where userid = 1 ")
          row = cur.fetchone()
          desc = list(zip(*cur.description))[0]  #To get column names
          rowdict = dict(zip(desc,row))
          jsondict = jsonify(rowdict)  #Flask jsonify
          

          cur.description 是一个元组,如下所示。 unzipzip 将列名与值结合起来

          (('name', None, None, None, None, None, None), ('userid', None, None, None, None, None, None), ('address', None, None, None, None, None, None))

          【讨论】:

          • 太棒了!感谢您的回答
          【解决方案11】:

          from sqlalchemy import Column
          from sqlalchemy import Integer
          from sqlalchemy import String
          
          Base = declarative_base()
          metadata = Base.metadata
          
          
          class UserTable(Base):
              __tablename__ = 'UserTable'
          
              Id = Column("ID", Integer, primary_key=True)
              Name = Column("Name", String(100))
          
                  
          class UserTableDTO:
              def __init__(self, ob):
                  self.Id = ob.Id
                  self.Name = ob.Name
                  
          rows = dbsession.query(Table).all()
          
          json_string = [json.loads(json.dumps(UserTableDTO(ob).__dict__, default=lambda x: str(x)))for ob in rows]
          print(json_string)
          

          【讨论】:

            【解决方案12】:

            将 SQL 表返回为 formatted JSON 并修复错误的一个简单示例,就像他有 @Whitecat 一样

            我收到错误 datetime.datetime(1941, 10, 31, 0, 0) is not JSON serializable

            在该示例中,您应该使用JSONEncoder

            import json
            import pymssql
            
            # subclass JSONEncoder
            class DateTimeEncoder(JSONEncoder):
                    #Override the default method
                    def default(self, obj):
                        if isinstance(obj, (datetime.date, datetime.datetime)):
                            return obj.isoformat()
            
            def mssql_connection():
                try:
                    return pymssql.connect(server="IP.COM", user="USERNAME", password="PASSWORD", database="DATABASE")
                except Exception:
                    print("\nERROR: Unable to connect to the server.")
                    exit(-1)
            
            def query_db(query):
                cur = mssql_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):
                # read sql from file
                with open("../sql/my_sql.txt", 'r') as f:
                    sql = f.read().replace('\n', ' ')
                # creating and writing to a json file and Encode DateTime Object into JSON using custom JSONEncoder
                with open("../output/my_json.json", 'w', encoding='utf-8') as f:
                    json.dump(query_db(sql), f, ensure_ascii=False, indent=4, cls=DateTimeEncoder) 
            
            if __name__ == "__main__":
                write_json()
            
            # You get formatted my_json.json, for example:
            [
               {
                  "divroad":"N",
                  "featcat":null,
                  "countyfp":"001",
                  "date":"2020-08-28"
               }
            ]
            

            【讨论】:

              【解决方案13】:

              对于 sqlite,可以设置一个可调用的 connection.row_factory 并将查询结果的格式更改为 python 字典对象。请参阅documentation。这是一个例子:

              import sqlite3, json
              
              def dict_factory(cursor, row):
                  d = {}
                  for idx, col in enumerate(cursor.description):
                      # col[0] is the column name
                      d[col[0]] = row[idx]
                  return d
              
              def get_data_to_json():
                  conn = sqlite3.connect("database.db")
                  conn.row_factory = dict_factory
                  c = conn.cursor()
                  c.execute("SELECT * FROM table")
                  rst = c.fetchall() # rst is a list of dict
                  return jsonify(rst)
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2022-01-19
                • 2016-01-03
                • 2015-07-26
                • 2014-12-16
                • 1970-01-01
                • 1970-01-01
                • 2016-10-05
                • 1970-01-01
                相关资源
                最近更新 更多