请求协助优化Django/SQLite3梦幻橄榄球赛事模型架构
Django梦幻橄榄球锦标赛模型优化方案
核心问题拆解
- 队伍与分数绑定:原
Game用ManyToManyField无法直接关联单支队伍的分数,需要明确每场比赛的对阵双方及各自得分。 - 层级逻辑梳理:年份代表一届完整锦标赛,轮次属于当届锦标赛,比赛属于对应轮次,拆分后结构更清晰,避免重复字段。
优化后模型设计
from django.db import models from django.core.validators import MinValueValidator, MaxValueValidator, RegexValidator class Owner(models.Model): name = models.CharField(max_length=200) email = models.EmailField(max_length=100) phone = models.CharField(max_length=12, null=True) def __str__(self): return self.name class Team(models.Model): owner = models.ForeignKey(Owner, on_delete=models.CASCADE) name = models.CharField(max_length=200) def __str__(self): return self.name class Tournament(models.Model): # 代表每一年的Toilet Bowl锦标赛 year = models.SmallIntegerField( unique=True, validators=[ MinValueValidator(2010), MaxValueValidator(2999), RegexValidator("^(20)([1-5][0-9])$") ] ) # 绑定当届参赛队伍,确保每年固定6支 participating_teams = models.ManyToManyField(Team) def __str__(self): return f"Toilet Bowl {self.year}" class Round(models.Model): # 代表某届锦标赛中的一轮赛事 tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE) round_number = models.SmallIntegerField(validators=[MinValueValidator(1), MaxValueValidator(3)]) class Meta: # 确保同一届锦标赛中轮次不重复 unique_together = ('tournament', 'round_number') def __str__(self): return f"{self.tournament} - 第{self.round_number}轮" class Game(models.Model): # 代表某一轮中的一场具体比赛 round = models.ForeignKey(Round, on_delete=models.CASCADE) team1 = models.ForeignKey(Team, on_delete=models.CASCADE, related_name='team1_games') team1_score = models.IntegerField(default=0) team2 = models.ForeignKey(Team, on_delete=models.CASCADE, related_name='team2_games') team2_score = models.IntegerField(default=0) def __str__(self): return f"{self.round}: {self.team1} vs {self.team2}"
关键设计说明
- Tournament模型:将年份抽象为独立的锦标赛实体,通过
participating_teams关联当届6支参赛队伍,可通过表单或信号限制队伍数量为6,保证数据完整性。 - Round模型:绑定到具体锦标赛,明确轮次归属,避免不同年份的轮次混淆。
- Game模型:用两个独立的
ForeignKey关联对阵队伍,直接绑定各自分数,完美解决原ManyToManyField无法关联分数的问题;related_name方便反向查询某支队伍参与的所有比赛。
额外建议
- 若需要记录比赛胜负结果,可在
Game中添加动态计算的属性,无需额外存储:@property def winner(self): if self.team1_score > self.team2_score: return self.team1 elif self.team2_score > self.team1_score: return self.team2 return None - 单字段的
Year模型完全没必要,Tournament本身已经承担了按年区分赛事的作用,符合Django模型“一个模型对应一个业务实体”的设计原则。
内容的提问来源于stack exchange,提问作者Shawn Johnson
相关产品推荐
相关产品推荐

