Kihagyás

Python webes frontend alkalmazás

Az alábbi anyagban feltételezzük, hogy az alábbi tananyaghoz tartozó backend anyagrész ismerete rendelkezésre áll, annak szakmai vizsgafeladata elkészült és megfelelően működik.

Környezet előkészítése

Először is biztosítani kell, hogy telepítve legyen a Flask és a Requests a Python környezetben. Ezt pip használatával teheted meg:

Csomagtelepítés pip segítségével
pip install flask requests

Minden esetben 3 lépésből áll a frontend alkalmazás elkészítése

  1. Route definíció: Az útvonalak meghatározása, amelyekre a Flask alkalmazás reagál.
  2. HTML sablon: Az HTML oldalak megjelenítésére szolgáló sablonok elkészítése.
  3. Alkalmazás futtatása: Az alkalmazás futtatása a Flask beépített szerverén.

Adatlekérés bejárással

Az alábbi példában egy egyszerű Flask alkalmazást fogunk létrehozni, amely egy API hívást fog végrehajtani a backend szerverhez, és megjeleníti a kapott adatokat egy HTML oldalon.

Route definíció

Hozz létre egy app.py nevű fájlt a projekt könyvtárban, és írd bele a következő kódot. Ez a fájl tartalmazza a Flask alkalmazás logikáját, beleértve az API hívásokat és a route definíciókat. A route definíciók segítségével meghatározhatjuk, hogy a Flask alkalmazás mely URL-ekre reagáljon.

from flask import Flask, jsonify, render_template
import requests

app = Flask(__name__)


@app.route('/')
def home():
    response = requests.get("http://127.0.0.1:5000/api/flowers") # Backend API hívás
    flowers = response.json() # API válasz JSON formátumban
    return render_template('index.html', flowers=flowers) # HTML sablon megjelenítése


if __name__ == '__main__':
    app.run(debug=True, port=5001)

Figyelmeztetés

Nagyon fontos, hogy a frontend Flask alkalmazást másik portra kell állítani mint a backend Flask alkalmazást! Ez esetben a frontend alkalmazás a 5001-es porton fog futni, míg a backend alkalmazás a 5000-es porton, így a teszteket a 5001-es porton érheted el a böngésződön keresztül.

HTML sablon

Az előző kódrészletben a render_template függvény segítségével egy HTML sablont jelenítünk meg a böngészőben, amely a virágok adatait tartalmazza. Hozz létre egy templates mappát a projekt könyvtárban, és benne egy index.html fájlt az alábbi tartalommal:

Projekt felépítése
FlaskApp/
├── app.py          # A Flask alkalmazás forráskódja
├── templates/      # Mappa a HTML sablonoknak
   └── index.html  # A HTML sablon, ami megjeleníti a virágokat
└── venv/           # Python virtuális környezet (opcionális, de ajánlott)

A backend egy API hívást fog végrehajtani a virágok adatainak lekérésére, és ezeket az adatokat a frontendnek kell megjelenítenie a weboldalon.

Az alábbi HTML sablon ezt a feladatot látja el:

index.html
<!DOCTYPE html>
<html lang="hu">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Virág katalógus</title>
</head>
<body>
    <h1>Virág katalógus</h1>
    <table border="1">
        <tr>
            <th>ID</th>
            <th>Név</th>
            <th>Leírás</th>
        </tr>
        {% for flower in flowers %}
        <tr>
            <td>{{ flower.id }}</td>
            <td>{{ flower.nev }}</td>
            <td>{{ flower.leiras }}</td>
        </tr>
        {% endfor %}
    </table>
</body>
</html>

Ez a HTML sablon egy egyszerű táblázatot jelenít meg, amely a szerverről kapott virágadatokat tartalmazza. A {% for flower in flowers %} sor a Jinja2 template motor segítségével iterál végig a virágok listáján, amit a Flask szerver küld a sablonnak.

Alkalmazás futtatása

Fájlok és mappák részletezése:

  • app.py: Ez a fő Python fájl, amely tartalmazza a Flask szerver logikáját, beleértve az API hívásokat és a route definíciókat.
  • templates/: Egy mappa, amely tartalmazza az összes Jinja2 template-et, amelyeket a Flask alkalmazás használ. Itt található az index.html, amely a böngészőben megjelenített oldal szerkezetét tartalmazza.
  • index.html: A HTML sablon, amely leírja, hogy hogyan jelenjenek meg a virágok adatai egy táblázatban a weboldalon.
  • venv/: Egy opcionális virtuális környezet mappa, amit a Python projektek izolálására használhatunk. Ez tartalmazza a projekt függőségeit, így más projektek nem zavarják be egymást.

Futtasd az app.py fájlt. Ez elindítja a Flask szervert, amely elérhető lesz a http://127.0.0.1:5001/ címen a böngésződben. A kezdőlap automatikusan megjeleníti a virágok adatait egy táblázatban.

Flask alkalmazás adatbeszúrással

Az előzőekben megnéztük, hogy hogyan lehet egy egyszerű GET kérést küldeni a Flask alkalmazásunknak és megjeleníteni a tartalmat. Most megnézzük, hogy hogyan lehet POST kérést küldeni, például egy űrlap elküldésekor.

Backend CORS

Figyelmeztetés

Ezt a lépést csak akkor kell elvégezni, ha saját backend szervert futtatunk!

Mindenek előtt biztosítani kell, hogy a backend szerver engedélyezze a frontend szerverről érkező POST kéréseket. Ehhez a backend szerveren be kell állítani a CORS (Cross-Origin Resource Sharing) engedélyezését.

Ennek lépéseit az alábbiak, amelyet a backenden projekten kell elvégezned:

  1. Telepítsd a flask-cors csomagot a backend projekt virtuális környezetében:

    Csomagtelepítés pip segítségével
    pip install flask-cors
    
  2. Importáld a CORS osztályt a flask_cors modulból a app.py fájlban:

    from flask_cors import CORS
    
  3. Hozd létre a CORS objektumot a Flask alkalmazásban, és engedélyezd a CORS-t a frontend szerver számára:

    app = Flask(__name__)
    CORS(app)
    

Figyelmeztetés

A fenti lépéseket a backend alkalmazásban kell elvégezned!

Példa kód a CORS engedélyezésére a Flask alkalmazásban

1
2
3
4
5
6
7
8
from flask import Flask, jsonify, request
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

if __name__ == '__main__':
    app.run(debug=True)

Route definíció

Egészítsük ki az app.py fájlt a következő módon, hogy elérhető legyen az új oldal és a hozzá tartozó route:

from flask import Flask, jsonify, render_template
import requests

app = Flask(__name__)

@app.route('/')
def home():
    response = requests.get("http://127.0.0.1:5000/api/flowers")
    flowers = response.json()
    return render_template('index.html', flowers=flowers)

@app.route('/insert')
def insert():
    return render_template('insert.html')

if __name__ == '__main__':
    app.run(debug=True, port=5001)

HTML űrlap

Első lépésként azt kell tudnunk, hogy a backend milyen formátumban várja a POST kérést. Ezt a backend dokumentációjából kell megtudnunk. A legtöbb esetben JSON formátumú adatokat vár a backend, de lehet, hogy más formátumot is elfogad.

Példa JSON formátumú adatra

1
2
3
4
5
6
7
8
{
    "nev": "Rózsa",
    "kategoria": 1,
    "leiras": "A rózsa a rózsafélék (Rosaceae) családjába tartozó növények közös neve.",
    "keszlet": 10,
    "ar": 1000,
    "kepUrl": "https://example.com/roza.jpg"
}

Hozz létre egy új HTML fájlt a templates mappában insert.html néven, amely tartalmazza az űrlapot a virágok felvételére:

inser.html
<!DOCTYPE html>
<html lang="hu">
<head>
    <meta charset="UTF-8">
    <title>Új Virág Felvétele</title>
</head>
<body>
    <h1>Új Virág Felvétele</h1>
    <form id="flowerForm">
        <label for="nev">Virág neve:</label>
        <input type="text" id="nev" name="nev" required><br><br>

        <label for="kategoria">Kategória ID:</label>
        <input type="number" id="kategoria" name="kategoria" required><br><br>

        <label for="leiras">Leírás:</label>
        <textarea id="leiras" name="leiras" required></textarea><br><br>

        <label for="keszlet">Készlet:</label>
        <input type="number" id="keszlet" name="keszlet" required><br><br>

        <label for="ar">Ár:</label>
        <input type="text" id="ar" name="ar" required><br><br>

        <label for="kepUrl">Kép URL:</label>
        <input type="text" id="kepUrl" name="kepUrl"><br><br>

        <button type="submit">Virág Hozzáadása</button>
    </form>
</body>
</html>

Probléma

A fenti kódrészlettel egyetlen probléma van, hogy nem fog megfelelően működni. Ennek oka, hogy A HTML űrlapok általában application/x-www-form-urlencoded vagy multipart/form-data formátumban küldik az adatokat, ha standard form elemet használunk. Ahhoz, hogy JSON formátumban küldj adatot egy HTML űrlapból, külön JavaScript kódra lesz szükség, ami összeállítja a JSON objektumot és elküldi egy AJAX kérés segítségével.

inser.html
<!DOCTYPE html>
<html lang="hu">
<head>
    <meta charset="UTF-8">
    <title>Új Virág Felvétele</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>
    <h1>Új Virág Felvétele</h1>
    <form id="flowerForm">
        <label for="nev">Virág neve:</label>
        <input type="text" id="nev" name="nev" required><br><br>

        <label for="kategoria">Kategória ID:</label>
        <input type="number" id="kategoria" name="kategoria" required><br><br>

        <label for="leiras">Leírás:</label>
        <textarea id="leiras" name="leiras" required></textarea><br><br>

        <label for="keszlet">Készlet:</label>
        <input type="number" id="keszlet" name="keszlet" required><br><br>

        <label for="ar">Ár:</label>
        <input type="text" id="ar" name="ar" required><br><br>

        <label for="kepUrl">Kép URL:</label>
        <input type="text" id="kepUrl" name="kepUrl"><br><br>

        <button type="submit">Virág Hozzáadása</button>
    </form>

    <script>
        $(document).ready(function() { //(1)
            $('#flowerForm').on('submit', function(e) { //(2)
                e.preventDefault(); //(3)
                var formData = { //(4)
                    "nev": $('#nev').val(), //(5)
                    "kategoria": parseInt($('#kategoria').val()), //(6)
                    "leiras": $('#leiras').val(), //(7)
                    "keszlet": parseInt($('#keszlet').val()), //(8)
                    "ar": parseFloat($('#ar').val()), //(9)
                    "kepUrl": $('#kepUrl').val() //(10)
                };
                $.ajax({ //(11)
                    url: 'http://127.0.0.1:5000/api/flowers', //(12)
                    type: 'POST', //(13)
                    contentType: 'application/json', //(14)
                    data: JSON.stringify(formData), //(15)
                    success: function(result) { //(16)
                        alert('Virág sikeresen hozzáadva!'); //(17)
                        window.location.reload(); //(18)
                    },
                    error: function(xhr, status, error) { //(19)
                        alert('Hiba történt: ' + xhr.responseText); //(20)
                    }
                });
            });
        });
    </script>
</body>
</html>
  1. Dokumentum betöltése után futtatandó: A jQuery ready függvényének használata biztosítja, hogy a dokumentum teljes betöltése után fut le a kód.
  2. Form beküldés figyelése: A jQuery on függvénye az űrlap beküldési eseményére (submit) figyel.
  3. Alapértelmezett művelet megakadályozása: Megakadályozza az űrlap automatikus beküldését, lehetővé téve az adatok JavaScript általi kezelését.
  4. Adatobjektum létrehozása: Egy objektum, amely tárolja az űrlapról származó adatokat.
  5. Név mező értéke: Az űrlapon található nev mező értékének lekérése.
  6. Kategória ID értéke: A kategoria mező értékének egész számmá konvertálása.
  7. Leírás mező értéke: A leiras mező szövegének lekérése.
  8. Készlet mező értéke: A keszlet mező értékének egész számmá konvertálása.
  9. Ár mező értéke: Az ar mező értékének lebegőpontos számmá konvertálása.
  10. Kép URL mező értéke: A kepUrl mező szövegének lekérése.
  11. AJAX kérés indítása: Egy AJAX kérés küldése a szervernek.
  12. AJAX kérés URL-je: Az API URL-je, ahová az adatokat küldeni kell.
  13. AJAX kérés típusa: A kérés típusa, ebben az esetben POST.
  14. AJAX kérés tartalomtípusa: A kérésben küldött adatok formátuma, itt application/json.
  15. Adatok JSON formátumban: Az formData objektum JSON formátumba konvertálása és az adatként történő elküldése.
  16. Sikeres kérés esetén futtatandó: Sikeres kérés esetén végrehajtandó műveletek.
  17. Sikerüzenet megjelenítése: Egy riasztó üzenet, amely tájékoztat a sikeres adatbeküldésről.
  18. Oldal újratöltése: Az oldal újratöltése a friss adatok megjelenítéséhez.
  19. Hiba esetén futtatandó: Hiba esetén végrehajtandó műveletek.
  20. Hibaüzenet megjelenítése: Egy riasztó üzenet, amely információt ad a hibáról.

Ebben a példában a jQuery keretrendszert használtunk a form adatok JSON formátumba konvertálásához és a POST kérés elküldéséhez az API-hoz. Az űrlap submit eseményét lekezeljük JavaScript segítségével, hogy megakadályozzuk az űrlap alapértelmezett küldési működését, és helyette egy AJAX kérést küldünk, ami lehetővé teszi, hogy a válasz alapján felhasználói visszajelzést adjunk (pl. siker vagy hiba üzenet megjelenítése).

Tesztelés

Ha mindent helyesen csináltunk, akkor az alábbihoz hasonló fájlstruktúrát kell látnunk:

Projekt felépítése
FlaskApp/
├── app.py          # A Flask alkalmazás forráskódja
├── templates/      # Mappa a HTML sablonoknak
   ├── index.html  # A főoldal HTML sablona, amely megjeleníti a virágokat
   └── insert.html # Az új virágok felvételére szolgáló űrlap sablona
└── venv/           # Python virtuális környezet (opcionális, de ajánlott)

Futtasd újra az app.py fájlt. Az alkalmazás indítása után a böngészőben a http://127.0.0.1:5001/insert URL-en keresztül elérhető az űrlap a virágok felvételére. Ellenőrizd, hogy az űrlap sikeresen továbbítja-e a virágok adatait közvetlenül a backend /api/flowers végpontra.

Statikus fájlok kiszolgálása

A statikus fájlok (pl. CSS, JavaScript, képek) a static mappában helyezkednek el a Flask alkalmazásban. Ezek a fájlok Jinja2 template motor segítségével hivatkozhatók meg a HTML sablonokban a url_for('static', filename='...') függvénnyel.

Az alábbi példa szemlélteti az előző mappaszerkezetet a statikus fájlok hozzáadásával:

Projekt felépítése, kiegészítve a static mappával
FlaskApp/
├── app.py          # A Flask alkalmazás forráskódja
├── static/         # Mappa a statikus fájloknak
   ├── style.css   # A CSS stíluslap fájl
   ├── script.js   # A JavaScript fájl
   └── images/     # Képek mappája
       └── flower.jpg # Virág kép
├── templates/      # Mappa a HTML sablonoknak
   ├── index.html  # A főoldal HTML sablona, amely megjeleníti a virágokat
   └── insert.html # Az új virágok felvételére szolgáló űrlap sablona
└── venv/           # Python virtuális környezet (opcionális, de ajánlott)

A static mappában található fájlok a következő módon hivatkozhatók meg a HTML sablonokban:

Példa kód

index.html
1
2
3
4
5
6
7
<!DOCTYPE html>
<html lang="hu">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
    <title>Virág katalógus</title>
</head>

Amennyiben az adott fájl egy alkönyvtárban található, akkor a következő módon lehet hivatkozni rá:

index.html
1
2
3
4
5
6
7
<!DOCTYPE html>
<html lang="hu">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="{{ url_for('static', filename='images/flower.jpg') }}">
    <title>Virág katalógus</title>
</head>