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# -*- coding: utf-8 -*-
2# quiz/quiz.py
3
4from flask import Flask
5
6app = Flask(__name__)
7
8if __name__ == '__main__':
9 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# -*- coding: utf-8 -*-
2# quiz/quiz.py
3
4from flask import Flask
5
6app = Flask(__name__)
7
8
9@app.route('/')
10def index():
11 return 'Cześć, tu Python!'
12
13
14if __name__ == '__main__':
15 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<!-- quiz/templates/index.html -->
2<html>
3 <head>
4 <title>Quiz Python</title>
5 </head>
6<body>
7 <h1>Quiz Python</h1>
8</body>
9</html>
Na koniec modyfikujemy funkcję index()
w pliku quiz.py
:
1# -*- coding: utf-8 -*-
2# quiz/quiz.py
3
4from flask import Flask
5from flask import render_template
6
7app = Flask(__name__)
8
9
10@app.route('/')
11def index():
12 # return 'Cześć, tu Python!'
13 return render_template('index.html')
14
15
16if __name__ == '__main__':
17 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# -*- coding: utf-8 -*-
2# quiz/quiz.py
3
4from flask import Flask
5from flask import render_template
6
7app = Flask(__name__)
8
9# konfiguracja aplikacji
10app.config.update(dict(
11 SECRET_KEY='bradzosekretnawartosc',
12))
13
14# lista pytań
15DANE = [{
16 'pytanie': 'Stolica Hiszpani, to:', # pytanie
17 'odpowiedzi': ['Madryt', 'Warszawa', 'Barcelona'], # możliwe odpowiedzi
18 'odpok': 'Madryt'}, # poprawna odpowiedź
19 {
20 'pytanie': 'Objętość sześcianu o boku 6 cm, wynosi:',
21 'odpowiedzi': ['36', '216', '18'],
22 'odpok': '216'},
23 {
24 'pytanie': 'Symbol pierwiastka Helu, to:',
25 'odpowiedzi': ['Fe', 'H', 'He'],
26 'odpok': 'He'},
27]
28
29
30@app.route('/')
31def index():
32 # return 'Cześć, tu Python!'
33 return render_template('index.html', pytania=DANE)
34
35
36if __name__ == '__main__':
37 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 <!-- formularz z quizem -->
2 <form method="POST">
3 <!-- przeglądamy listę pytań -->
4 {% for p in pytania %}
5 <p>
6 <!-- wyświetlamy treść pytania -->
7 {{ p.pytanie }}
8 <br>
9 <!-- zapamiętujemy numer pytania licząc od zera -->
10 {% set pnr = loop.index0 %}
11 <!-- przeglądamy odpowiedzi dla danego pytania -->
12 {% for o in p.odpowiedzi %}
13 <label>
14 <!-- odpowiedzi wyświetlamy jako pole typu radio -->
15 <input type="radio" value="{{ o }}" name="{{ pnr }}">
16 {{ o }}
17 </label>
18 <br>
19 {% endfor %}
20 </p>
21 {% endfor %}
22
23 <!-- przycisk wysyłający wypełniony formularz -->
24 <button type="submit">Sprawdź odpowiedzi</button>
25 </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:
6from flask import request, redirect, url_for, flash
– i uzupełniamy kod funkcji index()
:
30@app.route('/', methods=['GET', 'POST'])
31def index():
32
33 if request.method == 'POST':
34 punkty = 0
35 odpowiedzi = request.form
36
37 for pnr, odp in odpowiedzi.items():
38 if odp == DANE[int(pnr)]['odpok']:
39 punkty += 1
40
41 flash('Liczba poprawnych odpowiedzi, to: {0}'.format(punkty))
42 return redirect(url_for('index'))
43
44 # return 'Cześć, tu Python!'
45 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 <!-- wyświetlamy komunikaty z funkcji flash -->
10 <p>
11 {% for message in get_flashed_messages() %}
12 {{ message }}
13 {% endfor %}
14 </p>
Po uruchomieniu aplikacji, zaznaczeniu odpowiedzi i ich przesłaniu otrzymujemy ocenę.

7.1.5. Materiały
Źródła:
Instrukcja w pdf dla Pythona 2
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:
2025-04-12 o 10:21 w Sphinx 7.3.7
- Autorzy: