Wprowadzenie.
Gdy projektujemy aplikację, często chcemy, aby była łatwo skalowalna, a zarazem czytelna. Django w tym celu dostarcza nam między innymi dwa tagi, którymi są extends oraz include. O tagu extends już trochę napisałem we wpisie Django – #7 – Pierwsza aplikacja – Rozszerzenia szablonów, lecz wydaje mi się, że temu zagadnieniu warto poświęcić jeszcze trochę uwagi oraz zestawić obydwa tagi razem demonstrując tym samym ich funkcjonalności.
Zakres artykułu.
- Wbudowane tagi szablonów (Extends i Include)
Wbudowane tagi szablonów (Extends i Include)
Jak już zaznaczyłem na wstępnie jeden, jak i drugi tag pozwalają uczynić naszą stronę łatwiej skalowalną. Tagi te mają za zadanie wstawianie kodu z jednego pliku do drugiego zgodnie z pewnymi zasadami.
Poniżej zamieściłem przykład, który demonstruje, kiedy możemy zastosować rozwiązanie z tagiem extends, a kiedy z tagiem include.
Na początek zajmę się tagiem extends. Jak możemy zobaczyć relacja ta, występuje między plikiem home.html (dziecko) oraz main.html (rodzic). W pliku main.html należy zamieścić tag {% block dowolna_nazwa_bloku %} {% endblock %}, natomiast w pliku home.html należy zamieścić koniecznie na początku pliku tag {% extends “main.html” %} a następnie w dowolnym miejscu tag {% block dowolna_nazwa_bloku %} tu_jest_nasz_kod {% endblock %}. Taka struktura powoduje, że w miejsce tagu z pliku rodzica, wstawiany jest kod z tagu z pliku dziecka. Ze względy na fakt, że bloki oznaczone są dowolną nazwą, mamy możliwość wprowadzenia wielu takich tagów.
Przejdźmy teraz do tagu include z punktu widzenia pliku home.html oraz navbar.html. Jak widzimy, tagu tego możemy użyć wielokrotnie. Tag ten zamieszczany jest tylko w jedym pliku, co oznacza, że drugi plik nie będzie zawierał informacji, że może być użyty. W naszym przypadku include zamieszczamy w pliku home.html. Mechanizm ten powoduje, że kod zamieszczony w pliku navbar.html zostanie umieszczony w miejsce tagu include {% include “finance/navbar.html” %}, znajdującego się w pliku home.html.
Żeby nie zajmować się tworzeniem projektu na nowo, wykorzystałem szkielet projektu ze wpisu Django – #13 – System Autoryzacji cz. 1, który następnie podzieliłem między wyżej wymienione pliki i w niektórych miejscach dokonałem lekkiej modyfikacji.
Kod pliku main.html.
<!doctype html> <html lang="pl"> <head> {% include "finance/head.html" %} </head> {% block content %}{% endblock %} </html>
W pliku tym, w miejsce zawartości między tagiem head, zamieściłem tag include, a usunięty kod przeniosłem do pliku head.html. Druga modyfikacja polegała na usunięciu kodu z tagu body wraz z tym tagiem.
Kod pliku head.html.
<!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <!-- Bootstrap CSS --> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous"> <link rel="shortcut icon" href="#" /> <title>Hello, world!</title> <!-- Optional JavaScript --> <!-- jQuery first, then Popper.js, then Bootstrap JS --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script>
Kod ten jak już wspomniałem, został przeniesiony z tagu head pliku main.html.
Kod pliku home.html.
{% extends 'finance/main.html' %} {% block content %} {% include "finance/body_start.html" %} {% include "finance/navbar.html" %} {% include "finance/home_content.html" with layout=v_layout name="Hello" %} {% include "finance/footer.html" %} {% include "finance/body_end.html" %} {% endblock %}
Kod ten w zasadzie ma za zadanie rozszerzeć szablon main.html, gdzie zawartość wszystkich tagów include ma zostać umieszczona w bloku o nazwie content z pliku main.html. W tym miejscu warto zwrócić uwagę na linijkę z kodem {% include “finance/home_content.html” with layout=v_layout name=”Hello” %}, gdzie zostały umieszczone argumenty layout oraz name, które przekazywane są do pliku home_content.html. W tym miejscu muszę zaznaczyć, że do argumentu layout została przypisana zmienna v_layout, która jak później zobaczymy, znajduje się w widoku funkcji renderującej plik home.html.
Tu widzimy kolejną zaletę tagów include, które pozwalają używać argumentów.
Kod pliku body_start.html.
<body>
W tym miejscu można byłoby się zastanowić, dlaczego nie zastosowałem tagu extend, lecz dzięki takiej konstrukcji i możliwości użycia argumentów w include, jestem w stanie w prosty sposób kontrolowa na przykład przypisane klasy stylów css tagu body.
Kod pliku body_end.html.
</body>
Kod pliku navbar.html.
<div class="d-flex flex-column flex-md-row align-items-center p-3 px-md-4 mb-3 bg-white border-bottom shadow-sm"> <h5 class="my-0 mr-md-auto font-weight-normal">AUTH SYSTEM</h5> <nav class="my-2 my-md-0 mr-md-3"> <a class="btn btn-outline-primary" href="#">Zarejestruj się</a> <a class="btn btn-outline-primary" href="#">Zaloguj się</a> <a class="btn btn-outline-danger" href="#">Wyloguj się</a> </nav> </div>
Plik ten zawiera jedynie przeniesioną części kodu odpowiedzialną za generowanie paska nawigacji.
Kod pliku home_content.html.
<div class="container"> <h2>HOME</h2> <h3> {% if layout == "1" %} {% include "finance/home_content_layout1.html" %} {% elif layout == "2" %} {% include "finance/home_content_layout2.html" %} {% else %} {% include "finance/home_content_layout3.html" %} {% endif %} </h3> </div>
Do tego pliku dodałem kod umieszczony w tagu h3. Kod ten wykorzystuje tagi if, elif, else oraz endif, które sterowane są przy pomocy przekazanego argumentu v_layout. Na podstawie wartości argumentu jesteśmy w stanie określać, który plik chcemy dołączyć do pliku home_content.html.
Kod plików home_content_layout1.html, home_content_layout2.html, home_content_layout3.html.
layout1
layout2
layout3
Kod ten ma nas tylko informować, który plik się załączył, dzięki czemu możemy sprawdzić, czy wartość, która była przekazana do parametru, została przekazana poprawnie.
Kod pliku views.py.
from django.shortcuts import render # Create your views here. def home(request): context = { 'v_layout': '1', } return render(request, 'finance/home.html', context)
W tym pliku w słowniku context umieszczamy naszą wcześniej już wspominaną zmienną v_layout, która jest odpowiedzialna za sterowanie załączaniem odpowiedniego pliku home_content_layout1.html, home_content_layout2.html, home_content_layout3.html
Wpisanie w przeglądarkę adresu 127.0.0.1:8000, w takim przypadku, powinno spowodować pojawienie się następującej strony.
Zmodyfikujmy funkcję widoku home, gdzie teraz do zmiennej v_layout przypiszmy zmienną ‘2‘.
from django.shortcuts import render # Create your views here. def home(request): context = { 'v_layout': '2', } return render(request, 'finance/home.html', context)
Taka modyfikacja spowoduje, że wpisanie tego samego adresu wygeneruje nam następującą stronę.
Wykonajmy jeszcze jeden test i do zmiennej v_layout wpiszmy wartość ‘asd‘.
from django.shortcuts import render # Create your views here. def home(request): context = { 'v_layout': 'asd', } return render(request, 'finance/home.html', context)
W efekcie otrzymamy następującą stronę.