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)