from django.db import models from django.core.validators import MinValueValidator, MaxValueValidator from django.utils import timezone from django.contrib.auth.models import User class Musician(models.Model): musician_id = models.AutoField(primary_key=True) name = models.CharField(max_length=100, verbose_name="Имя исполнителя") city = models.CharField(max_length=100, blank=True, null=True) birth_year = models.IntegerField(null=True, blank=True) class Meta: db_table = 'musician' verbose_name = 'Исполнитель' verbose_name_plural = 'Исполнители' def __str__(self): return self.name class Genre(models.Model): genre_id = models.AutoField(primary_key=True) genre_name = models.CharField(max_length=50, unique=True) class Meta: db_table = 'genre' verbose_name = 'Жанр' verbose_name_plural = 'Жанры' def __str__(self): return self.genre_name class Album(models.Model): album_id = models.AutoField(primary_key=True) album_name = models.CharField(max_length=150) release_date = models.DateField(null=True, blank=True) musician = models.ForeignKey(Musician, on_delete=models.CASCADE, db_column='musician_id') class Meta: db_table = 'album' verbose_name = 'Альбом' verbose_name_plural = 'Альбомы' indexes = [ models.Index(fields=['musician'], name='idx_album_musician'), ] def __str__(self): return f"{self.album_name} - {self.musician.name}" class Song(models.Model): song_id = models.AutoField(primary_key=True) title = models.CharField(max_length=150) duration_sec = models.IntegerField(validators=[MinValueValidator(1)], null=True, blank=True) album = models.ForeignKey(Album, on_delete=models.CASCADE, db_column='album_id') genre = models.ForeignKey(Genre, on_delete=models.SET_NULL, null=True, db_column='genre_id') class Meta: db_table = 'song' verbose_name = 'Песня' verbose_name_plural = 'Песни' indexes = [ models.Index(fields=['album'], name='idx_song_album'), models.Index(fields=['genre'], name='idx_song_genre'), ] def __str__(self): return self.title @property def duration_formatted(self): """Расчетный атрибут: форматированная длительность""" if not self.duration_sec: return "00:00" minutes = self.duration_sec // 60 seconds = self.duration_sec % 60 return f"{minutes}:{seconds:02d}" class Meloman(models.Model): GENDER_CHOICES = [ ('M', 'Мужской'), ('F', 'Женский'), ] meloman_id = models.AutoField(primary_key=True) full_name = models.CharField(max_length=150) gender = models.CharField(max_length=1, choices=GENDER_CHOICES, blank=True, null=True) city = models.CharField(max_length=100, blank=True, null=True) birth_year = models.IntegerField(null=True, blank=True) user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True, related_name='meloman') class Meta: db_table = 'meloman' verbose_name = 'Меломан' verbose_name_plural = 'Меломанцы' def __str__(self): return self.full_name @property def age(self): """Расчетный атрибут: возраст меломана""" if not self.birth_year: return None return timezone.now().year - self.birth_year class Rating(models.Model): rating_id = models.AutoField(primary_key=True) meloman = models.ForeignKey(Meloman, on_delete=models.CASCADE, db_column='meloman_id') song = models.ForeignKey(Song, on_delete=models.CASCADE, db_column='song_id') score = models.IntegerField(validators=[MinValueValidator(1), MaxValueValidator(10)]) rating_date = models.DateField(auto_now_add=True) class Meta: db_table = 'rating' verbose_name = 'Оценка' verbose_name_plural = 'Оценки' unique_together = ['meloman', 'song'] # один меломан — одна оценка на песню def __str__(self): return f"{self.meloman.full_name} - {self.song.title}: {self.score}" class Preference(models.Model): preference_id = models.AutoField(primary_key=True) meloman = models.ForeignKey(Meloman, on_delete=models.CASCADE, db_column='meloman_id') genre = models.ForeignKey(Genre, on_delete=models.CASCADE, db_column='genre_id') class Meta: db_table = 'preference' verbose_name = 'Предпочтение' verbose_name_plural = 'Предпочтения' unique_together = ['meloman', 'genre']