Django modele, Podstawy_005:


Istnieje typ SlugField - wyjaśnij po co jest używany.

Odpowiedź:
  • SlugField jest typem pola w Django, które przechowuje "slug" — krótką, URL-przyjazną wersję tekstu, która najczęściej jest wykorzystywana w adresach URL.
  • Slug to zazwyczaj ciąg znaków, który jest przekształcony z długiego tekstu, np. tytułu, do formy bez spacji, z myślnikami (-) zamiast spacji i małymi literami.
  • Na przykład, tytuł 'Moje pierwsze wpisy blogowe' mógłby zostać przekonwertowany na slug: 'moje-pierwsze-wpisy-blogowe'.
  • class Post(models.Model):
        options = (
            ("draft", "Draft"),
            ("published", "Published")
        )
    
        title = models.CharField(max_length=250)
        slug = models.SlugField(max_length=250, unique_for_date="publish")
        publish = models.DateTimeField(default=timezone.now)
        author = models.ForeignKey(User, on_delete=models.CASCADE, related_name="blog_posts")
        content = models.TextField()
        status = models.CharField(max_length=10, choices=options, default="draft")
    
        def __str__(self):
            return self.title
  • SlugField automatycznie "slugifikuje" wartość, która jest przypisywana do tego pola. To oznacza, że:
    • Automatycznie konwertuje tekst na małe litery.
    • Usuwa znaki specjalne (takie jak znaki diakrytyczne) i zamienia je na odpowiedniki (np. ą -> a).
    • Zamienia spacje na myślniki (-).
  • Nie trzeba ręcznie wywoływać metod takich jak clean_slug — Django automatycznie zapewnia to przez walidację na poziomie modelu.

Jak zaimplementować automatyczne 'slugifying' w Django?

Odpowiedź:
  • Można to zrobić w metodzie save() modelu, która będzie sprawdzać, czy slug nie jest już ustawiony, a jeśli nie, wygeneruje go na podstawie title.
  • from django.utils.text import slugify
    
    class Post(models.Model):
        options = (
            ("draft", "Draft"),
            ("published", "Published")
        )
    
        title = models.CharField(max_length=250)
        slug = models.SlugField(max_length=250, unique_for_date="publish")
        publish = models.DateTimeField(default=timezone.now)
        author = models.ForeignKey(User, on_delete=models.CASCADE, related_name="blog_posts")
        content = models.TextField()
        status = models.CharField(max_length=10, choices=options, default="draft")
    
        def __str__(self):
            return self.title
    
        def save(self, *args, **kwargs):
            # Jeśli slug nie jest ustawiony, generujemy go na podstawie tytułu
            if not self.slug:
                self.slug = slugify(self.title)
    
            # Wywołujemy metodę save() klasy bazowej
            super(Post, self).save(*args, **kwargs)
                        
  • Co się tu dzieje?
    • slugify(self.title) - Używamy funkcji slugify z modułu django.utils.text, która zamienia tytuł na format "slugified" (czyli zamienia spacje na myślniki, konwertuje litery na małe, usuwa niealfanumeryczne znaki, itp.).
    • if not self.slug: - Sprawdzamy, czy pole slug jest puste (np. obiekt jest tworzony). Jeśli jest puste, generujemy wartość na podstawie title.
    • super(Post, self).save(*args, **kwargs) - Wywołujemy metodę save() klasy bazowej, aby obiekt został zapisany w bazie danych.
  • Automatyczne "slugifying" działa w Django, ale musisz ręcznie przypisać wartość do pola slug, najlepiej w metodzie save().
  • SlugField zapewnia walidację i "slugifying", ale musisz dostarczyć odpowiednią logikę generowania slugu, jeśli chcesz to zrobić automatycznie na podstawie innych pól, jak np. title.

005b. Podczas zapisu obiektu modelu domyślnie pole typu SlugField nie jest walidowane co do zgodności z formatem 'Slug' - dlaczego?

Odpowiedź:

To, że SlugField nie waliduje automatycznie formatu danych w metodzie save(), jest zgodne z filozofią Django.
Design Django mówi, że walidacja odbywa się w innych etapach.
    - Na poziomie formularzy.
    - Na poziomie metod clean() i walidatorów o ile wymusisz ich działanie i ręcznie wywołasz metodę full_clean.

Metoda save() w Django służy do zapisu danych do bazy, ale domyślnie nie waliduje danych.
Django przyjmuje, że dane są poprawne, ponieważ zakłada się, że walidacja powinna zostać przeprowadzona wcześniej
(np. w formularzach lub ręcznie przez programistę).
                    
Dlaczego SlugField działa w ten sposób?

Django rozdziela odpowiedzialność między warstwę modelu a formularzy (i innych customych operacji), aby dać większą elastyczność:
    1. Model:
        W modelu możesz zapisać dowolne dane, jeśli nie narzucisz dodatkowych ograniczeń.
        Django zakłada, że programista wie, co robi.

    2. Formularze i inne customowe operacji (jak wymuszona walidacja):
        Formularze Django, to miejsce, gdzie zazwyczaj odbywa się walidacja danych od użytkownika.
        W przypadku SlugField, formularze automatycznie sprawdzają poprawność formatu.
        Można customowo wymusić wywołanie walidacji na modelu (full_clean), ale to dalej jest zgodne z założeniem, że programista wie co robi.