You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django模型关联问题:如何在计分表表单中录入单场球员数据

问题分析

你当前的模型设计无法实现单场球员统计数据关联的核心需求,原因是:

  • Score_sheet模型中的goals、freekicks等字段是球队整体数据,无法对应到单个球员
  • players多对多字段仅能关联球员与赛事,但无法存储每个球员在这场比赛的个性化统计数据
解决方案

需要新增一个球员单场统计模型,作为Score_sheet与Player的关联中间表,专门存储单场中每个球员的进球、红黄牌等数据;同时调整Score_sheet的关联逻辑,结合Django的inlineformset实现表单中同时录入球队与球员数据。

修改后的模型代码

from django.db import models
from django.contrib.auth.models import User

# 假设Category和Season模型已定义
class Category(models.Model):
    name = models.CharField(max_length=40)
    # 其他字段...

class Season(models.Model):
    name = models.CharField(max_length=40)
    # 其他字段...

Roles = [
    ('default', 'Default'),
    # 其他角色选项...
]

class Player(models.Model):
    # 修正字段命名为Django推荐的snake_case
    user = models.OneToOneField(User, on_delete=models.SET_NULL, null=True, related_name="playeruser")
    player_name = models.CharField(max_length=40)
    player_surname = models.CharField(max_length=40)
    player_id = models.CharField(max_length=40)
    player_email = models.CharField(max_length=40)
    player_contact = models.CharField(max_length=40)
    category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name="pcategory")
    player_preferred = models.CharField(choices=Roles, default="default", max_length=16)
    
    def __str__(self):
        return f"{self.player_name} {self.player_surname}"

# 新增球员单场统计模型
class PlayerGameStats(models.Model):
    score_sheet = models.ForeignKey('Score_sheet', on_delete=models.CASCADE, related_name='player_stats')
    player = models.ForeignKey(Player, on_delete=models.CASCADE, related_name='game_stats')
    goals = models.IntegerField(default=0)
    freekicks = models.IntegerField(default=0)
    red_cards = models.IntegerField(default=0)
    yellow_cards = models.IntegerField(default=0)

    def __str__(self):
        return f"{self.player} - {self.score_sheet}"

class Score_sheet(models.Model):
    season = models.ForeignKey(Season, on_delete=models.CASCADE, related_name="season")
    category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name="sscategory")
    # 多对多关联改为通过PlayerGameStats中间表
    players = models.ManyToManyField(Player, through='PlayerGameStats', related_name='score_sheets')
    captain = models.ForeignKey(Player, on_delete=models.CASCADE, related_name="captain")
    date = models.DateField()
    venue = models.CharField(max_length=40, null=True, blank=True)
    description = models.TextField(null=True, blank=True)
    # 若需要球队总数据,可保留以下字段,或通过PlayerGameStats自动计算
    total_goals = models.IntegerField(null=True, blank=True)
    total_freekicks = models.IntegerField(null=True, blank=True)
    total_redcards = models.IntegerField(null=True, blank=True)
    total_yellowcards = models.IntegerField(null=True, blank=True)

    def __str__(self):
        return f"{self.season} - {self.venue}"

表单实现(关联球员统计)

使用Django的inlineformset_factory,在计分表表单中嵌入球员单场统计的表单集,实现一次提交同时录入球队与球员数据:

# views.py
from django.shortcuts import render, redirect
from .models import Score_sheet, PlayerGameStats
from .forms import ScoreSheetForm
from django.forms import inlineformset_factory

# 创建球员统计表单集
PlayerStatsFormSet = inlineformset_factory(
    Score_sheet,
    PlayerGameStats,
    fields=('player', 'goals', 'freekicks', 'red_cards', 'yellow_cards'),
    extra=10,  # 默认显示10个球员统计输入框,可根据需求调整
    can_delete=True
)

def create_score_sheet(request):
    if request.method == 'POST':
        form = ScoreSheetForm(request.POST)
        formset = PlayerStatsFormSet(request.POST, instance=form.instance)
        if form.is_valid() and formset.is_valid():
            score_sheet = form.save()
            formset.save()
            # 可选:自动计算球队总数据
            score_sheet.total_goals = sum(stat.goals for stat in score_sheet.player_stats.all())
            score_sheet.save()
            return redirect('score_sheet_list')
    else:
        form = ScoreSheetForm()
        formset = PlayerStatsFormSet(instance=form.instance)
    return render(request, 'create_score_sheet.html', {'form': form, 'formset': formset})

模板示例(create_score_sheet.html)

在模板中同时渲染计分表表单和球员统计表单集:

<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <h3>球员单场统计</h3>
    {{ formset.management_form }}
    {% for form in formset %}
        {{ form.as_table }}
        <hr>
    {% endfor %}
    <button type="submit">保存计分表</button>
</form>
关键说明
  1. 中间表作用:PlayerGameStats模型作为关联层,实现了"一场比赛-多个球员-每个球员的单场数据"的关联逻辑
  2. 表单集优势:inlineformset允许在同一个页面处理主模型(Score_sheet)和关联模型(PlayerGameStats)的表单,符合业务流程
  3. 字段规范:将原模型中的大写字段名改为snake_case,符合Python/Django的编码惯例,提升代码可读性

内容的提问来源于stack exchange,提问作者Eesa Kamaldien

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 18:01:10