Blog JSystems - z miłości do programowania

Framework Flask - tworzenie aplikacji webowej i wyświetlanie danych



W tym rozdziale, podobnie jak i innych rozdziałach dotyczących aplikacji webowych w Pythonie, będę używał Pycharm w wersji Professional ze względu na wsparcie dla Flaska i Django. Można pobrać wersję trial na potrzeby nauki, ale do profesjonalnej pracy proponuję faktycznie wykupić subskrypcję. Wprawdzie kosztuje ona niecałe 200zł miesięcznie, ale przyspiesza pracę tak bardzo, że moim zdaniem warto. Inna sprawa – profesjonalny rysownik też nie używa produkcyjnie darmowych ołówków z Ikei.


Tworzenie projektu i mapowanie pierwszego adresu


Jeśli wybrałeś proponowane przeze mnie oprogramowanie, to tworząc nowy projekt powinieneś mieć taki mniej więcej widok:


40.png (598×351)


W zasadzie jedyne co trzeba tu zrobić to nadać nazwę projektowi – ja nadałem nazwę „flask_mapet”. W projekcie powinien zostać stworzony plik „app.py” który będzie naszym głównym plikiem uruchomieniowym. Jego zawartość poniżej:


42.png (433×334)


Co oznaczają poszczególne elementy? Linia 1 – importujemy klasę „Flask” z modułu „flask” którą będziemy wykorzystywać za chwilę. Linia 3 – konieczne jest stworzenie instancji obiektu modułu Flask, ponieważ później się do niego odnosimy na przykład uruchamiając apkę (w linii 12) czy w @app.route (w linii 6). Konstruktor oczekuje podania nazwy aplikacji jako parametru.


Linie 6-8. W linii 6 używamy dekoratora pozwalającego nam zadeklarować mapowany przez funkcję url (czyli w reakcji na jaki adres http w ramach naszej aplikacji ma odpowiadać dana funkcja).  Wartość argumentu: „/” oznacza że poniższa funkcja będzie mapować stronę główną. Funkcja nie przyjmuje żadnych argumentów. Zwraca za to w linii 8 kod który ma zostać wyświetlony w reakcji na wejście na url mapowany przez funkcję. 


Linie 11-12. To jest kod zapewniający że serwer jest uruchamiany kiedy odpalamy plik app.py będący głównym skryptem aplikacji. W zasadzie chodzi o wywołanie funkcji „run()” na obiekcie instancji obiektu modułu Flask. Warunek służy temu, by nie następowały kolejne próby uruchamiania w sytuacji gdyby np. ten moduł był importowany.  Jeśli to skrypt „app.py” będzie uruchamiany, to w „__name__” dostaniemy „__main__”.


Aplikację możemy uruchomić z konsoli wywołując skrypt jak każdy inny:


43.png (602×140)


Flask ma wbudowany własny serwer http, będzie on domyslnie chodził na porcie 5000. Po wejściu przez przeglądarkę na ten port powinniśmy zobaczyć wynik działania funkcji „hello_world” która obsługuje główną stronę aplikacji:


44.png (281×108)


Konfiguracja portu nasłuchu serwera i automatyczna implementacja zmian.


Odrobinę zmodyfikuję teraz skrypt „app.py”:


45.png (412×115)


Dodałem argumenty do wywołania funkcji run. Parametr „port” pozwala ustawić na którym porcie ma nasłuchiwać serwer. Zmieniam na 80 by móc wywoływać aplikację  po prostu „localhost” zamiast „localhost:5000”.  Parametr „debug” powoduje, że zmiany na plikach z kodem będą od razu aktualizowane na serwerze, bez potrzeby restartu.  Poniżej przykład takiego przeładowania. To jest zrzut logów. Dodałem do skryptu enter, zapisałem i aplikacja została przeładowana:


46.png (603×290)


 


Kod i szablony kodu HTML


Funkcja obsługująca mapowanie adresu może zamiast zwykłego tekstu, zwracać również kod HTML:


47.png (387×186)


Efekt działania:


48.png (262×125)


Na dłuższą metę, lub przy większej ilości kodu takie działanie będzie po prostu bardzo niewygodne. Wyobraź sobie 1000 linijkową stronę generowaną w ten sposób. Biorąc jeszcze pod uwagę że zwykle będą jakieś elementy wspólne na wielu podstronach, a podmieniana będzie tylko jakaś nieduża część widoku, to jest to całkowicie pozbawione sensu. Co więc możemy zrobić? Wykorzystać szablon HTML:


49.png (472×340)


Wykorzystamy funkcję „render_template”(linia 12) którą trzeba uprzednio zaimportować (linia 1). Funkcja jako argument będzie przyjmowała nazwę pliku który ma zostać pokazany. Co ważne, plik ten musi znajdować się w podkatalogu „templates”, ponieważ Flask tam właśnie będzie go szukał.


50.png (352×167)


Efekt działania:


51.png (293×116)


Przekazywanie danych do widoku i jinja2


Wszystko pięknie, ale widok ten jest statyczny. Jak zatem przekazać dane do widoku? Kod z poprzedniego przykładu nieco przerobiłem. Do funkcji „render_template” poza samą nazwą widoku, przekazuję też dwie zmienne: imię i nazwisko. Pod takimi nazwami zostaną do widoku przekazane dane. Typ danych nie ma tu wielkiego znaczenia, jeśli okazałoby się że jest to kolekcja, różnica będzie tylko w sposobie wyświetlania.


52.png (597×89)


Mała przeróbka po stronie szablonu HTML:


53.png (382×192)


Pomiędzy podwójnymi klamrami umieszczamy nazwę pod jaką przekazaliśmy dane do widoku w argumentach funkcji „render_template”. Efekt działania:


54.png (318×183)


To są pojedyncze zmienne. Jak jednak przekazać listę, a następnie przeiterować po niej na poziomie widoku? W pierwszej kolejności modyfikuję funkcję by przekazać dane:


55.png (598×82)


Utworzyłem sobie listę krajów którą przekazałem wraz z imieniem i nazwiskiem do widoku. Po stronie widoku korzystam ze składni jinja2:


56.png (350×121)


Wynik działania:


57.png (291×282)


Zaraz, zaraz… jinja? Jinja2 to silnik szablonów dla Pythona. Taki powiedzmy mikro język skryptowy który umożliwia nam zawieranie pewnej logiki biznesowej po stronie widoku. Daje nam możliwość wyświetlania danych przekazanych do render_template, iterowanie po listach na poziomie widoków, warunkowe wykonywanie czynności, a także kilka innych możliwości które omówimy nieco później.


Sama Jinja2 to osobna biblioteka którą musicie dodać do projektu wykonując „pip install jinja2”. Jeśli korzystacie z Pycharm Professional, nie musicie się o to marwić bo IDE zadbało już o to za Was. Gdyby Pycharm podkreślał Ci składnię jinja2, upewnij się że Jinja2 znajduje się w venv projektu:


59.png (319×392)


Wracając jednak do składni:


60.png (350×121)


Iterujemy po liście o nazwie „kraje”, ponieważ pod taką nazwą została przekazana nasza lista.


61.png (598×82)


Odwołujemy się potem do tej listy w linii 7 naszego kodu HTML we fragmencie „for k in kraje”. Klamry i znaczniki „%” są elementem tej składni. Fragment „for k in ….” to deklaracja w jaki sposób będę się odnosił w pętli do elementów po których iteruję. Wewnątrz pętli posługuję się notacją taką jak przy wyświetleniu zwykłych zmiennych „{{ k }}”, z tą różnicą że odnoszę się do lokalnego „k”. Nie zapominamy też o „{% endfor %} który zamyka pętlę. Efekt działania:


62.png (312×277)


Jinja2 umożliwia też warunkowe wykonanie. Poniżej przykład pewnego wariantu naszej aplikacji. Postanowiłem że na liście „Polska” ma być pogrubiona:


63.png (429×211)


We wnętrzu naszej pętli umieściłem jeszcze blok warunkowy. Jeśli przetwarzany element będzie równy ciągowi tekstowemu „Polska”, wyświetlany element będzie dodatkowo otoczony takami „<b>” i „</b>”. Efekt działania:


64.png (322×287)


Taka instrukcja warunkowa może przyjmować oczywiście więcej wariantów, podobnie jak w czysto pythonowym ifie. W poniższym przykładzie Rosja zostanie podkreślona:


65.png (403×259)


Efekt działania:


66.png (192×115)


 


 

Przyjdź do nas na szkolenie z języka Python! Mamy szereg szkoleń w ofercie, od podstawowych po aplikacje webowe z użyciem Django, analizę danych, tesowanie, machine learning i wiele innych.
Sprawdź dostępne szkolenia Python
Zapisz się do newslettera aby otrzymywać najnowsze świeżynki pojawiające się na blogu!