7.1. Quiz¶
Realizacja aplikacji internetowej Quiz w oparciu o framework Flask 0.12.x. Na stronie wyświetlamy pytania, użytkownik zaznacza poprawne odpowiedzi, przesyła je na serwer i otrzymuje informację o wynikach.
7.1.1. Projekt i aplikacja¶
W katalogu użytkownika tworzymy nowy katalog aplikacji o nazwie quiz
:
~$ mkdir quiz; cd quiz;
Utworzymy szkielet aplikacji Flask, co pozwoli na uruchomienie testowego serwera www,
umożliwiającego wygodne rozwijanie kodu. W nowym pliku o nazwie quiz.py
wpisujemy poniższy kod i zapisujemy w katalogu aplikacji.
1 2 3 4 5 6 7 8 9 | # -*- coding: utf-8 -*-
# quiz/quiz.py
from flask import Flask
app = Flask(__name__)
if __name__ == '__main__':
app.run(debug=True)
|
Serwer uruchamiamy komendą:
~/quiz$ python3 quiz.py

Domyślnie serwer uruchamia się pod adresem http://127.0.0.1:5000. Po wpisaniu go do przeglądarki internetowej otrzymamy kod odpowiedzi HTTP 404, tj. błąd “nie znaleziono”, co wynika z faktu, że nasza aplikacja nie ma jeszcze zdefiniowanego żadnego widoku dla tego adresu.

Wskazówka
Działanie serwera w terminalu zatrzymujemy skrótem CTRL+C
.
7.1.2. Strona główna¶
Jeżeli chcemy, aby nasza aplikacja zwracała użytkownikowi jakieś strony www, tworzymy tzw. widok. Jest to funkcja Pythona powiązana z określonymi adresami URL za pomocą tzw. dekoratorów. Widoki pozwalają nam obsługiwać podstawowe żądania protokołu HTTP, czyli: GET, wysyłane przez przeglądarkę, kiedy użytkownik chce zobaczyć stronę, i POST, kiedy użytkownik przesyła dane na serwer za pomocą formularza.
W odpowiedzi aplikacja może odsyłać różne dane. Najczęściej będą to znaczniki HTML oraz treści, np. wyniki quizu. Flask ułatwia tworzenie takich dokumentów za pomocą szablonów.
W pliku quiz.py
umieszczamy kod:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | # -*- coding: utf-8 -*-
# quiz/quiz.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return 'Cześć, tu Python!'
if __name__ == '__main__':
app.run(debug=True)
|
Widok (czyli funkcja) index()
powiązany jest z adresem głównym (/)
za pomocą dekoratora @app.route('/')
. Funkcja zostanie wykonana w odpowiedzi
na żądanie GET wysłane przez przeglądarkę po wpisaniu i zatwierdzeniu przez
użytkownika adresu serwera.
Najprostszą odpowiedzią jest zwrócenie jakiegoś tekstu: return 'Cześć, tu Python!'
.

Zazwyczaj będziemy prezentować bardziej skomplikowane dane, w dodatku
sformatowane wizualnie. Potrzebujemy szablonów. Będziemy je zapisywać
w katalogu quiz/templates
, który utworzymy np. poleceniem:
~/quiz$ mkdir templates
Następnie w nowym pliku templates/index.html
umieszczamy kod:
1 2 3 4 5 6 7 8 9 | <!-- quiz/templates/index.html -->
<html>
<head>
<title>Quiz Python</title>
</head>
<body>
<h1>Quiz Python</h1>
</body>
</html>
|
Na koniec modyfikujemy funkcję index()
w pliku quiz.py
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # -*- coding: utf-8 -*-
# quiz/quiz.py
from flask import Flask
from flask import render_template
app = Flask(__name__)
@app.route('/')
def index():
# return 'Cześć, tu Python!'
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
|
Do renderowania szablonu (zob: renderowanie szablonu) używamy
funkcji render_template('index.html')
, która jako argument przyjmuje
nazwę pliku szablonu. Pod adresem http://127.0.0.1:5000 strony głównej,
zobaczymy dokument HTML:

7.1.3. Pytania i odpowiedzi¶
Dane aplikacji, a więc pytania i odpowiedzi, umieścimy w liście
DANE
w postaci słowników zawierających: treść pytania,
listę możliwych odpowiedzi oraz poprawną odpowiedź.
Modyfikujemy plik quiz.py
. Podany kod wstawiamy po inicjacji zmiennej
app
, ale przed dekoratorem widoku index()
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | # -*- coding: utf-8 -*-
# quiz/quiz.py
from flask import Flask
from flask import render_template
app = Flask(__name__)
# konfiguracja aplikacji
app.config.update(dict(
SECRET_KEY='bradzosekretnawartosc',
))
# lista pytań
DANE = [{
'pytanie': 'Stolica Hiszpani, to:', # pytanie
'odpowiedzi': ['Madryt', 'Warszawa', 'Barcelona'], # możliwe odpowiedzi
'odpok': 'Madryt'}, # poprawna odpowiedź
{
'pytanie': 'Objętość sześcianu o boku 6 cm, wynosi:',
'odpowiedzi': ['36', '216', '18'],
'odpok': '216'},
{
'pytanie': 'Symbol pierwiastka Helu, to:',
'odpowiedzi': ['Fe', 'H', 'He'],
'odpok': 'He'},
]
@app.route('/')
def index():
# return 'Cześć, tu Python!'
return render_template('index.html', pytania=DANE)
if __name__ == '__main__':
app.run(debug=True)
|
W konfiguracji aplikacji dodaliśmy sekretny klucz, wykorzystywany podczas korzystania z sesji (zob sesja).
Dane aplikacji
Każda aplikacja korzysta z jakiegoś źródła danych. W najprostszym przypadku
dane zawarte są w samej aplikacji. Dodaliśmy więc listę słowników DANE
,
którą przekazujemy dalej jako drugi argument do funkcji render_template()
.
Dzięki temu będziemy mogli odczytać je w szablonie w zmiennej pytania
.
Do szablonu index.html
wstawiamy poniższy kod po nagłówku <h1>
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <!-- formularz z quizem -->
<form method="POST">
<!-- przeglądamy listę pytań -->
{% for p in pytania %}
<p>
<!-- wyświetlamy treść pytania -->
{{ p.pytanie }}
<br>
<!-- zapamiętujemy numer pytania licząc od zera -->
{% set pnr = loop.index0 %}
<!-- przeglądamy odpowiedzi dla danego pytania -->
{% for o in p.odpowiedzi %}
<label>
<!-- odpowiedzi wyświetlamy jako pole typu radio -->
<input type="radio" value="{{ o }}" name="{{ pnr }}">
{{ o }}
</label>
<br>
{% endfor %}
</p>
{% endfor %}
<!-- przycisk wysyłający wypełniony formularz -->
<button type="submit">Sprawdź odpowiedzi</button>
</form>
|
Znaczniki HTML w powyższym kodzie tworzą formularz (<form>
).
Natomiast tagi, czyli polecenia dostępne w szablonach, pozwalają
wypełnić go danymi.
{% instrukcja %}
– tak wstawiamy instrukcje sterujące;{{ zmienna }}
– tak wstawiamy wartości zmiennych przekazanych do szablonu.
Z przekazanej do szablonu listy pytań, czyli ze zmiennej pytania
odczytujemy
w pętli {% for p in pytania %}
kolejne słowniki; dalej tworzymy elementy formularza,
czyli wyświetlamy treść pytania {{ p.pytanie }}
, a w kolejnej pętli
{% for o in p.odpowiedz %}
odpowiedzi w postaci grupy opcji typu radio.
Każda grupa odpowiedzi nazywana jest dla odróżnienia numerem pytania liczonym od 0.
Odpowiednią zmienną ustawiamy w instrukcji {% set pnr = loop.index0 %}
,
a używamy w postaci name="{{ pnr }}"
. Dzięki temu przyporządkujemy
przesłane odpowiedzi do kolejnych pytań podczas ich sprawdzania.
Po ponownym uruchomieniu serwera powinniśmy otrzymać następującą stronę internetową:

7.1.4. Oceniamy odpowiedzi¶
Mechanizm sprawdzana liczby poprawnych odpowiedzi umieścimy w funkcji index()
.
Na początku pliku quiz.py
dodajemy potrzebne importy:
6 | from flask import request, redirect, url_for, flash
|
– i uzupełniamy kod funkcji index()
:
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | @app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
punkty = 0
odpowiedzi = request.form
for pnr, odp in odpowiedzi.items():
if odp == DANE[int(pnr)]['odpok']:
punkty += 1
flash('Liczba poprawnych odpowiedzi, to: {0}'.format(punkty))
return redirect(url_for('index'))
# return 'Cześć, tu Python!'
return render_template('index.html', pytania=DANE)
|
methods=['GET', 'POST']
– lista zawiera obsługiwane typy żądań, chcemy obsługiwać zarówno żądania GET (odesłanie żądanej strony), jak i POST (ocena przesłanych odpowiedzi i odesłanie wyniku);if request.method == 'POST':
– instrukcja warunkowa, która wykrywa żądania POST i wykonuje blok kodu zliczający poprawne odpowiedzi;odpowiedzi = request.form
– przesyłane dane z formularza pobieramy z obiekturequest
i zapisujemy w zmiennej odpowiedzi;for pnr, odp in odpowiedzi.items()
– w pętli odczytujemy kolejne pary danych, czyli numer pytania i udzieloną odpowiedź;if odp == DANE[int(pnr)]['odpok']:
– sprawdzamy, czy nadesłana odpowiedź jest zgodna z poprawną, którą wydobywamy z listy pytań.
Zwróćmy uwagę, że wartości zmiennej pnr
, czyli numery pytań liczone od zera,
ustaliliśmy wcześniej w szablonie.
Jeżeli nadesłana odpowiedź jest poprawna, doliczamy punkt (punkty += 1
).
Informacje o wyniku przekazujemy użytkownikowi za pomocą funkcji flash()
,
która korzysta z tzw. sesji HTTP (wykorzystującej SECRET_KEY
),
czyli mechanizmu pozwalającego na rozróżnianie żądań przychodzących
w tym samym czasie od różnych użytkowników.
W szablonie index.html
między znacznikami <h1>
i <form>
wstawiamy instrukcje wyświetlające wynik:
9 10 11 12 13 14 | <!-- wyświetlamy komunikaty z funkcji flash -->
<p>
{% for message in get_flashed_messages() %}
{{ message }}
{% endfor %}
</p>
|
Po uruchomieniu aplikacji, zaznaczeniu odpowiedzi i ich przesłaniu otrzymujemy ocenę.

7.1.5. Materiały¶
Źródła:
Materiały Python 101
udostępniane przez
Centrum Edukacji Obywatelskiej na licencji
Creative Commons Uznanie autorstwa-Na tych samych warunkach 4.0 Międzynarodowa.
Utworzony: | 2022-05-22 o 19:52 w Sphinx 1.5.3 |
---|---|
Autorzy: | Patrz plik “Autorzy” |