如何用Python将已注册足球队展示为淘汰赛图表?
足球队淘汰赛图表可视化实现
我现有一段Django代码,能够从数据库读取注册球队信息并生成填充好的Excel文件,现在需要将这些球队以淘汰赛对阵图表的形式可视化展示。
原代码功能回顾
原代码负责加载Excel模板、填充随机排序的球队信息并导出Excel:
from django.shortcuts import render from .models import Team, TieSheet from openpyxl.utils import get_column_letter from openpyxl.styles import Font from openpyxl import Workbook from django.http import HttpResponse import pandas as pd from openpyxl.styles import Font, PatternFill, Alignment, borders from django.http import HttpResponse from openpyxl import load_workbook from django.core.files import File from django.core.files.base import ContentFile def tie_sheet(request): # Load the Excel template workbook = load_workbook(filename='static/excel/Tie-sheet.xlsx') # Get the active worksheet worksheet = workbook.active # Create merged cell for POLL1 and POLL2 columns and set heading worksheet.merge_cells(start_row=1, start_column=2, end_row=1, end_column=3) worksheet.cell(row=1, column=2, value='POLL1') worksheet.cell(row=1, column=4, value='POLL2') # Get the teams from the database teams = Team.objects.all().order_by('?') # Fill the data into the worksheet row_num = 2 count = 1 col = 2 for team in teams: cell = worksheet.cell(row=row_num, column=col, value=team.title) cell.border = borders.Border(left=borders.Side(style='thin'), right=borders.Side(style='thin'), top=borders.Side(style='thin'), bottom=borders.Side(style='thin')) if col == 2: col = 4 row_num = row_num elif col == 4: col = 2 row_num += 2 count = count+2 # Add styling for row in worksheet.iter_rows(min_row=1, max_row=1): for cell in row: cell.font = Font(size=12, bold=True) cell.alignment = Alignment(horizontal='center') for col in worksheet.iter_cols(min_col=2, max_col=4): for cell in col: cell.font = Font(size=12, bold=True) cell.alignment = Alignment(horizontal='center') # Export Excel response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') response['Content-Disposition'] = 'attachment; filename=teams.xlsx' workbook.save(response) return response
实现淘汰赛可视化的方案
1. 后端调整:生成结构化的淘汰赛对阵数据
修改视图函数,保留Excel导出功能的同时,生成适合前端渲染的淘汰赛对阵结构(自动将球队数补至最近的2的幂次,不足时填充“轮空”):
from django.shortcuts import render from .models import Team from openpyxl.styles import Font, PatternFill, Alignment, borders from openpyxl import load_workbook from django.http import HttpResponse import math def generate_knockout_bracket(teams): # 调整球队数量为最近的2的幂次 team_count = len(teams) next_power = 2 ** math.ceil(math.log2(team_count)) # 补轮空 while len(teams) < next_power: teams.append({"title": "轮空"}) bracket = [] current_round = teams.copy() round_num = 1 while len(current_round) > 1: next_round = [] matches = [] # 两两配对生成对阵 for i in range(0, len(current_round), 2): match = { "team1": current_round[i], "team2": current_round[i+1], "winner": None # 可扩展为后续填写胜者 } matches.append(match) next_round.append({"winner": None, "match": match}) bracket.append({ "round_name": f"第{round_num}轮", "matches": matches }) current_round = next_round round_num += 1 # 添加决赛轮 bracket.append({ "round_name": "决赛", "matches": [{"team1": current_round[0]["match"]["winner"], "team2": current_round[1]["match"]["winner"], "winner": None}] }) return bracket def tie_sheet(request): teams = Team.objects.all().order_by('?') # 转换为字典列表便于前端处理 team_list = [{"id": team.id, "title": team.title} for team in teams] # 生成淘汰赛对阵结构 knockout_bracket = generate_knockout_bracket(team_list) if request.GET.get('export') == 'excel': # 原Excel导出逻辑 workbook = load_workbook(filename='static/excel/Tie-sheet.xlsx') worksheet = workbook.active worksheet.merge_cells(start_row=1, start_column=2, end_row=1, end_column=3) worksheet.cell(row=1, column=2, value='POLL1') worksheet.cell(row=1, column=4, value='POLL2') row_num = 2 col = 2 for team in teams: cell = worksheet.cell(row=row_num, column=col, value=team.title) cell.border = borders.Border(left=borders.Side(style='thin'), right=borders.Side(style='thin'), top=borders.Side(style='thin'), bottom=borders.Side(style='thin')) if col == 2: col = 4 elif col == 4: col = 2 row_num += 2 for row in worksheet.iter_rows(min_row=1, max_row=1): for cell in row: cell.font = Font(size=12, bold=True) cell.alignment = Alignment(horizontal='center') for col in worksheet.iter_cols(min_col=2, max_col=4): for cell in col: cell.font = Font(size=12, bold=True) cell.alignment = Alignment(horizontal='center') response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') response['Content-Disposition'] = 'attachment; filename=teams.xlsx' workbook.save(response) return response # 渲染可视化页面 return render(request, 'knockout_bracket.html', {'bracket': knockout_bracket})
2. 前端模板:绘制淘汰赛图表
创建templates/knockout_bracket.html,用HTML+CSS实现横向排列的淘汰赛对阵图:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>球队淘汰赛对阵图</title> <style> .bracket-container { display: flex; justify-content: space-around; padding: 20px; gap: 40px; overflow-x: auto; min-height: 600px; } .round { display: flex; flex-direction: column; gap: 80px; } .match { display: flex; flex-direction: column; gap: 10px; min-width: 200px; position: relative; } .team { padding: 10px; border: 1px solid #ccc; border-radius: 4px; text-align: center; background: #f8f9fa; font-weight: bold; } .winner { background: #d4edda; border-color: #c3e6cb; } .round-title { text-align: center; font-size: 1.2em; font-weight: bold; margin-bottom: 10px; } /* 对阵连接线条 */ .match::after { content: ''; position: absolute; left: 100%; top: 25px; width: 40px; height: 2px; background: #ccc; } .round:not(:last-child) .match::after { display: block; } .round:last-child .match::after { display: none; } </style> </head> <body> <h1 style="text-align: center;">足球队淘汰赛对阵图</h1> <div class="bracket-container"> {% for round in bracket %} <div class="round"> <div class="round-title">{{ round.round_name }}</div> {% for match in round.matches %} <div class="match"> <div class="team">{{ match.team1.title }}</div> <div class="team">{{ match.team2.title }}</div> </div> {% endfor %} </div> {% endfor %} </div> <div style="text-align: center; margin-top: 30px;"> <a href="?export=excel" style="padding: 10px 20px; background: #007bff; color: white; text-decoration: none; border-radius: 4px;">导出Excel对阵表</a> </div> </body> </html>
功能说明
- 后端自动处理球队数量,确保符合淘汰赛对阵要求(2的幂次)
- 前端通过Flex布局实现横向的淘汰赛对阵图,轮次清晰区分
- 保留原Excel导出功能,通过
?export=excel参数触发 - 可扩展胜者标记功能:修改后端
winner字段并更新前端.winner样式即可
内容的提问来源于stack exchange,提问作者Binay Adhikari
相关产品推荐
相关产品推荐

