Files
hoopscout/apps/players/models.py

192 lines
6.0 KiB
Python

from django.db import models
class TimeStampedModel(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class Nationality(TimeStampedModel):
name = models.CharField(max_length=120, unique=True)
iso2_code = models.CharField(max_length=2, unique=True)
iso3_code = models.CharField(max_length=3, unique=True, blank=True, null=True)
class Meta:
ordering = ["name"]
indexes = [models.Index(fields=["name"]), models.Index(fields=["iso2_code"])]
verbose_name_plural = "Nationalities"
def __str__(self) -> str:
return f"{self.name} ({self.iso2_code})"
class Position(TimeStampedModel):
code = models.CharField(max_length=10, unique=True)
name = models.CharField(max_length=80, unique=True)
class Meta:
ordering = ["code"]
indexes = [models.Index(fields=["code"]), models.Index(fields=["name"])]
def __str__(self) -> str:
return f"{self.code} - {self.name}"
class Role(TimeStampedModel):
code = models.CharField(max_length=32, unique=True)
name = models.CharField(max_length=120, unique=True)
description = models.TextField(blank=True)
class Meta:
ordering = ["name"]
indexes = [models.Index(fields=["code"]), models.Index(fields=["name"])]
def __str__(self) -> str:
return self.name
class Player(TimeStampedModel):
class DominantHand(models.TextChoices):
RIGHT = "right", "Right"
LEFT = "left", "Left"
BOTH = "both", "Both"
UNKNOWN = "unknown", "Unknown"
first_name = models.CharField(max_length=120)
last_name = models.CharField(max_length=120)
full_name = models.CharField(max_length=260)
birth_date = models.DateField(blank=True, null=True)
nationality = models.ForeignKey(
"players.Nationality",
on_delete=models.SET_NULL,
blank=True,
null=True,
related_name="players",
)
nominal_position = models.ForeignKey(
"players.Position",
on_delete=models.SET_NULL,
blank=True,
null=True,
related_name="nominal_players",
)
inferred_role = models.ForeignKey(
"players.Role",
on_delete=models.SET_NULL,
blank=True,
null=True,
related_name="role_players",
)
height_cm = models.PositiveSmallIntegerField(blank=True, null=True)
weight_kg = models.PositiveSmallIntegerField(blank=True, null=True)
wingspan_cm = models.PositiveSmallIntegerField(blank=True, null=True)
dominant_hand = models.CharField(
max_length=16,
choices=DominantHand.choices,
default=DominantHand.UNKNOWN,
)
is_active = models.BooleanField(default=True)
class Meta:
ordering = ["full_name", "id"]
constraints = [
models.UniqueConstraint(
fields=["full_name", "birth_date"],
name="uq_player_full_name_birth_date",
)
]
indexes = [
models.Index(fields=["full_name"]),
models.Index(fields=["last_name", "first_name"]),
models.Index(fields=["birth_date"]),
models.Index(fields=["nationality"]),
models.Index(fields=["nominal_position"]),
models.Index(fields=["inferred_role"]),
models.Index(fields=["is_active"]),
models.Index(fields=["height_cm"]),
]
def __str__(self) -> str:
return self.full_name
class PlayerAlias(TimeStampedModel):
player = models.ForeignKey("players.Player", on_delete=models.CASCADE, related_name="aliases")
alias = models.CharField(max_length=260)
source = models.CharField(max_length=80, blank=True)
is_primary = models.BooleanField(default=False)
class Meta:
ordering = ["alias"]
constraints = [
models.UniqueConstraint(fields=["player", "alias"], name="uq_player_alias_per_player")
]
indexes = [models.Index(fields=["alias"]), models.Index(fields=["source"])]
def __str__(self) -> str:
return f"{self.alias} ({self.player_id})"
class PlayerCareerEntry(TimeStampedModel):
player = models.ForeignKey(
"players.Player",
on_delete=models.CASCADE,
related_name="career_entries",
)
team = models.ForeignKey(
"teams.Team",
on_delete=models.SET_NULL,
blank=True,
null=True,
related_name="career_entries",
)
competition = models.ForeignKey(
"competitions.Competition",
on_delete=models.SET_NULL,
blank=True,
null=True,
related_name="career_entries",
)
season = models.ForeignKey(
"competitions.Season",
on_delete=models.SET_NULL,
blank=True,
null=True,
related_name="career_entries",
)
role_snapshot = models.ForeignKey(
"players.Role",
on_delete=models.SET_NULL,
blank=True,
null=True,
related_name="career_entries",
)
shirt_number = models.PositiveSmallIntegerField(blank=True, null=True)
start_date = models.DateField(blank=True, null=True)
end_date = models.DateField(blank=True, null=True)
notes = models.TextField(blank=True)
class Meta:
ordering = ["player", "-start_date", "-id"]
constraints = [
models.UniqueConstraint(
fields=["player", "team", "competition", "season", "start_date"],
name="uq_player_career_entry_scope",
),
models.CheckConstraint(
check=models.Q(end_date__isnull=True) | models.Q(start_date__isnull=True) | models.Q(end_date__gte=models.F("start_date")),
name="ck_career_entry_dates",
),
]
indexes = [
models.Index(fields=["player", "start_date"]),
models.Index(fields=["team", "season"]),
models.Index(fields=["competition", "season"]),
]
def __str__(self) -> str:
return f"{self.player} | {self.team or '-'} | {self.season or '-'}"