python - sqlalchemy 输出到排序字典
问题描述
我的表如下所示:
User
| id | name |
| 1 | user1 |
| 2 | user2 |
| 3 | user3 |
| 4 | user4 |
| 5 | user5 |
| 6 | user6 |
| 7 | user7 |
| 8 | user8 |
Event
| id | name | created_by | published_by |
| 1 | event1 | 1 | 2 |
| 2 | event2 | 2 | 2 |
| 3 | event3 | 3 | 1 |
Team
| id | name | player1 | player2 | player3 | player4 |
| 1 | teamA | 1 | 2 | | |
| 2 | teamB | 5 | 6 | | |
Schedule
| id | event_id | player1 | player2 | team1 | team2 | when_do_they_play | round |
| 1 | 1 | 1 | 3 | | | 2019-09-20 11:22:33 | 1 |
| 1 | 1 | 2 | 4 | | | 2019-09-21 12:32:23 | 1 |
| 1 | 1 | 5 | 6 | | | 2019-09-22 22:42:03 | 4 |
| 2 | 2 | | | 1 | 2 | 2019-09-25 21:12:43 | 2 |
我正在使用以下查询从中选择数据
scheduled_games = (
db.session.query(
e.name.label('event_name'),
u1.name.label('player1'),
c1.code.label('player1_country'),
u2.name.label('player2'),
c2.code.label('player2_country'),
s.when_do_they_play,
s.round.label('round'),
t1.name.label('team1'),
t2.name.label('team2')
)
.outerjoin(u1, u1.id == s.player1)
.outerjoin(u2, u2.id == s.player2)
.outerjoin(e, e.id == s.event_id)
.outerjoin(c1, c1.id == u1.country)
.outerjoin(c2, c2.id == u2.country)
.outerjoin(t1, t1.id == s.team1)
.outerjoin(t2, t2.id == s.team2)
.filter(s.when_do_they_play>=(datetime.utcnow() - timedelta(days=10)))\
.order_by(s.when_do_they_play)
.order_by(s.round.asc())
)
我想要做的是生成按事件排序然后按轮次排序的 json/字典,所以类似于(或类似的,以后易于迭代):
[
{
"event1": {
"round1": {
"player1": "player1",
"player2": "player3",
"when_do_they_play": "2019-09-20 11:22:33"
},
"round1": {
"player1": "player2",
"player2": "player4",
"when_do_they_play": "2019-09-21 12:32:23"
},
"round4": {
"player1": "player5",
"player2": "player6",
"when_do_they_play": "2019-09-22 22:42:03"
}
},
"event2": {
"round1": {
"team1": "teamA",
"team2": "teamB",
"when_do_they_play": "2019-09-25 21:12:43"
}
}
}
]
我现在拥有的是
scheduled_json={}
print('scheduled_games: {}'.format(scheduled_games))
# json needs to have another index for round1, round2 etc, because items are overlapping
for ldata in scheduled_games:
if ldata[0] not in scheduled_json:
scheduled_json[ldata[0]]={}
if 'round'+str(ldata[6]) not in scheduled_json[ldata[0]]:
print('init!')
scheduled_json[ldata[0]]['round'+str(ldata[6])]={}
if ldata[1] or ldata[3]:
scheduled_json[ldata[0]]['round'+str(ldata[6])]['player1']=ldata[1]
scheduled_json[ldata[0]]['round'+str(ldata[6])]['player2']=ldata[3]
else:
scheduled_json[ldata[0]]['round'+str(ldata[6])]['team1']=ldata[7]
scheduled_json[ldata[0]]['round'+str(ldata[6])]['team2']=ldata[8]
scheduled_json[ldata[0]]['round'+str(ldata[6])]['when_do_they_play']=ldata[5]
它有点工作,但不像我想要的那样,因为标记为“round1”的项目被压扁,而是我看到:
[
{
"event1": {
"round1": {
"player1": "player1",
"player2": "player3",
"when_do_they_play": "2019-09-20 11:22:33"
},
"round4": {
"player1": "player5",
"player2": "player6",
"when_do_they_play": "2019-09-22 22:42:03"
}
},
"event2": {
"round1": {
"team1": "teamA",
"team2": "teamB",
"when_do_they_play": "2019-09-25 21:12:43"
}
}
}
]
我怎样才能解决这个问题?我想我需要以不同的方式分配这些项目,但是如何?
解决方案
您希望每个事件的回合由列表表示。在您的尝试中,这些行:
if ldata[1] or ldata[3]:
scheduled_json[ldata[0]]['round'+str(ldata[6])]['player1']=ldata[1]
scheduled_json[ldata[0]]['round'+str(ldata[6])]['player2']=ldata[3]
else:
scheduled_json[ldata[0]]['round'+str(ldata[6])]['team1']=ldata[7]
scheduled_json[ldata[0]]['round'+str(ldata[6])]['team2']=ldata[8]
... 将覆盖嵌套在密钥中的任何现有密钥'round' + str(ldata[6])
。
而不是这个:
scheduled_json[ldata[0]]['round'+str(ldata[6])]={}
使用list
:
scheduled_json[ldata[0]]['round'+str(ldata[6])] = []
然后为每个事件的每一轮附加一个新dict
的:list
if ldata[1] or ldata[3]:
d = {'player1': ldata[1], 'player2': ldata[2]}
else:
d = {'team1': ldata[7], 'team2': ldata[8]}
d['when_do_they_play'] = ldata[5]
scheduled_json[ldata[0]]['round'+str(ldata[6])].append(d)
从风格上讲,您也可以对整体可读性进行一些改进。例如,您的解决方案可以这样重写:
for ldata in scheduled_games:
event = ldata.event # the row proxy facilitates attribute access syntax
if event not in scheduled_json:
scheduled_json[event] = {}
round_key = f"round{ldata.round}" # have a look at f-string and str.format() for string concat
if round_key not in scheduled_json[event]:
print('init!')
scheduled_json[event][round_key] = []
if ldata.player1 or ldata.player2:
d = {'player1': ldata.player1, 'player2': ldata.player2}
else:
d = {'team1': ldata.team1, 'team2': ldata.team2}
d['when_do_they_play'] = ldata.when_do_they_play
scheduled_json[event][round_key].append(d)
您甚至可以更进一步并使用 acollections.defaultdict
这样您就不需要实例化空集合:
from collections import defaultdict
scheduled_json = defaultdict(lambda: defaultdict(list))
for ldata in scheduled_games:
if ldata.player1 or ldata.player2:
d = {'player1': ldata.player1, 'player2': ldata.player2}
else:
d = {'team1': ldata.team1, 'team2': ldata.team2}
d['when_do_they_play'] = ldata.when_do_they_play
scheduled_json[ldata.event][f"round{ldata.round}"].append(d)
推荐阅读
- reactjs - 使用 withRouter 时找不到 props.history
- powershell - 如何检索哈希表中的键,然后更新 Powershell 中的值?
- python - 计算两个python数组之间的欧几里得距离
- python - Python - TypeError:“int”对象在简单函数中不可迭代
- jsf - 添加primefaces ajax时未调用JSF命令按钮
- amazon-web-services - AWS App Load-Balancer 的侦听器是否针对目标或目标组?
- sqlalchemy - hdp 中的 Apache superset 0.23.3 无法通过 sqlalchemy url 连接到 sql server
- python-3.x - 如何在 Jupyter Notebook 中运行`wx python`
- c# - Microsoft GraphAPI 在一个项目中工作,但不在另一个项目中
- shell - Shell:如果将多个语句放在一行中