Menu

  • Home
  • Flask Tutorial
  • WebGL
  • Kontakt

Alicja | Theme by Theme in Progress | Proudly powered by WordPress

Alicja & IT
  • Home
  • Flask Tutorial
  • WebGL
  • Kontakt

Aplikacja webowa w Pythonie – Flask – Formularze – #6

January 3, 2017Flask Standard

W szóstym odcinku tutorialu, który masz właśnie przed sobą, przejdziemy do tematu formularzy. Bazę danych już podpięliśmy – pytanie, jak przetwarzać dane wysłane przez naszą aplikację w stronę serwera? Zaraz się dowiesz! Napisaliśmy już skrypt pobierający z bazy wpisy, więc logicznie rzecz biorąc, powinniśmy teraz napisać taki umożliwiający dodanie posta.

Napiszmy formularz!

Na początek – prosty HTML do wyświetlenia naszych inputów. Umieścimy go w pliku database_posts.html, zaraz nad wpisami:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  <h2>Dodaj wpis</h2>
    <div class="row">
      <form class="col s12" action="{{ url_for('database_posts')}}" method="post">
        <div class="row">
          <div class="input-field col s6">
           <input name="tytul" id="tytul" type="text" class="validate">
           <label for="tytul">Tytuł</label>
         </div>
         <div class="input-field col s6">
           <input name="autor" id="autor" type="text" class="validate">
           <label for="autor">Autor</label>
         </div>
          <div class="input-field col s12">
            <textarea id="tresc" name="tresc" class="materialize-textarea"></textarea>
            <label for="tresc">Treść</label>
          </div>
        </div>
        <button class="btn waves-effect waves-light" type="submit" name="action">Zapisz</button>
      </form>
    </div>

Na co należy zwrócić uwagę? Przede wszystkim na tag <form> i to co znajduje się wewnątrz. Akcję skierujemy na funkcję wykonywaną w routingu tej podstrony ( url_for('database_posts')), a do przekazania zawartości wykorzystamy metodę post.

Nad samymi inputami nie będę się rozpisywać – ważne, aby miały konkretne id oraz name. Cała reszta to tak naprawdę sprawa wyglądu (tutaj korzystam z formularzy MaterializeCSS). Pamiętaj tylko, aby uwzględnić button o typie submit :)

Kolejnym krokiem będzie ulepszenie routingu dla database_posts.

Metody, routing, requesty…

Aby móc stronę nie tylko wyświetlić, ale również przesłać do niej dane, będziemy musieli zdefiniować metody. Staną się one drugim parametrem app.route(): @app.route("/wszystkie-posty", methods=['POST', 'GET']). Oprócz dodania POST, musimy również uwzględnić już używane wcześniej (domyślnie) GET.

Kolejnym krokiem, będzie edycja głównej funkcji w routingu. Dodamy do niej warunek, który wykona się jedynie, gdy rozpoznana zostanie metoda POST:

1
2
3
4
    if request.method == 'POST':
        name = request.form['tytul']
        author = request.form['autor']
        content = request.form['tresc']

Pod zmienne name, author i content podstawimy to, co przekazane zostanie z formularzy za pomocą request.form. Następnie wykona się cała magia:

1
2
3
4
5
6
        conn = mysql.connect()
        cursor = conn.cursor()
        to_db = ("", name, content, author)
        cursor.execute("INSERT INTO posty VALUES (%s, %s, %s, %s)", to_db)
        conn.commit()
        cursor.close()

Jak to działa? Na początek definiuję połączenie oraz kursor. Tworzę krotkę zawierającą wszystkie zmienne, które chcę mieć w danym wierszu. Pierwszą pozostawiam pustą – w swojej tabeli zdefiniowałam pole ID jako auto increment, w związku z czym nie muszę się nim przejmować. Linijka z cursor.execute wykona MySQL-owy skrypt, który pozwoli nam dodać wartości do bazy. Ważne jest, aby nie przekazywać parametrów bezpośrednio, ale właśnie poprzez %s i krotkę. Na koniec zacommituję zmiany (inaczej rezultat się nie zapisze) i zamknę kursor.

Całość funkcji database_posts() powinna teraz wyglądać tak:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@app.route("/wszystkie-posty", methods=['POST', 'GET'])
def database_posts():
    if request.method == 'POST':
        name = request.form['tytul']
        author = request.form['autor']
        content = request.form['tresc']
        conn = mysql.connect()
        cursor = conn.cursor()
        to_db = ("", name, content, author)
        cursor.execute("INSERT INTO posty VALUES (%s, %s, %s, %s)", to_db)
        conn.commit()
        cursor.close()
    cursor = mysql.connect().cursor()
    cursor.execute("SELECT * from posty")
    data = cursor.fetchall()
    cursor.close()
    return render_template('database_posts.html', data = data)

Wywołanie wszystkich postów przełożyłam na koniec, aby po wysłaniu formularza nasz nowy wpis również się wyświetlił :) Jak widać, możemy już dodawać posty – co powiecie na usuwanie?

11

Usuwanie postów

Tak jak wcześniej, zaczniemy od templatki. Zazwyczaj chcemy wiedzieć, która operacja się wykonała, dlatego na początku layoutu database_posts.html dodamy sobie miejsce na wiadomość: <p class="red white-text">{{message}}</p>. Tak naprawdę powinna ona wyświetlić się dopiero wtedy, gdy zapytanie do bazy wykona się poprawnie, ale obsługę błędów zostawimy sobie na następny raz.

Aby móc odczytać, czy w metodzie POST przesyłamy formularz dodający nowy wpis, czy raczej chcemy coś usunąć, potrzebujemy zmienić minimalnie przycisk submit dla stworzonej już formatki:

1
  <button class="btn waves-effect waves-light" type="submit" name="action" value="add">Zapisz</button>

Dodamy mu name="action" i value="add" – jak łatwo się domyślić, pozostałe buttony będą mieć value="delete". Nasz wcześniejszy kod do wyświetlenia każdego z artykułów prezentował się tak:

1
2
3
4
5
6
7
      {% for row in data %}
        <article>
          <h3>{{ row[0] }}. {{ row[1] }}</h3>
          <p>{{ row[2] }}</p>
          <p><i>Autor: {{ row[3] }}</i></p>
        </article>
      {% endfor %}

Teraz między treścią a autorem dodamy jeszcze nasz nieduży formularz:

1
2
3
4
5
6
7
8
9
10
11
      {% for row in data %}
        <article>
          <h3>{{ row[0] }}. {{ row[1] }}</h3>
          <p>{{ row[2] }}</p>
          <form class="col s12" action="{{ url_for('database_posts')}}" method="post">
            <input id='{{row[0]}}' type='hidden' value='{{row[0]}}' name='id-delete'>
            <button class="btn waves-effect waves-light red" type="submit" name="action" value="delete">Usuń mnie</button>
          </form>
          <p><i>Autor: {{ row[3] }}</i></p>
        </article>
      {% endfor %}

Oprzemy go na metodzie POST, tak samo jak ten do dodawania wpisu. Ma jednego inputa – ukrytego – którym przekażemy ID wpisu przeznaczonego do usunięcia. Czerwony przycisk wykonuje akcję, którą teraz musimy opisać w views.py. Tak naprawdę zmienia się tylko treść funkcji – oprócz sprawdzenia czy metodą jest POST, musimy jeszcze sprawdzić którą konkretnie akcję użytkownik chce wykonać ( add czy delete) i dopisać skrypt, który będzie potrzebny w przypadku tej drugiej.

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
@app.route("/wszystkie-posty", methods=['POST', 'GET'])
def database_posts():
    message = ""
    if request.method == 'POST':
        if request.form["action"] == "add":
            name = request.form['tytul']
            author = request.form['autor']
            content = request.form['tresc']
            conn = mysql.connect()
            cursor = conn.cursor()
            to_db = ("", name, content, author)
            cursor.execute("INSERT INTO posty VALUES (%s, %s, %s, %s)", to_db)
            conn.commit()
            cursor.close()
            message = "Dodano!"
        if request.form["action"] == "delete":
            id = request.form['id-delete']
            conn = mysql.connect()
            cursor = conn.cursor()
            cursor.execute("DELETE from posty where ID='" + id + "'")
            conn.commit()
            cursor.close()
            message = "Usunięto post numer " + id + "!"
    cursor = mysql.connect().cursor()
    cursor.execute("SELECT * from posty")
    data = cursor.fetchall()
    cursor.close()
    return render_template('database_posts.html', data = data, message = message)

Na początku definiujemy jeszcze pustą wiadomość, którą przy dodawaniu wpisu wypełniamy treścią “Dodano!”, a w przypadku usunięcia – ID postu, którego się pozbyliśmy. Struktura skryptu na usuwanie jest podobna do tego dodawania – definiujemy połączenie, kursor, wykonujemy zapytanie i commitujemy rezultat. Posty pobierają się później, dlatego usunięty nie zostanie już wyświetlony.

Jak zauważysz w aplikacji i w bazie danych – wszystko działa jak trzeba :)

12

Flask:

  • Aplikacja webowa w Pythonie – Flask – Hello World – #1
  • Aplikacja webowa w Pythonie – Flask – Template’y – #2
  • Aplikacja webowa w Pythonie – Flask na Windowsie
  • Aplikacja webowa w Pythonie – Flask – Routing – #3
  • Aplikacja webowa w Pythonie – Flask – Static Files – #4
  • Aplikacja webowa w Pythonie – Flask – Łączenie z bazą danych – #5
  • Aplikacja webowa w Pythonie – Flask – Formularze – #6
  • Aplikacja webowa w Pythonie – Flask – Struktura większej aplikacji, czyli Blueprint – #7
  • Aplikacja webowa w Pythonie – Flask – Logowanie – #8
  • Aplikacja webowa w Pythonie – Flask – Obsługa błędów – #9
  • Aplikacja webowa w Pythonie – Flask – Migracja z localhosta na serwer, czyli co może pójść nie tak z bazą danych – #10
  • Aplikacja webowa w Pythonie – Flask – Deploy na Azure’a – #11

Facebook

Kontakt

kontakt[at]alicja.it

Kategorie

  • Flask (12)
  • Luźne (2)
  • PyGame (5)
  • Relacje z wydarzeń (3)
  • WebGL (3)