Narzędzia użytkownika

Narzędzia witryny


pl:python:dbaudiocd

Różnice

Różnice między wybraną wersją a wersją aktualną.

Odnośnik do tego porównania

Poprzednia rewizja po obu stronachPoprzednia wersja
Nowa wersja
Poprzednia wersja
pl:python:dbaudiocd [2023/11/23 14:52] – [Dodanie modelu MusicAlbum] sindappl:python:dbaudiocd [2024/01/05 13:22] (aktualna) – [Modyfikacja w pliku cdacd/cdacd/settings.py] sindap
Linia 76: Linia 76:
 LANGUAGE_CODE = 'pl-pl' LANGUAGE_CODE = 'pl-pl'
 TIME_ZONE = 'Europe/Warsaw'</code> TIME_ZONE = 'Europe/Warsaw'</code>
 +
 +Poniżej przykład struktury pliku ''apps.py'':
 +
 +<code python apps.py>
 +from django.apps import AppConfig
 +
 +
 +class DbcdappConfig(AppConfig):
 +    default_auto_field = 'django.db.models.BigAutoField'
 +    name = 'dbcdapp'
 +</code>
 +
 +W tym przykładzie ''dbcdapp.apps.DbcdappConfig'' składa się z wartości zmiennej ''name''. Następnie po kropce nazwa modułu bibliotece django czyli ''apps'' oraz nazwa klasy ''DbcdappConfig''.
 +
 +Warto wspomnieć, że w pliku można nadać bardziej ludzką nazwę aplikacji:
 +
 +<code python apps.py>
 +from django.apps import AppConfig
 +
 +
 +class DbcdappConfig(AppConfig):
 +    default_auto_field = 'django.db.models.BigAutoField'
 +    name = 'dbcdapp'
 +    verbose_name = 'Moja Aplikacja'
 +</code>
  
 ===== Pierwsze uruchomienie serwera ===== ===== Pierwsze uruchomienie serwera =====
Linia 825: Linia 850:
 ===== Dodanie modelu MusicAlbum ===== ===== Dodanie modelu MusicAlbum =====
  
-Następny model będzie zawierał informację o tytule albumu, na jakim nośniku został wydany. Model będzie powiązany z modelem ''Song''. Jak już się można domyśleć dany utwór może się znajdować na wielu albumach a album może zawierać wiele utworów. Sam utwór będzie taki sam no chyba, że powstanie jego inna wersja ale to już wtedy będzie traktowany jako inny utwór. +Następny model będzie zawierał informację o tytule albumu, na jakim nośniku został wydany. Model będzie powiązany z modelem ''Song''. Jak już się można domyśleć dany utwór może się znajdować na wielu albumach a album może zawierać wiele utworów. Sam utwór będzie taki sam no chyba, że powstanie jego inna wersja ale to już wtedy będzie traktowany jako inny utwór.\\ 
 +\\ 
 +Analogicznie jak poprzednio musimy użyć relacji wiele-do-wielu. Opcję ''ManyToManyField'' umieścimy w MusicAlbum bo do konkretnego albumu najczęściej będziemy dodawać wiele utworów. 
 + 
 +<code python models.py> 
 +from django.db import models 
 +from django.utils import timezone 
 +from .verbose_names import verbose_names 
 +from django.core.validators import MinValueValidator, MaxValueValidator, ValidationError 
 + 
 +class Song(models.Model): 
 +    song_title = models.CharField(max_length=200, verbose_name=verbose_names['song_title']) 
 +    release_year = models.CharField(max_length=4, verbose_name=verbose_names['release_year']) 
 +    duration = models.DurationField(null=True, verbose_name=verbose_names['duration']) 
 +    created_at = models.DateTimeField(default=timezone.now, verbose_name=verbose_names['created_at'], editable=False) 
 +    modified_at = models.DateTimeField(auto_now=True, verbose_name='Data ostatniej modyfikacji'
 + 
 +    class Meta: 
 +        verbose_name = 'Song' 
 +        verbose_name_plural = 'Songs' 
 +        unique_together = ('song_title', 'release_year'
 + 
 +    def __str__(self): 
 +        return f"{self.song_title}, ({self.release_year})" 
 + 
 +class Artist(models.Model): 
 +    artist_name = models.CharField(max_length=255, verbose_name=verbose_names['artist_name']) 
 +    songs = models.ManyToManyField(Song) 
 + 
 +    class Meta: 
 +        verbose_name = 'Artist' 
 +        verbose_name_plural = 'Artists' 
 + 
 +    def __str__(self): 
 +        return self.artist_name 
 + 
 +class MusicAlbum(models.Model): 
 +    MEDIUM_TYPE = ( 
 +        ('audiocd', 'Audio CD'), 
 +        ('audiocd_r', 'Audio CD-R'), 
 +        ('sacd', 'Super Audio CD') 
 +    ) 
 +    album_title = models.CharField(max_length=255, verbose_name=verbose_names['album_title']) 
 +    medium_type = models.CharField(max_length=50, choices=MEDIUM_TYPE, verbose_name=verbose_names['medium_type']) 
 +    disc_number = models.PositiveIntegerField( 
 +        validators=[MinValueValidator(1), 
 +                    MaxValueValidator(50)],verbose_name=verbose_names['disk_number'
 +    ) 
 +    total_disc = models.PositiveIntegerField( 
 +        validators=[MinValueValidator(1), 
 +                    MaxValueValidator(50)],verbose_name=verbose_names['total_disk'
 +    ) 
 +    songs = models.ManyToManyField(Song) 
 + 
 +    def __str__(self): 
 +        return f"{self.album_title} - Album {self.disc_number}" 
 + 
 +    def clean(self): 
 +        if self.disc_number and self.total_disc and self.disc_number > self.total_disc: 
 +            raise ValidationError("Numer kolejny disku nie może być większy od całkowitej ilości dysków w albumie."
 +</code> 
 + 
 +===== Dodanie MusicAlbum w panelu admina ===== 
 + 
 +<code python admin.py> 
 +from django.contrib import admin 
 +from .models import Song, Artist, MusicAlbum 
 +from django import forms 
 + 
 +class SongAdminForm(forms.ModelForm): 
 +    class Meta: 
 +        model = Song 
 +        fields = ['song_title', 'release_year', 'duration'
 + 
 +    def __init__(self, *args, **kwargs): 
 +        super().__init__(*args, **kwargs) 
 + 
 +        # Dodaj placeholder do pola duration 
 +        self.fields['duration'].widget.attrs['placeholder'] = 'HH:MM:SS' 
 + 
 +        # Dodaj placeholder do pola rok 
 +        self.fields['release_year'].widget.attrs['placeholder'] = 'Wprowadź rok wydania' 
 + 
 +    def clean_release_year(self): 
 +        release_year = self.cleaned_data['release_year'
 + 
 +        # Sprawdź, czy rok wydania zawiera dokładnie cztery cyfry 
 +        if release_year and (len(str(release_year)) != 4 or not str(release_year).isdigit()): 
 +            raise forms.ValidationError('Rok wydania musi składać się z dokładnie czterech cyfr.'
 + 
 +        # Sprawdź, czy rok wydania nie jest większy niż rok utworzenia 
 +        if release_year: 
 +            created_at_year = self.instance.created_at.year if self.instance and self.instance.created_at else timezone.now().year 
 +            if int(release_year) > created_at_year: 
 +                raise forms.ValidationError("Rok wydania nie może być większy niż rok utworzenia."
 + 
 +        return release_year 
 + 
 +    def clean_duration(self): 
 +        duration = self.cleaned_data['duration'
 + 
 +        # Sprawdzamy, czy duration ma poprawny format (HH:MM:SS) 
 +        if duration.total_seconds() < 0: 
 +            raise forms.ValidationError('Niewłaściwy format czasu. Użyj wartości nieujemnej.'
 + 
 +        # Sprawdzamy, czy duration nie przekracza 01:59:59 
 +        if duration.total_seconds() > 7199: 
 +            raise forms.ValidationError('Maksymalna długość to 1 godzina, 59 minut i 59 sekund.'
 + 
 +        return duration 
 + 
 +class ArtistInline(admin.TabularInline): 
 +    model = Artist.songs.through  # To jest model pośredniczący w relacji wiele-do-wielu 
 +    extra = 1 
 + 
 +@admin.register(Song) 
 +class SongAdmin(admin.ModelAdmin): 
 +    form = SongAdminForm 
 +    list_display = ('song_title', 'release_year', 'duration', 'created_at', 'modified_at'
 +    list_filter = ('release_year',
 +    search_fields = ('song_title',
 +    readonly_fields = ['created_at', 'modified_at'
 +    inlines = [ArtistInline] 
 + 
 +@admin.register(Artist) 
 +class ArtistAdmin(admin.ModelAdmin): 
 +    list_display = ('artist_name',
 +    search_fields = ['artist_name'
 +    filter_horizontal = ('songs',
 + 
 +@admin.register(MusicAlbum) 
 +class MusicAlbumAdmin(admin.ModelAdmin): 
 +    # form = MusicAlbumAdminForm 
 +    list_display = ('album_title', 'disc_number', 'total_disc'
 +    search_fields = ['album_title'
 +    filter_horizontal = ('songs',
 +</code> 
 + 
 +===== Zmiana typu pola release_year w modelu Song ===== 
 +Po przeanalizowaniu w przypadku modelu ''Song'' i pola ''release_year'' wydaje się bardziej uzasadnione użycie pola ''PositiveIntegerField''. Wprowadzamy więc stosowane modyfikacje. Uwzględniamy, że rok musi się składać z ''4'' cyfr i że rok wydania nie może być późniejszy od daty tworzenia wpisu. W zasadzie jeżeli wpiszemy minimalną dozwoloną wartość ''1000'' dla pola ''release_year'' walidacja czterech cyfr jest zbędna ale zostawiamy ją dla bajeru. Walidację też przenosimy z pliku ''admin.py'' do ''models.py''. Wynik będzie taki, że będzie ona działać dla panelu admin jak również na stronie użytkownika.\\ 
 +\\ 
 +Poniżej pliki po modyfikacji. 
 +<code python models.py> 
 +from django.db import models 
 +from django.utils import timezone 
 +from .verbose_names import verbose_names 
 +from django.core.validators import MinValueValidator, MaxValueValidator, ValidationError 
 + 
 +# Funkcja walidacyjna dla pola release_year 
 +def validate_release_year(value): 
 +    current_year = timezone.now().year 
 +    if not str(value).isdigit() or len(str(value)) != 4: 
 +        raise ValidationError("Rok wydania musi się składać z czterech cyfr"
 +    if value > current_year: 
 +        raise ValidationError("Rok wydania nie może być większy od roku tworzenia wpisu."
 + 
 +class Song(models.Model): 
 +    song_title = models.CharField(max_length=200, verbose_name=verbose_names['song_title']) 
 +    release_year = models.PositiveIntegerField( 
 +        validators=[MinValueValidator(1000),validate_release_year],verbose_name=verbose_names['release_year']) 
 +    duration = models.DurationField(null=True, verbose_name=verbose_names['duration']) 
 +    created_at = models.DateTimeField(default=timezone.now, verbose_name=verbose_names['created_at'], editable=False) 
 +    modified_at = models.DateTimeField(auto_now=True, verbose_name='Data ostatniej modyfikacji'
 + 
 +    class Meta: 
 +        verbose_name = 'Song' 
 +        verbose_name_plural = 'Songs' 
 +        unique_together = ('song_title', 'release_year'
 + 
 +    def __str__(self): 
 +        return f"{self.song_title}, ({self.release_year})" 
 + 
 +class Artist(models.Model): 
 +    artist_name = models.CharField(max_length=255, verbose_name=verbose_names['artist_name']) 
 +    songs = models.ManyToManyField(Song) 
 + 
 +    class Meta: 
 +        verbose_name = 'Artist' 
 +        verbose_name_plural = 'Artists' 
 + 
 +    def __str__(self): 
 +        return self.artist_name 
 + 
 +class MusicAlbum(models.Model): 
 +    MEDIUM_TYPE = ( 
 +        ('audiocd', 'Audio CD'), 
 +        ('audiocd_r', 'Audio CD-R'), 
 +        ('sacd', 'Super Audio CD') 
 +    ) 
 +    album_title = models.CharField(max_length=255, verbose_name=verbose_names['album_title']) 
 +    medium_type = models.CharField(max_length=50, choices=MEDIUM_TYPE, verbose_name=verbose_names['medium_type']) 
 +    disc_number = models.PositiveIntegerField( 
 +        validators=[MinValueValidator(1), 
 +                    MaxValueValidator(50)],verbose_name=verbose_names['disk_number'
 +    ) 
 +    total_disc = models.PositiveIntegerField( 
 +        validators=[MinValueValidator(1), 
 +                    MaxValueValidator(50)],verbose_name=verbose_names['total_disk'
 +    ) 
 +    songs = models.ManyToManyField(Song) 
 + 
 +    def __str__(self): 
 +        return f"{self.album_title} - Album {self.disc_number}" 
 + 
 +    def clean(self): 
 +        if self.disc_number and self.total_disc and self.disc_number > self.total_disc: 
 +            raise ValidationError("Numer kolejny disku nie może być większy od całkowitej ilości dysków w albumie."
 +</code> 
 +<code python admin.py> 
 +from django.contrib import admin 
 +from .models import Song, Artist, MusicAlbum 
 +from django import forms 
 + 
 +class SongAdminForm(forms.ModelForm): 
 +    class Meta: 
 +        model = Song 
 +        fields = ['song_title', 'release_year', 'duration'
 + 
 +    def __init__(self, *args, **kwargs): 
 +        super().__init__(*args, **kwargs) 
 + 
 +        # Dodaj placeholder do pola duration 
 +        self.fields['duration'].widget.attrs['placeholder'] = 'HH:MM:SS' 
 + 
 +        # Dodaj placeholder do pola rok 
 +        self.fields['release_year'].widget.attrs['placeholder'] = 'Wprowadź rok wydania' 
 + 
 + 
 +    def clean_duration(self): 
 +        duration = self.cleaned_data['duration'
 + 
 +        # Sprawdzamy, czy duration ma poprawny format (HH:MM:SS) 
 +        if duration.total_seconds() < 0: 
 +            raise forms.ValidationError('Niewłaściwy format czasu. Użyj wartości nieujemnej.'
 + 
 +        # Sprawdzamy, czy duration nie przekracza 01:59:59 
 +        if duration.total_seconds() > 7199: 
 +            raise forms.ValidationError('Maksymalna długość to 1 godzina, 59 minut i 59 sekund.'
 + 
 +        return duration 
 + 
 +class ArtistInline(admin.TabularInline): 
 +    model = Artist.songs.through  # To jest model pośredniczący w relacji wiele-do-wielu 
 +    extra = 1 
 + 
 +@admin.register(Song) 
 +class SongAdmin(admin.ModelAdmin): 
 +    form = SongAdminForm 
 +    list_display = ('song_title', 'release_year', 'duration', 'created_at', 'modified_at'
 +    list_filter = ('release_year',
 +    search_fields = ('song_title',
 +    readonly_fields = ['created_at', 'modified_at'
 +    inlines = [ArtistInline] 
 + 
 +@admin.register(Artist) 
 +class ArtistAdmin(admin.ModelAdmin): 
 +    list_display = ('artist_name',
 +    search_fields = ['artist_name'
 +    filter_horizontal = ('songs',
 + 
 +@admin.register(MusicAlbum) 
 +class MusicAlbumAdmin(admin.ModelAdmin): 
 +    # form = MusicAlbumAdminForm 
 +    list_display = ('album_title', 'disc_number', 'total_disc'
 +    search_fields = ['album_title'
 +    filter_horizontal = ('songs',
 +</code> 
 + 
 +===== Zmiana organizacji modeli ===== 
 + 
 +Do tego momentu utwory były bezpośrednio dodawane do albumu. Skoro album może się składać z kilku nośników (płyt) dodajemy kolejny model 'StorageMedium' gdzie będziemy dodawać utwory a dopiero dane medium do albumu. 
 + 
 +===== Założenia w pliku modeli po modyfikacji ===== 
 + 
 +<code python models.py> 
 +from django.db import models 
 +from django.utils import timezone 
 +from .verbose_names import verbose_names 
 +from django.core.validators import MinValueValidator, MaxValueValidator, ValidationError 
 + 
 +# Funkcja walidacyjna dla pola release_year 
 +def validate_release_year(value): 
 +    current_year = timezone.now().year 
 +    if not str(value).isdigit() or len(str(value)) != 4: 
 +        raise ValidationError("Rok wydania musi się składać z czterech cyfr"
 +    if value > current_year: 
 +        raise ValidationError("Rok wydania nie może być większy od roku tworzenia wpisu."
 + 
 +class Song(models.Model): 
 +    song_title = models.CharField(max_length=200, verbose_name=verbose_names['song_title']) 
 +    release_year = models.PositiveIntegerField( 
 +        validators=[MinValueValidator(1000),validate_release_year],verbose_name=verbose_names['release_year']) 
 +    duration = models.DurationField(null=True, verbose_name=verbose_names['duration']) 
 +    created_at = models.DateTimeField(default=timezone.now, verbose_name=verbose_names['created_at'], editable=False) 
 +    modified_at = models.DateTimeField(auto_now=True, verbose_name='Data ostatniej modyfikacji'
 + 
 +    class Meta: 
 +        verbose_name = 'Song' 
 +        verbose_name_plural = 'Songs' 
 +        unique_together = ('song_title', 'release_year'
 + 
 +    def __str__(self): 
 +        return f"{self.song_title}, ({self.release_year})" 
 + 
 +class Artist(models.Model): 
 +    artist_name = models.CharField(max_length=255, verbose_name=verbose_names['artist_name']) 
 +    songs = models.ManyToManyField(Song) 
 + 
 +    class Meta: 
 +        verbose_name = 'Artist' 
 +        verbose_name_plural = 'Artists' 
 + 
 +    def __str__(self): 
 +        return self.artist_name 
 + 
 +class MusicAlbum(models.Model): 
 +    album_title = models.CharField(max_length=255, verbose_name=verbose_names['album_title']) 
 +    total_disc = models.PositiveIntegerField( 
 +        validators=[MinValueValidator(1), 
 +                    MaxValueValidator(50)], verbose_name=verbose_names['total_disk'
 +    ) 
 +    def __str__(self): 
 +        return f"{self.album_title}" 
 + 
 +class StorageMedium(models.Model): 
 +    MEDIUM_TYPE = ( 
 +        ('audiocd', 'Audio CD'), 
 +        ('audiocd_r', 'Audio CD-R'), 
 +        ('sacd', 'Super Audio CD') 
 +    ) 
 +    albums_title = models.ForeignKey('MusicAlbum', on_delete=models.PROTECT, 
 +                                     verbose_name=verbose_names['albums_title'], related_name='musicalbum'
 +    disc_title = models.CharField(max_length=255, verbose_name=verbose_names['disc_title']) 
 +    medium_type = models.CharField(max_length=50, choices=MEDIUM_TYPE, verbose_name=verbose_names['medium_type']) 
 +    disc_number = models.PositiveIntegerField( 
 +        validators=[MinValueValidator(1), 
 +                    MaxValueValidator(50)], verbose_name=verbose_names['disk_number'
 +    ) 
 +    songs = models.ManyToManyField(Song, verbose_name=verbose_names['songs']) 
 + 
 +    class Meta: 
 +        unique_together = ('albums_title', 'disc_number'
 + 
 +    def clean(self): 
 +        super().clean() 
 + 
 +        if self.disc_number > self.albums_title.total_disc: 
 +            raise ValidationError({'disc_number':'Numer dysku nie może być większy niż ilość dysków w albumie.'}) 
 + 
 +    def __str__(self): 
 +        return f"W albumie \"{self.albums_title}\" płyta pt. \"{self.disc_title}\" nośnik nr {self.disc_number}" 
 +</code> 
 + 
 +===== Założenia w pliku admin po modyfikacji ===== 
 + 
 +<code python admin.py> 
 +from django.contrib import admin 
 +from .models import Song, Artist, MusicAlbum, StorageMedium 
 +from django import forms 
 + 
 +class SongAdminForm(forms.ModelForm): 
 +    class Meta: 
 +        model = Song 
 +        fields = ['song_title', 'release_year', 'duration'
 + 
 +    def __init__(self, *args, **kwargs): 
 +        super().__init__(*args, **kwargs) 
 + 
 +        # Dodaj placeholder do pola duration 
 +        self.fields['duration'].widget.attrs['placeholder'] = 'HH:MM:SS' 
 + 
 +        # Dodaj placeholder do pola rok 
 +        self.fields['release_year'].widget.attrs['placeholder'] = 'Wprowadź rok wydania' 
 + 
 + 
 +    def clean_duration(self): 
 +        duration = self.cleaned_data['duration'
 + 
 +        # Sprawdzamy, czy duration ma poprawny format (HH:MM:SS) 
 +        if duration.total_seconds() < 0: 
 +            raise forms.ValidationError('Niewłaściwy format czasu. Użyj wartości nieujemnej.'
 + 
 +        # Sprawdzamy, czy duration nie przekracza 01:59:59 
 +        if duration.total_seconds() > 7199: 
 +            raise forms.ValidationError('Maksymalna długość to 1 godzina, 59 minut i 59 sekund.'
 + 
 +        return duration 
 + 
 +class ArtistInline(admin.TabularInline): 
 +    model = Artist.songs.through  # To jest model pośredniczący w relacji wiele-do-wielu 
 +    extra = 1 
 + 
 +@admin.register(Song) 
 +class SongAdmin(admin.ModelAdmin): 
 +    form = SongAdminForm 
 +    list_display = ('song_title', 'release_year', 'duration', 'created_at', 'modified_at'
 +    list_filter = ('release_year',
 +    search_fields = ('song_title',
 +    readonly_fields = ['created_at', 'modified_at'
 +    inlines = [ArtistInline] 
 + 
 +@admin.register(Artist) 
 +class ArtistAdmin(admin.ModelAdmin): 
 +    list_display = ('artist_name',
 +    search_fields = ['artist_name'
 +    filter_horizontal = ('songs',
 + 
 +class StorageMediumInline(admin.StackedInline): 
 +    model = StorageMedium 
 +    extra = 1 
 +    filter_horizontal = ('songs',
 + 
 +@admin.register(MusicAlbum) 
 +class MusicAlbumAdmin(admin.ModelAdmin): 
 +    search_fields = ['album_title'
 +    inlines = [StorageMediumInline] 
 + 
 +@admin.register(StorageMedium) 
 +class StorageMediumAdmin(admin.ModelAdmin): 
 +    filter_horizontal = ('songs',
 +    search_fields = ['disc_title'
 +    list_filter = ('albums_title',
 +</code> 
 +  
  
  
pl/python/dbaudiocd.1700747568.txt.gz · ostatnio zmienione: 2023/11/23 14:52 przez sindap

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki