如何在多个Python字典上执行类似SQL的INNER JOIN



我目前正在计划一个django应用程序,它不仅允许用户构建与模型相关的自定义表(例如,用户可以创建一个与"员工"模型相关的琐碎的自定义"停车位"表,而无需编辑models.py),还可以使用这些自定义表构建自定义报告。我唯一能想到的方法是建立一个在JSONField中存储自定义表数据的模型(我使用Postgres作为后端,所以这实际上很好),然后建立一个报告模型,允许用户构建和保存"类似SQL"的查询,为他们的自定义报告返回连接的数据集。

我已经学会了如何存储自定义表并在我的应用程序中使用它们,我甚至对如何将伪外键上的多个JSON对象合并到自定义报告中有一个松散的概念,但我只创建了一对一连接。

使用下面的脚本,如果我的任何dict在一个外键上有多个记录,则只使用最后一个记录。有人知道我如何实现多个python字典的一对多连接吗?

如果我有这三个数据集:

employees = [{"id": 1, "user_id": 303, "name": "Mike"},
             {"id": 2, "user_id": 304, "name": "James"},
             {"id": 3, "user_id": 305, "name": "David"},]
roles = [{"id": 1, "user_id": 303, "role": "Manager"},
         {"id": 2, "user_id": 304, "role": "Assistant"},
         {"id": 3, "user_id": 305, "role": "Assistant"},]
absences = [{"id": 1, "user_id": 303, "date": "2015-03-01"},
            {"id": 2, "user_id": 303, "date": "2015-03-02"},
            {"id": 3, "user_id": 303, "date": "2015-03-03"},
            {"id": 4, "user_id": 304, "date": "2015-03-15"},
            {"id": 5, "user_id": 305, "date": "2015-03-19"},]

我希望直接加入的结果是:

[{'date': '2015-03-01', 'role': 'Manager', 'user_id': 303, 'id': 1, 'name': 'Mike'},
    {'date': '2015-03-02', 'role': 'Manager', 'user_id': 303, 'id': 1, 'name': 'Mike'},
    {'date': '2015-03-03', 'role': 'Manager', 'user_id': 303, 'id': 1, 'name': 'Mike'}, 
    {'date': '2015-03-15', 'role': 'Assistant', 'user_id': 304, 'id': 2, 'name': 'James'}, 
    {'date': '2015-03-19', 'role': 'Assistant', 'user_id': 305, 'id': 3, 'name': 'David'}]

但由于我的脚本首先循环通过FROM字典(在本例中是员工),所以我所能得到的就是:

[{'date': '2015-03-03', 'role': 'Manager', 'user_id': 303, 'id': 1, 'name': 'Mike'},
{'date': '2015-03-15', 'role': 'Assistant', 'user_id': 304, 'id': 2, 'name': 'James'},
{'date': '2015-03-19', 'role': 'Assistant', 'user_id': 305, 'id': 3, 'name': 'David'}]

下面是我的代码的基础:

def joiner(from_table, joins):
    report_data = []
    for row in from_table:
        new_row = row
        for table in joins:
            table_dict = table["table"]
            table_fk = table["fk"]
            for tdr in table_dict:
                if tdr[table_fk] == row[table_fk]:
                    for field in table["fields"]:
                        new_row[field] = tdr[field]
    report_data = from_table
    return report_data
join_tables = [{"table": roles, "fk": "user_id", "fields": ["role"]},
               {"table": absences, "fk": "user_id", "fields": ["date"]},
          ]
joiner(employees, join_tables)

我能想到的最简单的解决方案是从"缺席"dict作为from_table而不是employees开始,但这是一个多对一的加入,这对我来说是非常有限的。

此外,如果有人对构建用户创建的数据模式有更好的想法,可以使用django将其合并到自定义报告中,我会洗耳恭听。我能想到的唯一其他解决方案是完全绕过django模型,只使用直接SQL创建、更新和查询所有自定义表。

只要在调用合并时将最长的字典列表放在第一位(可以很容易地修改),这里就是一个粗略的解决方案

    def merge_lists(listdict1, listdict2,listdict3, joinkey):
        mergedlist=listdict1
        for i in range(len(listdict1)):
            for j in range(len(listdict2)):
                if (listdict1[i][joinkey]==listdict2[j][joinkey]):
                    for keys in listdict2[j].keys():
                        mergedlist[i][keys]=listdict2[j][keys]
            for k in range(len(listdict3)):
                if listdict1[i][joinkey]==listdict3[k][joinkey]:
                    for keys in listdict3[k].keys():
                        mergedlist[i][keys]=listdict3[k][keys]                       
        return mergedlist
    merge_lists(absences, employees, roles,  "user_id")

[  
   {  
      "date":"2015-03-01",
      "id":1,
      "name":"Mike",
      "role":"Manager",
      "user_id":303
   },
   {  
      "date":"2015-03-02",
      "id":1,
      "name":"Mike",
      "role":"Manager",
      "user_id":303
   },
   {  
      "date":"2015-03-03",
      "id":1,
      "name":"Mike",
      "role":"Manager",
      "user_id":303
   },
   {  
      "date":"2015-03-15",
      "id":2,
      "name":"James",
      "role":"Assistant",
      "user_id":304
   },
   {  
      "date":"2015-03-19",
      "id":3,
      "name":"David",
      "role":"Assistant",
      "user_id":305
   }
]

最新更新