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}"