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:55] – [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 827: Linia 852:
 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...+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.1700747734.txt.gz · ostatnio zmienione: 2023/11/23 14:55 przez sindap

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki