Sekrety Django Templates #1. Html na sterydach

Szablony Django (Django templates) to pliki tekstowe, zawierające najczęściej kod html, do których możemy wstrzyknąć dodatkowe zmienne przekazane z widoku. 

Dzisiaj postaram się pokazać Ci, jak dokładnie wygląda wymiana informacji pomiędzy tymi szablonami a widokami i zaprezentuję kilka ciekawych sztuczek, dzięki którym możesz uprościć swój kod.

Na potrzeby tego artykułu stworzyłam prosty widok zwracający informację o dwóch studentach:

class StudentsView(View):
    
    def get(self, request):
        student_1 = {'name': 'John', 'surname': 'Black', 'grade':5.0}
        student_2 = {'name': 'Mary', 'surname': 'White', 'grade': 3.5}
        context = {
            'student_1': student_1,
            'student_2': student_2
        }
        return render(request, 'students.html', context=context) 

Co możemy z nim zrobić?

1. Zmienne

Jeśli chcesz odczytać wartość zmiennej przekazanej do szablonu, podaj jej nazwę w podwójnych nawiasach klamrowych: {{ .. }}.

Zacznij od stworzenia szablonu students.html i uzupełnij go w następujący sposób:

Student 1 : {{ student_1 }}
Student 2 : {{ student_2 }} 

W przeglądarce powinieneś zobaczyć coś takiego:

Student 1: {'name': 'John', 'surname': 'Black', 'grade': 5.0}
Student 2: {'name': 'Mary', 'surname': 'White', 'grade': 3.5}

Brawo! Django zwróciło całą zawartość wywołanych obiektów. 

No to lecimy dalej. 

Słowniki

Aby odczytać wybrane pola słownika (dict), należy po kropce podać nazwę odpowiedniego klucza:

Student 1:
Imię: {{ student_1.name }}, Nazwisko: {{ student_1.surname }}
 

Powyższy kod zwróci następujący widok:

Student 1:
Imię: John, Nazwisko: Black

W ten sposób możesz odwoływać się do dowolnych kluczy i wyświetlać powiązane z nimi wartości. 

Obiekty

Aby odwołać się do atrybutów obiektów klas, należy postąpić tak samo i również wykorzystać notację kropki (dot notation).

Sprawdź więc teorię i zmodyfikuj nieco widok, tworząc trzeciego studenta i przekazując go do kontekstu:

student_3 = Student(name='Mike', surname='Doe', grade=4.5)
context = {
            ...
            'student_3': student_3
}    

Brakuje jeszcze definicji nowej klasy Student. W najprostszej implementacji może ona wyglądać tak:

class Student:
    def __init__(self, name, surname, grade):
        self.name = name
        self.surname = surname
        self.grade = grade 
Domyślasz się juz, jak będzie wyglądał nowy widok? Myślę, że tak. 😃
Student 3:
Imię: {{ student_3.name}}, Nazwisko: {{ student_3.surname }} 

Teraz nie ma już innej możliwości, jak tylko podejrzeć dane nowego studenta:

Student 3:
Imię: Mike, Nazwisko: Doe

Proste, prawda?😉 

No to czas połączyć studentów w jedną całość i stworzyć z nich listę.

Listy

Na początek mała modyfikacja widoku i nowa zmienna przekazana do kontekstu:

students_list = [student_1, student_2, student_3]
context = {
            ...
            'students_list': students_list
} 

I tutaj czeka nas coś zaskakującego. Jeśli w kodzie Pythona chciałbyś pobrać pierwszego studenta z listy, użyłbyś poniższego zapisu: 

students_list[0] 

Niestety w przypadku szablonów twórcy Django nagięli nieco własne zasady i zastąpili nawiasy kwadratowe kropką! 😯

Stąd też odwołanie się do pierwszego elementu listy będzie wyglądało odrobinę inaczej, niż mogłoby się wydawać:

Pierwszy student z listy: {{ students_list.0 }}
Drugi student z listy: {{ students_list.1 }} 

W rezultacie powinieneś zobaczyć poniższy wynik:

Pierwszy student z listy:
{'name': 'John', 'surname': 'Black', 'grade': 5.0}
Drugi student z listy:
{'name': 'Mary', 'surname': 'White', 'grade': 3.5}

Dziwne? 🤨 Tak, mi też na początku wydawało mi się to niezbyt logiczne, ale jak się nie ma co się lubi… to lepiej docenić to, co się ma. 😁

A teraz ciekawostka!

Jak myślisz, co się stanie, kiedy nazwa Twojej zmiennej będzie zaczynać się od podkreślnika?

Próba wywołania w szablonie takiej zmiennej: {{ _student_4 }} zakończy się poniższym błędem:

Dlaczego?

Zgodnie z konwencją Pythona zmienne rozpoczynające się podkreślnikiem uważane są za prywatne i nie mogą być dostępne z zewnątrz. Zwracaj więc uwagę na to, jak nazywasz swoje zmienne.

2. Tagi

Oprócz obsługi zmiennych Django umożliwia też sterowanie logiką wyświetlanych w szablonach danych. Służą do tego tzw. tagi, które wywołuje się z wykorzystaniem symbolu: {% ... %}, podając wewnątrz nazwę odpowiedniego znacznika.

Niektóre tagi działają tylko w obrębie wybranej sekcji szablonu i wywagają znacznika zamykającego: {% end... %}.

Może na razie wydaje Ci się to nieco zagmatwane, ale spokojnie. Zaraz wszystko wyjaśnię. 😀

Iteracja po liście
{% for ... in ... %}

Wróć więc do listy studentów i spróbuj wyświetlić informację o każdym z nich w nowym wierszu. Przyda się do tego tag {% for ... in ... %}, pozwalający iterować po liście podanej jako drugi parametr (po słowie in).
Jako pierwszy parametr możesz podać dowolną nazwę, która będzie służyła jako referencja do aktualnie przetwarzanego elementu listy.

<ul>
    {% for student in students_list %}
        <li>{{ student.name }} {{ student.surname }}</li>
    {% endfor %}
</ul> 

Powyższy kod wygeneruje następujący widok:

  • John Black
  • Mary White
  • Mike Doe

Jak widać potrzebny był też tag zamykający {% endfor %}. Dzięki niemu Django wie, które elementy szablonu musi wygenerować dla każdego elementy listy.

Instrukcje warunkowe
{% if ... elif ... else %}

A teraz czas na instrukcje warunkowe. Sprawdźmy więc oceny naszych studentów. Potrzebne będą do tego tagi: {% if ... %}, {% elif %}, {% else %} oraz zamykający {% endif %}
<ul>
    {% for student in students_list %}
        <li>
        {{ student.name }} {{ student.surname }}
        {% if student.grade == 5.0 %} - Kujon
        {% elif student.grade > 4 %} - Tak trzymaj!
        {% else %} - Pora na naukę!
        {% endif %}
        </li>
     {% endfor %}
</ul> 
Wewnątrz dwóch pierwszych tagów podaliśmy warunki, które muszą być spełnione, aby wyświetlił się odpowiedni komunikat. Tag {% else %} wyłapuje wszystkie pozostałe przypadki. Po odświeżeniu strony powinieneś otrzymać coś takiego:
  • John Black - Kujon
  • Mary White - Pora na naukę!
  • Mike Doe - Tak trzymaj!

W zależności od Twoich potrzeb możesz użyć tylu tagów {% elif %}, ile potrzebujesz. Z kolei zarówno {% elif %}, jak i {% else %} są opcjonalne i nie musisz ich używać, jeśli są zbędne.
Jednocześnie pamiętaj o znaczniku zamykającym: {% endif %}.

Dziedziczenie i nadpisywanie szablonów

Oprócz list i instrukcji warunkowych, jednymi z najczęściej używanych tagów są te, które umożliwiają rozszerzanie lub nadpisywanie szablonów. Zaliczają się do nich następujące znaczniki:

  • {% block ... %} {% endblock %} – opakowanie fragmentu szablonu tymi tagami pozwala na nadpisanie jego zawartości w innych szablonach,
  • {% extends ... %} – pozwala na wywołanie szablonu nadrzędnego w dziedziczącym z niego i ewentualne nadpisanie jego zawartości,
  • {% include %} – umożliwia wstrzyknięcie szablonu wewnątrz innego,
  • {% load %} – pozwala ładować dodatkowe tagi – własne lub z zewnętrznych bibliotek.

Poza kilkoma wymienionymi tagami Django udostępnia jeszcze wiele interesujących znaczników. Pełną listę możesz znaleźć w oficjalnej dokumentacji.

3. Filtry

Na koniec w kilku słowach chciałabym opisać trzeci mechanizm Django templates – filtry. Oferują one rozmaite przekształcenia wyświetlanej wartości wstrzykiwanych zmiennych, a wywołuje się je w następujący sposób:

{{ student1.name | filter_name }} 

Lista dostępnych filtrów jest naprawdę spora, a możesz ją znaleźć oczywiście w oficjalnej dokumentacji. Pozwolę sobie pokazać jedynie kilka wybranych przykładów.

Zacznijmy od dodania kilku pól do zmiennej student_1:

student_1 = {
    'name': 'John', 
    'surname': 'Black', 
    'grade': 5.0,
    'birth_date': datetime(2000, 10, 27, 16, 25),  
    'has_graduated': True, 
    'bio': 'Very smart \n and intelligent.', 
    'scholarship': ''
} 

Czas przekonać się, co potrafią filtry szablonów Django!

Operacje na ciągach znaków

  • lower – najprostsza operacja, czyli zamiana wszystkich liter na małe.
    Przykład: {{ student_1.name | lower }}    john.
  • upper – sytuacja odwrotna – zamiana wszystkich liter na wielkie.  Przykład:  {{ student_1.name | upper }}   ➜  JOHN
  • title – każde słowo podanego stringa rozpocznie się wielką literą.  Przykład:  {{ student_1.bio | title }}   ➜  Very Smart And Intelligent.
  • slice – wycina znaki z zakresu indeksów podanych w parametrze.
    Przykład:  {{ student_1.bio | slice:"5:16" }}   ➜  smart and
  • truncatechars – ucina stringa do podanej ilości znaków i dostawia wielokropek, który jest traktowany jako dodatkowy znak.
    Przykład:  {{ student_1.bio | truncatechars:7 }}   ➜  Very s…
  • truncatewords – ucina ciąg znaków do podanej ilości słów i dostawia wielokropek.
    Przykład:  {{ student_1.bio | truncatewords:2 }}   ➜  Very smart …
  • linebreaksbr – jeśli string zawiera znak końca linii ‘\n’, to zostanie on zamieniony na odpowiedni znacznik html: <br>.
    Przykład dla wartości bio = 'Very smart \n and intelligent.':

    {{ student_1.bio | linebreaksbr }}   ➜  Very smart
                                                                       and intelligent

Formatowanie daty / godziny

  • date – pozwala na wyświetlenie daty w dowolnym formacie.
    Przykład:  {{ student_1.birth_date | date:"d/m/Y" }}   ➜  27/10/2000
  • time – pozwala na wyświetlenie godziny w dowolnym formacie.
    Przykład:  {{ student_1.birth_date | time:"H:i" }}   ➜  16:25

Wszystkie dostępne formaty daty i godziny znajdziesz tutaj.

Wartości puste i domyślne

  • default – jeśli podana zmienna będzie nullem lub pustym stringiem, można ustawić jej wartość domyślną.
    Przykład:  {{ student_1.scholarship | default:"Brak" }}   ➜  Brak 
  • yesno – w przypadku wartości typu boolean można nadać im własne etykiety.
    Przykład:  {{ student_1.has_graduated | yesno:"Tak,Nie" }}   ➜  Tak

To zaledwie ułamek wszystkich możliwości filtrów, ale jak widać są one naprawdę ogromne.

Podsumowanie

Mam nadzieję, że udało mi się pokazać Ci jak wiele tajemnic kryją w sobie szablony Django. Odpowiednie wykorzystanie tagów i filtrów często pozwala zawrzeć skomplikowaną logikę w kilku liniach kodu.

Masz jakieś pytania albo wątpliwości? Podziel się swoim doświadczeniem w komentarzu!

I pozostań z nami, bo już niedługo kolejne artykuły, w których postaramy się odkryć jeszcze więcej sekretów Django Templates.

5 1 vote
Article Rating
guest
0 komentarzy
Inline Feedbacks
View all comments