You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
140 lines
6.7 KiB
140 lines
6.7 KiB
from django.db import models
|
|
|
|
# Create your models here.
|
|
class Season(models.Model):
|
|
name = models.CharField(max_length=32, blank=False, null=False)
|
|
start_date = models.DateField(blank=True, null=True)
|
|
end_date = models.DateField(blank=True, null=True)
|
|
|
|
class Division(models.Model):
|
|
name = models.CharField(max_length=64, blank=False, null=False)
|
|
|
|
class Team(models.Model):
|
|
name = models.CharField(max_length=32, blank=False, null=False)
|
|
season = models.ForeignKey(Season, related_name="teams", on_delete=models.PROTECT, blank=False, null=False)
|
|
division = models.ForeignKey(Division, related_name="teams", on_delete=models.PROTECT, blank=False, null=False)
|
|
|
|
class Player(models.Model):
|
|
first_name = models.CharField(max_length=32, blank=True, null=False)
|
|
last_name = models.CharField(max_length=32, blank=False, null=False)
|
|
middle_names = models.CharField(max_length=64, blank=True, null=False)
|
|
|
|
class TeamPlayer(models.Model):
|
|
team = models.ForeignKey(Team, related_name="players", on_delete=models.PROTECT, blank=False, null=False)
|
|
player = models.ForeignKey(Player, related_name="teams", on_delete=models.PROTECT, blank=False, null=False)
|
|
number = models.IntegerField(blank=False, null=False)
|
|
|
|
class Game(models.Model):
|
|
_name = models.CharField(max_length=64, blank=True, null=True)
|
|
home_team = models.ForeignKey(Team, related_name="home_games", on_delete=models.PROTECT, blank=True, null=True)
|
|
away_team = models.ForeignKey(Team, related_name="away_games", on_delete=models.PROTECT, blank=True, null=True)
|
|
season = models.ForeignKey(Season, related_name="games", on_delete=models.PROTECT, blank=False, null=False)
|
|
date_of = models.DateField(blank=False, null=False)
|
|
time_of = models.TimeField(blank=True, null=True)
|
|
|
|
def name(self):
|
|
return name if name else f"{home_team} v. {away_team}"
|
|
|
|
PERIOD_CHOICES = [
|
|
(1, "1st"),
|
|
(2, "2nd"),
|
|
(3, "3rd"),
|
|
(4, "OT"),
|
|
(5, "2OT"),
|
|
(6, "3OT"),
|
|
(7, "4OT"),
|
|
(8, "5OT"),
|
|
(9, "6OT"),
|
|
(0, "SO")
|
|
]
|
|
|
|
class Goal(models.Model):
|
|
scorer = models.ForeignKey(TeamPlayer, related_name="goals", on_delete=models.PROTECT, blank=False, null=False)
|
|
game = models.ForeignKey(Game, related_name="goals", on_delete=models.PROTECT, blank=False, null=False)
|
|
# NOTE: may be null if empty net
|
|
goalie = models.ForeignKey(TeamPlayer, related_name="goals_on", on_delete=models.PROTECT, blank=True, null=True)
|
|
assists = models.ManyToManyField(TeamPlayer, related_name="assists", blank=True)
|
|
period = models.IntegerField(choices=PERIOD_CHOICES, blank=False, null=False, default=1)
|
|
time = models.DurationField(blank=True, null=True)
|
|
# TODO allow no time column during SO
|
|
|
|
class Shot(models.Model):
|
|
SHOT_TYPE_CHOICES = [
|
|
("O", "On Goal"),
|
|
("M", "Missed"),
|
|
("B", "Blocked"),
|
|
]
|
|
# NOTE: default shot type is "on goal"
|
|
shot_type = models.CharField(max_length=1, choices=SHOT_TYPE_CHOICES, blank=False, null=False, default="O")
|
|
shooter = models.ForeignKey(TeamPlayer, related_name="shots", on_delete=models.PROTECT, blank=False, null=False)
|
|
game = models.ForeignKey(Game, related_name="shots", on_delete=models.PROTECT, blank=False, null=False)
|
|
period = models.IntegerField(choices=PERIOD_CHOICES, blank=False, null=False, default=1)
|
|
time = models.DurationField(blank=True, null=True)
|
|
# NOTE: the goalie the shot was on; note that only player.shots_on.filter(shot_type="O") count as saved goals
|
|
# NOTE: may be blank if an attempt is made on an open net
|
|
goalie = models.ForeignKey(TeamPlayer, related_name="shots_on", on_delete=models.PROTECT, blank=True, null=True)
|
|
# TODO allow no time column during SO
|
|
# this is only set in the case of a shot_type="B" for blocked
|
|
blocker = models.ForeignKey(TeamPlayer, related_name="blocked_shots", on_delete=models.PROTECT, blank=True, null=True)
|
|
|
|
# NOTE: game misconducts will eject a player from the game, but the penelty may be served by another player
|
|
class PeneltyLength(models.Model):
|
|
PENELTY_LENGTH_CHOICES = [
|
|
("M", "Minor"), # 2 mins in NHL
|
|
("MR", "Minor (running)"), # 3 minutes for running clock compensation
|
|
("D", "Double Minor"), # 4 mins in NHL
|
|
("J", "Major"), # 5 mins in NHL
|
|
("C", "Misconduct"), # 10 mins in NHL
|
|
("G", "Game Misconduct"), # ejection from game in NHL
|
|
("S", "Shot"), # penelty shot
|
|
]
|
|
name = models.CharField(max_length=2, choices=PENELTY_LENGTH_CHOICES, blank=False, null=False)
|
|
length = models.DurationField(blank=False, null=False)
|
|
|
|
# NOTE: i.e.: "Minor (2:00)", or "Misconduct (10:00")", or "Shot"
|
|
# TODO: filter shot
|
|
def __str__(self):
|
|
return f"{self.name} ({self.length})"
|
|
|
|
class PeneltyType(models.Model):
|
|
PENELTY_TYPE_CHOICES = [
|
|
("B", "Boarding"),
|
|
("C", "Charging"),
|
|
("D", "Delay of Game"),
|
|
("X", "Cross-Checking"),
|
|
("E", "Elbowing"),
|
|
("G", "Grasping the Facemask"),
|
|
("H", "High Sticking"),
|
|
("O", "Holding"),
|
|
("K", "Hooking"),
|
|
("I", "Interference"),
|
|
("M", "Miscounduct"), # see above where misconduct equals 10 minutes
|
|
("R", "Roughing"),
|
|
("S", "Slashing"),
|
|
("P", "Spearing"),
|
|
("T", "Tripping"),
|
|
("U", "Unsportsmanlike Conduct"),
|
|
]
|
|
name = models.CharField(max_length=1, choices=PENELTY_TYPE_CHOICES, blank=False, null=False)
|
|
|
|
class Penelty(models.Model):
|
|
PENELTY_GIVEN_CHOICES = [
|
|
("I", "Individual"),
|
|
("T", "Team"), # e.g., too many men
|
|
]
|
|
# default="I" because individual penelties are much more common
|
|
penelty_classification = models.CharField(max_length=1, choices=PENELTY_GIVEN_CHOICES, blank=False, null=False, default="I")
|
|
penelty_type = models.ForeignKey(PeneltyType, related_name="given_out", on_delete=models.PROTECT, blank=False, null=False)
|
|
penelty_length = models.ForeignKey(PeneltyLength, related_name="given_out", on_delete=models.PROTECT, blank=False, null=False)
|
|
game = models.ForeignKey(Game, related_name="penelties", on_delete=models.PROTECT, blank=False, null=False)
|
|
# NOTE: may be none if team penelty like too many men
|
|
on_ind = models.ForeignKey(TeamPlayer, related_name="penelties_given", on_delete=models.PROTECT, blank=True, null=True)
|
|
# NOTE: may be noen if individual penelty
|
|
on_team = models.ForeignKey(Team, related_name="penelties_given", on_delete=models.PROTECT, blank=True, null=True)
|
|
# NOTE: some player will ALWAYS serve the penelty
|
|
served_by = models.ForeignKey(TeamPlayer, related_name="penelties_served", on_delete=models.PROTECT, blank=False, null=False)
|
|
# NOTE: an indiviaul will not be named in the case of a delay of game; some misconducts, like swearing at a referee also would not list a "drawn_by"
|
|
drawn_by = models.ForeignKey(TeamPlayer, related_name="penelties_drawn", on_delete=models.PROTECT, blank=True, null=True)
|
|
period = models.IntegerField(choices=PERIOD_CHOICES, blank=False, null=False)
|
|
time = models.DurationField(blank=False, null=False)
|