Najważniejsze cechy Django: Szablonowanie zapisuje wiersze (część 2)

Opublikowany: 2022-03-10
Szybkie podsumowanie ↬ Tworzenie kodu front-endu w Django z szablonami i renderowaniem po stronie serwera łączy precyzyjną kontrolę nad odręcznym kodem HTML z czystym kodem i potężnymi funkcjami generowanych stron. Badamy rozbijanie złożonej strony internetowej na wiele szablonów, komponowanie tych komponentów oraz stosowanie tagów i filtrów w celu refaktoryzacji zwykłej strony HTML.

Niektóre proste podejścia do tworzenia stron internetowych wymagają od programisty ręcznego napisania każdej linii kodu HTML. Z drugiej strony, komercyjne programy do tworzenia witryn bez kodu tworzą cały kod HTML dla użytkownika automatycznie, często kosztem czytelności wynikowego kodu. Szablonowanie jest mniej więcej pośrodku tego spektrum, ale bliższe ręcznemu pisaniu HTML niż, powiedzmy, generowaniu struktury strony w aplikacji jednostronicowej za pomocą Reacta lub podobnej biblioteki. To idealne miejsce na kontinuum zapewnia wiele korzyści płynących z ręcznego HTML-a od zera (semantyczny/czytelny kod, pełna kontrola nad strukturą strony, szybkie ładowanie strony) i dodaje oddzielenie obaw i zwięzłości, a wszystko to kosztem poświęcenia czasu na pisanie zmodyfikowany HTML ręcznie. W tym artykule pokazano, jak używać szablonów Django do pisania złożonych stron.

Widmo HTML. (duży podgląd)

Dzisiejszy temat dotyczy poza frameworkiem Django. Flask (kolejna platforma internetowa) i Pelican (generator stron statycznych) to tylko dwa z wielu innych projektów Pythona, które wykorzystują to samo podejście do tworzenia szablonów. Jinja2 to silnik szablonów, którego używają wszystkie trzy frameworki, chociaż możesz użyć innego, zmieniając ustawienia projektu (ściśle mówiąc, Jinja2 jest nadzbiorem szablonów Django). Jest to wolnostojąca biblioteka, którą możesz włączyć do własnych projektów nawet bez frameworka, więc techniki z tego artykułu są bardzo przydatne.

Poprzednie części z serii:

  • Najważniejsze cechy Django: modele użytkownika i uwierzytelnianie (część 1)
  • Najważniejsze cechy Django: modele, administracja i wykorzystanie relacyjnej bazy danych (część 3)
  • Najważniejsze cechy Django: walka o zasoby statyczne i pliki multimedialne (część 4)
Więcej po skoku! Kontynuuj czytanie poniżej ↓

Renderowanie po stronie serwera

Szablon to po prostu plik HTML, w którym HTML został rozszerzony o dodatkowe symbole. Pamiętaj, co oznacza HTML : Język znaczników hipertekstowych . Jinja2, nasz język szablonów, po prostu dodaje do języka dodatkowe znaczące symbole znaczników. Te dodatkowe struktury są interpretowane, gdy serwer renderuje szablon, aby wyświetlić użytkownikowi zwykłą stronę HTML (to znaczy, że dodatkowe symbole z języka szablonów nie trafiają do końcowego wyniku).

Renderowanie po stronie serwera to proces tworzenia strony internetowej w odpowiedzi na żądanie. Django używa renderowania po stronie serwera do obsługi stron HTML klientowi. Pod koniec wykonywania funkcja widoku łączy żądanie HTTP, jeden lub więcej szablonów i opcjonalnie dane dostępne podczas wykonywania funkcji w celu skonstruowania pojedynczej strony HTML, którą wysyła jako odpowiedź do klienta. Dane trafiają z bazy danych przez widok do szablonu, aby trafić do użytkownika. Nie martw się, jeśli to abstrakcyjne wyjaśnienie nie ma w pełni sensu, w dalszej części artykułu przejdziemy do konkretnego przykładu.

Konfiguracja

W naszym przykładzie weźmiemy dość złożoną stronę internetową, szablon administratora Start Bootstrap i przepiszemy kod HTML jako szablon Jinja2. Zauważ, że biblioteka na licencji MIT używa innego systemu szablonów (opartego na JavaScript i Pug) do generowania strony, którą widzisz, ale ich podejście różni się znacznie od szablonów w stylu Jinja2, więc ten przykład jest bardziej inżynierią wsteczną niż tłumaczeniem ich doskonałego projektu open-source. Aby zobaczyć stronę, którą będziemy konstruować, możesz rzucić okiem na podgląd na żywo w Start Bootstrap.

Przygotowałem przykładową aplikację do tego artykułu. Aby uruchomić projekt Django na własnym komputerze, uruchom środowisko wirtualne Python 3, a następnie uruchom następujące polecenia:

 pip install django git clone https://github.com/philipkiely/sm_dh_2_dashboard.git cd sm_dh_2_dashboard python manage.py migrate python manage.py createsuperuser python manage.py loaddata employee_fixture.json python manage.py runserver

Następnie otwórz przeglądarkę internetową i przejdź do https://127.0.0.1:8000 . Powinieneś zobaczyć tę samą stronę co podgląd, pasującą do poniższego obrazu.

Strona główna pulpitu nawigacyjnego. (duży podgląd)

Ponieważ ten samouczek koncentruje się na frontendzie, podstawowa aplikacja Django jest bardzo prosta. Może się wydawać, że jest to dużo konfiguracji do prezentacji jednej strony internetowej i szczerze mówiąc, tak jest. Jednak tak duża konfiguracja może również wspierać znacznie bardziej niezawodną aplikację.

Teraz jesteśmy gotowi, aby przejść przez proces przekształcania tego 668-liniowego pliku HTML w odpowiednio zaprojektowaną witrynę Django.

Szablonowanie i dziedziczenie

Pierwszym krokiem w refaktoryzacji setek linijek kodu HTML w czysty kod jest podzielenie elementów na ich własne szablony, które Django skomponuje w jedną stronę internetową podczas kroku renderowania.

Zajrzyj do stron/szablonów . Powinieneś zobaczyć pięć plików:

  • base.html , podstawowy szablon, który będzie rozszerzany na każdej stronie internetowej. Zawiera <head> z tytułem, importami CSS itp.
  • navbar.html , kod HTML dla górnego paska nawigacyjnego, komponent, który należy dołączyć w razie potrzeby.
  • footer.html , kod stopki strony, inny składnik, który należy dołączyć w razie potrzeby.
  • sidebar.html , HTML dla paska bocznego, trzeci składnik, który należy dołączyć w razie potrzeby.
  • index.html , kod unikalny dla strony głównej. Ten szablon rozszerza szablon podstawowy i obejmuje trzy komponenty.

Django składa te pięć plików, tak jak Voltron, w celu renderowania strony indeksu. Słowa kluczowe, które na to pozwalają, to {% block %} , {% include %} i {% extend %} . W pliku base.html :

 {% block content %} {% endblock %}

Te dwie linie pozostawiają miejsce dla innych szablonów, które rozszerzają base.html o wstawienie własnego kodu HTML. Zauważ, że content jest nazwą zmiennej, możesz mieć wiele bloków o różnych nazwach w szablonie, dając elastyczność szablonom podrzędnym. Widzimy, jak to rozszerzyć w index.html :

 {% extends "base.html" %} {% block content %} <!-- HTML Goes Here --> {% endblock %}

Użycie słowa kluczowego extends z nazwą szablonu bazowego nadaje stronie indeksowej jej strukturę, oszczędzając nas przed kopiowaniem w nagłówku (zauważ, że nazwa pliku jest ścieżką względną w postaci ciągu znaków w cudzysłowie). Strona indeksu zawiera wszystkie trzy składniki, które są wspólne dla większości stron w witrynie. Wprowadzamy te komponenty z dołączonymi tagami, include poniżej:

 {% extends "base.html" %} {% block content %} {% include "navbar.html" %} {% include "sidebar.html" %} <!--Index-Specific HTML--> {% include "footer.html" %} <!--More Index-Specific HTML--> {% endblock %}

Ogólnie rzecz biorąc, ta struktura zapewnia trzy kluczowe korzyści w porównaniu z indywidualnym pisaniem stron:

  • Kod DRY (nie powtarzaj się)
    Rozkładając wspólny kod na określone pliki, możemy zmienić kod tylko w jednym miejscu i odzwierciedlić te zmiany na wszystkich stronach.
  • Większa czytelność
    Zamiast przewijać jeden gigantyczny plik, możesz wyizolować konkretny komponent, który Cię interesuje.
  • Separacja obaw
    Kod dla, powiedzmy, paska bocznego musi teraz znajdować się w jednym miejscu, nie może być żadnych nieuczciwych tagów script pływających na dole kodu lub innych elementów łączących się między tym, co powinno być oddzielnymi komponentami. Wyodrębnianie poszczególnych elementów wymusza tę dobrą praktykę kodowania.

Chociaż moglibyśmy zaoszczędzić jeszcze więcej wierszy kodu, umieszczając określone komponenty w szablonie base.html , trzymanie ich oddzielnie zapewnia dwie korzyści. Po pierwsze, jesteśmy w stanie osadzić je dokładnie tam, gdzie należą w pojedynczym bloku (dotyczy to tylko footer.html , który znajduje się w głównym div bloku content ). Inną zaletą jest to, że gdybyśmy utworzyli stronę, powiedzmy stronę błędu 404, i nie chcielibyśmy paska bocznego lub stopki, moglibyśmy je pominąć.

Te możliwości są typowe dla kursu tworzenia szablonów. Teraz zwracamy się do potężnych tagów, których możemy użyć w naszym index.html , aby zapewnić dynamiczne funkcje i zapisać setki wierszy kodu.

Dwa podstawowe tagi

To bardzo daleko od wyczerpującej listy dostępnych tagów. Dokumentacja Django dotycząca tworzenia szablonów zawiera takie wyliczenie. Na razie skupiamy się na przypadkach użycia dla dwóch najczęstszych elementów języka szablonów. W mojej własnej pracy zasadniczo używam regularnie tylko tagów for i if , chociaż kilkanaście innych dostarczonych tagów ma swoje własne przypadki użycia, które zachęcam do przejrzenia w dokumentacji szablonu.

Zanim przejdziemy do tagów, chcę zrobić notatkę na temat składni. Znacznik {% foo %} oznacza, że ​​„foo” jest funkcją lub inną funkcją samego systemu szablonów, natomiast znacznik {{ bar }} oznacza, że ​​„bar” jest zmienną przekazywaną do określonego szablonu.

Dla pętli

W pozostałym index.html największą sekcją kodu o kilkaset wierszy jest tabela. Zamiast tej zakodowanej na sztywno tabeli, możemy generować tabelę dynamicznie z bazy danych. Przywołaj python manage.py loaddata employee_fixture.json z etapu konfiguracji. To polecenie używało pliku JSON, zwanego Django Fixture, do załadowania wszystkich 57 rekordów pracowników do bazy danych aplikacji. Używamy widoku w views.py , aby przekazać te dane do szablonu:

 from django.shortcuts import render from .models import Employee def index(request): return render(request, "index.html", {"employees": Employee.objects.all()})

Trzecim argumentem pozycyjnym do render jest słownik danych udostępniany szablonowi. Używamy tych danych i znacznika for do skonstruowania tabeli. Nawet w oryginalnym szablonie, z którego zaadaptowałem tę stronę, tabela pracowników była zakodowana na sztywno. Nasze nowe podejście eliminuje setki wierszy powtarzających się na stałe wierszy tabeli. index.html zawiera teraz:

 {% for employee in employees %} <trv <td>{{ employee.name }}</td> <td>{{ employee.position }}</td> <td>{{ employee.office }}</td> <td>{{ employee.age }}</td> vtd>{{ employee.start_date }}</td> <td>${{ employee.salary }}</td> </tr> {% endfor %}

Większą zaletą jest to, że znacznie upraszcza to proces aktualizacji tabeli. Zamiast zmuszać programistę do ręcznej edycji kodu HTML, aby odzwierciedlić podwyżkę wynagrodzenia lub nowo zatrudnionego pracownika, a następnie wprowadzić tę zmianę do środowiska produkcyjnego, każdy administrator może użyć panelu administracyjnego do wprowadzania aktualizacji w czasie rzeczywistym (https://127.0.0.1/admin, użyj poświadczenia utworzone w python manage.py createsuperuser , aby uzyskać dostęp). Jest to zaleta używania Django z tym silnikiem renderującym, zamiast używania go samodzielnie w generatorze stron statycznych lub innym podejściu do szablonów.

Jeśli inaczej

Tag if jest niezwykle potężnym tagiem, który umożliwia ocenę wyrażeń w szablonie i odpowiednie dostosowanie kodu HTML. Wiersze takie jak {% if 1 == 2 %} są całkowicie poprawne, choć trochę bezużyteczne, ponieważ za każdym razem dają ten sam wynik. Tag if świeci się podczas interakcji z danymi przekazanymi do szablonu przez widok. Rozważmy następujący przykład z sidebar.html :

 <div class="sb-sidenav-footer"> <div class="small"> Logged in as: </div> {% if user.is_authenticated %} {{ user.username }} {% else %} Start Bootstrap {% endif %} </div>

Zauważ, że cały obiekt użytkownika jest domyślnie przekazywany do szablonu, bez określania czegokolwiek w widoku, aby tak się stało. Pozwala nam to uzyskać dostęp do statusu uwierzytelnienia użytkownika (lub jego braku), nazwy użytkownika i innych funkcji, w tym śledzenia relacji klucza obcego w celu uzyskania dostępu do danych przechowywanych w profilu użytkownika lub innym połączonym modelu, wszystko z pliku HTML.

Możesz obawiać się, że ten poziom dostępu może stanowić zagrożenie dla bezpieczeństwa. Należy jednak pamiętać, że te szablony są przeznaczone dla struktury renderowania po stronie serwera. Po zbudowaniu strony tagi same się zużywają i są zastępowane czystym kodem HTML. Tak więc, jeśli instrukcja if wprowadza dane do strony pod pewnymi warunkami, ale dane nie są używane w danej instancji, dane te w ogóle nie zostaną wysłane do klienta, ponieważ instrukcja if jest oceniana po stronie serwera. Oznacza to, że prawidłowo skonstruowany szablon jest bardzo bezpieczną metodą dodawania poufnych danych do stron bez opuszczania ich serwera, chyba że jest to konieczne. To powiedziawszy, użycie szablonów Django nie eliminuje potrzeby przekazywania poufnych informacji w bezpieczny, zaszyfrowany sposób, oznacza to po prostu, że kontrole bezpieczeństwa, takie jak user.is_authenticated mogą bezpiecznie odbywać się w HTML, ponieważ jest on przetwarzany po stronie serwera.

Ta funkcja ma wiele innych przypadków użycia. Na przykład na ogólnej stronie głównej produktu możesz ukryć przyciski „zarejestruj się” i „zaloguj się” i zastąpić je przyciskiem „wyloguj się” dla zalogowanych użytkowników. Innym powszechnym zastosowaniem jest pokazywanie i ukrywanie komunikatów o powodzeniu lub błędach dla operacji takich jak przesyłanie formularzy. Pamiętaj, że generalnie nie ukryjesz całej strony, jeśli użytkownik nie jest zalogowany. Lepszym sposobem zmiany całej strony internetowej na podstawie stanu uwierzytelnienia użytkownika jest obsłużenie jej w odpowiedniej funkcji w views.py .

Filtracja

Częścią pracy widoku jest odpowiednie formatowanie danych dla strony. Aby to osiągnąć, mamy potężne rozszerzenie tagów: filtry. W Django dostępnych jest wiele filtrów do wykonywania czynności, takich jak wyrównywanie tekstu, formatowanie dat i dodawanie liczb. Zasadniczo możesz myśleć o filtrze jako o funkcji stosowanej do zmiennej w tagu. Na przykład chcemy, aby nasze numery wynagrodzeń brzmiały „1 200 000 USD” zamiast „1200 000”. Użyjemy filtra, aby wykonać zadanie w index.html :

 <td>${{ employee.salary|intcomma }}</td>

Znak rury | to filtr, który stosuje polecenie intcomma do zmiennej employee.salary . Znak „$” nie pochodzi z szablonu, dla elementu takiego jak ten, który pojawia się za każdym razem, łatwiej jest po prostu wystawić go poza tag.

Zauważ, że intcomma wymaga, abyśmy umieścili {% load humanize %} na górze naszego index.html i 'django.contrib.humanize', w naszym INSTALLED_APPS w settings.py . Odbywa się to za Ciebie w dostarczonej przykładowej aplikacji.

Wniosek

Renderowanie po stronie serwera z silnikiem Jinja2 zapewnia kluczowe narzędzia do tworzenia czystego, elastycznego i responsywnego kodu front-endu. Rozdzielenie stron na pliki pozwala na komponenty DRY o elastycznym składzie. Tagi zapewniają podstawowe możliwości wyświetlania danych przekazywanych z bazy danych przez funkcje widoku. Właściwe podejście może zwiększyć szybkość, możliwości SEO, bezpieczeństwo i użyteczność witryny i jest kluczowym aspektem programowania w Django i podobnych frameworkach.

Jeśli jeszcze tego nie zrobiłeś, sprawdź przykładową aplikację i spróbuj dodać własne tagi i filtry, korzystając z pełnej listy.

Django Highlights to seria wprowadzająca ważne koncepcje tworzenia stron internetowych w Django. Każdy artykuł jest napisany jako samodzielny przewodnik po aspekcie rozwoju Django, który ma pomóc deweloperom i projektantom front-end w osiągnięciu głębszego zrozumienia „drugiej połowy” bazy kodu. Artykuły te są w większości skonstruowane tak, aby pomóc Ci zrozumieć teorię i konwencję, ale zawierają kilka przykładów kodu, które zostały napisane w Django 3.0.

Poprzednie części z serii:

  • Najważniejsze cechy Django: modele użytkownika i uwierzytelnianie (część 1)
  • Najważniejsze cechy Django: modele, administracja i wykorzystanie relacyjnej bazy danych (część 3)
  • Najważniejsze cechy Django: walka o zasoby statyczne i pliki multimedialne (część 4)