generated from bisco/codex-bootstrap
feat: bootstrap HoopScout scouting app
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
|
||||
|
||||
class UserProfile(models.Model):
|
||||
ROLE_ADMIN = "admin"
|
||||
ROLE_SCOUT = "scout"
|
||||
ROLE_VIEWER = "viewer"
|
||||
ROLE_CHOICES = [
|
||||
(ROLE_ADMIN, "Admin"),
|
||||
(ROLE_SCOUT, "Scout"),
|
||||
(ROLE_VIEWER, "Viewer"),
|
||||
]
|
||||
|
||||
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="profile")
|
||||
role = models.CharField(max_length=16, choices=ROLE_CHOICES, default=ROLE_VIEWER)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.user.username} ({self.role})"
|
||||
|
||||
|
||||
class League(models.Model):
|
||||
name = models.CharField(max_length=120)
|
||||
code = models.CharField(max_length=16, unique=True)
|
||||
region = models.CharField(max_length=60)
|
||||
country = models.CharField(max_length=80)
|
||||
|
||||
class Meta:
|
||||
ordering = ["region", "country", "name"]
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.code
|
||||
|
||||
|
||||
class Team(models.Model):
|
||||
name = models.CharField(max_length=120)
|
||||
league = models.ForeignKey(League, on_delete=models.PROTECT, related_name="teams")
|
||||
country = models.CharField(max_length=80)
|
||||
|
||||
class Meta:
|
||||
ordering = ["name"]
|
||||
constraints = [models.UniqueConstraint(fields=["name", "league"], name="unique_team_per_league")]
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.name
|
||||
|
||||
|
||||
class Season(models.Model):
|
||||
label = models.CharField(max_length=20, unique=True)
|
||||
is_active = models.BooleanField(default=False)
|
||||
|
||||
class Meta:
|
||||
ordering = ["-label"]
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.label
|
||||
|
||||
|
||||
class Player(models.Model):
|
||||
POSITION_CHOICES = [
|
||||
("PG", "Point Guard"),
|
||||
("SG", "Shooting Guard"),
|
||||
("SF", "Small Forward"),
|
||||
("PF", "Power Forward"),
|
||||
("C", "Center"),
|
||||
]
|
||||
|
||||
first_name = models.CharField(max_length=80)
|
||||
last_name = models.CharField(max_length=80)
|
||||
position = models.CharField(max_length=2, choices=POSITION_CHOICES)
|
||||
role = models.CharField(max_length=120, blank=True)
|
||||
birth_year = models.PositiveSmallIntegerField(null=True, blank=True)
|
||||
height_cm = models.PositiveSmallIntegerField(null=True, blank=True)
|
||||
weight_kg = models.PositiveSmallIntegerField(null=True, blank=True)
|
||||
nationality = models.CharField(max_length=80, blank=True)
|
||||
current_team = models.ForeignKey(Team, on_delete=models.SET_NULL, null=True, blank=True, related_name="players")
|
||||
external_source = models.CharField(max_length=80, blank=True)
|
||||
external_id = models.CharField(max_length=120, blank=True)
|
||||
profile_url = models.URLField(blank=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ["last_name", "first_name"]
|
||||
constraints = [
|
||||
models.UniqueConstraint(
|
||||
fields=["first_name", "last_name", "birth_year", "nationality"],
|
||||
name="unique_player_identity",
|
||||
)
|
||||
]
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return f"{self.first_name} {self.last_name}"
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.name
|
||||
|
||||
|
||||
class PlayerSeasonStat(models.Model):
|
||||
player = models.ForeignKey(Player, on_delete=models.CASCADE, related_name="season_stats")
|
||||
team = models.ForeignKey(Team, on_delete=models.PROTECT, related_name="season_stats")
|
||||
league = models.ForeignKey(League, on_delete=models.PROTECT, related_name="season_stats")
|
||||
season = models.ForeignKey(Season, on_delete=models.PROTECT, related_name="player_stats")
|
||||
games_played = models.PositiveSmallIntegerField(default=0)
|
||||
minutes_per_game = models.DecimalField(max_digits=5, decimal_places=2, default=0)
|
||||
points_per_game = models.DecimalField(max_digits=5, decimal_places=2, default=0)
|
||||
assists_per_game = models.DecimalField(max_digits=5, decimal_places=2, default=0)
|
||||
rebounds_per_game = models.DecimalField(max_digits=5, decimal_places=2, default=0)
|
||||
steals_per_game = models.DecimalField(max_digits=5, decimal_places=2, default=0)
|
||||
blocks_per_game = models.DecimalField(max_digits=5, decimal_places=2, default=0)
|
||||
turnovers_per_game = models.DecimalField(max_digits=5, decimal_places=2, default=0)
|
||||
field_goal_percentage = models.DecimalField(max_digits=5, decimal_places=2, default=0)
|
||||
three_point_percentage = models.DecimalField(max_digits=5, decimal_places=2, default=0)
|
||||
free_throw_percentage = models.DecimalField(max_digits=5, decimal_places=2, default=0)
|
||||
efficiency_rating = models.DecimalField(max_digits=6, decimal_places=2, default=0)
|
||||
true_shooting_percentage = models.DecimalField(max_digits=5, decimal_places=2, default=0)
|
||||
usage_percentage = models.DecimalField(max_digits=5, decimal_places=2, default=0)
|
||||
total_points = models.PositiveSmallIntegerField(default=0)
|
||||
total_assists = models.PositiveSmallIntegerField(default=0)
|
||||
total_rebounds = models.PositiveSmallIntegerField(default=0)
|
||||
|
||||
class Meta:
|
||||
ordering = ["-efficiency_rating", "-points_per_game"]
|
||||
constraints = [
|
||||
models.UniqueConstraint(fields=["player", "team", "league", "season"], name="unique_player_stat_line")
|
||||
]
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.player} {self.season} {self.league}"
|
||||
|
||||
|
||||
class PlayerGameLog(models.Model):
|
||||
player = models.ForeignKey(Player, on_delete=models.CASCADE, related_name="game_logs")
|
||||
team = models.ForeignKey(Team, on_delete=models.PROTECT, related_name="game_logs")
|
||||
opponent = models.CharField(max_length=120)
|
||||
league = models.ForeignKey(League, on_delete=models.PROTECT, related_name="game_logs")
|
||||
season = models.ForeignKey(Season, on_delete=models.PROTECT, related_name="game_logs")
|
||||
game_date = models.DateField()
|
||||
points = models.PositiveSmallIntegerField(default=0)
|
||||
assists = models.PositiveSmallIntegerField(default=0)
|
||||
rebounds = models.PositiveSmallIntegerField(default=0)
|
||||
steals = models.PositiveSmallIntegerField(default=0)
|
||||
blocks = models.PositiveSmallIntegerField(default=0)
|
||||
turnovers = models.PositiveSmallIntegerField(default=0)
|
||||
efficiency_rating = models.DecimalField(max_digits=6, decimal_places=2, default=0)
|
||||
|
||||
class Meta:
|
||||
ordering = ["-game_date"]
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.player} vs {self.opponent} on {self.game_date}"
|
||||
Reference in New Issue
Block a user