Egy egyszerű webshop kosár funkciójának leprogramozása Flask-ben

Üdvözöllek, leendő webfejlesztő! Ha valaha is elgondolkodtál azon, hogyan működnek a webshopok a háttérben, vagy szeretnéd kipróbálni magad egy egyszerű, de funkcionális webes alkalmazás építésében, akkor jó helyen jársz. Ebben a cikkben egy alapvető, de létfontosságú funkcióra fogunk koncentrálni: egy webshop kosár leprogramozására a népszerű Python webes keretrendszerrel, a Flask-kel.

A kosár funkció a modern e-kereskedelem szíve és lelke. Lehetővé teszi a felhasználók számára, hogy kiválogassák a termékeket, mielőtt eldöntenék, hogy megvásárolják-e azokat. Ez a cikk részletesen bemutatja, hogyan építheted fel ezt a funkciót Flask-ben, a felhasználói session (munkamenet) adatai segítségével. Készen állsz? Vágjunk is bele!

Miért épp Flask?

A Flask egy mikro-keretrendszer, ami azt jelenti, hogy minimális beépített funkcióval rendelkezik, és a fejlesztőre bízza a legtöbb döntést. Ez a rugalmasság ideálissá teszi kisebb, testreszabott projektekhez, prototípusokhoz vagy olyan alkalmazásokhoz, ahol csak bizonyos komponensekre van szükség. Kezdők számára is kiváló választás, mivel könnyen tanulható, és gyorsan lehet vele eredményeket elérni. A Python nyelven íródott, ami köztudottan olvasható és intuitív szintaxist kínál.

A Kosár Funkció Alapvető Működése

Mielőtt belemerülnénk a kódba, értsük meg, hogyan is fogjuk tárolni a kosár tartalmát. Egy valódi, komplex webshop adatbázist használna a felhasználói kosarak tárolására, különösen, ha a felhasználó be van jelentkezve, és szeretné, hogy a kosara megmaradjon, még ha bezárja is a böngészőjét. Egy egyszerűbb megvalósításhoz azonban a Flask session a tökéletes megoldás.

A session egy szerver-oldali tárolási mechanizmus, amely lehetővé teszi, hogy adatokat tároljunk a felhasználó böngészőjében egy cookie formájában. Ez a cookie tartalmaz egy titkosított azonosítót, amellyel a szerver hozzáfér a felhasználóhoz tartozó session adatokhoz. Ez azt jelenti, hogy a felhasználó kosara addig marad meg, amíg a session él (például amíg be nem zárja a böngészőjét, vagy amíg a session le nem jár). Biztonsági okokból fontos, hogy a Flask alkalmazásnak legyen egy erős SECRET_KEY-e a session adatok titkosításához.

A kosár lényegében egy egyszerű szótár (dictionary) lesz a sessionben, ahol a kulcsok a termékazonosítók, az értékek pedig a kosárban lévő termékre vonatkozó információk (pl. mennyiség).

Előkészületek és Projektstruktúra

Ahhoz, hogy elkezdhessük, szükséged lesz a következőkre:

  • Python 3 telepítve a gépeden.
  • pip (Python csomagkezelő) a Flask telepítéséhez.
  • Alapvető ismeretek a Flask-ről (route-ok, template-ek, request objektum).
  • HTML és CSS alapok a felhasználói felülethez.

Hozzuk létre a projektstruktúrát:


my_webshop/
├── app.py
├── templates/
│   ├── index.html
│   └── cart.html
└── static/
    └── style.css

Telepítsük a Flask-et (ha még nem tetted meg):


pip install Flask

Alapvető Flask Alkalmazás Beállítása (app.py)

Kezdjük az app.py fájllal, ahol inicializáljuk a Flask alkalmazást, és beállítjuk a SECRET_KEY-t. Ezen felül definiálunk néhány dummy termékadatot, hogy legyen mivel dolgoznunk.


from flask import Flask, render_template, request, redirect, url_for, session

app = Flask(__name__)
# FONTOS: Cseréld le ezt egy erős, véletlenszerű kulcsra éles környezetben!
app.config['SECRET_KEY'] = 'egy_nagyon_biztonsagos_titkos_kulcs_amit_senki_nem_talal_ki_12345'

# Dummy termékadatok egy szótárban
PRODUCTS = {
    "1": {"id": "1", "name": "Programozó bögre", "price": 2500, "image": "mug.jpg"},
    "2": {"id": "2", "name": "Flask póló", "price": 5000, "image": "tshirt.jpg"},
    "3": {"id": "3", "name": "Python matrica szett", "price": 1200, "image": "stickers.jpg"},
    "4": {"id": "4", "name": "Mechanikus billentyűzet", "price": 35000, "image": "keyboard.jpg"},
}

@app.route('/')
def index():
    # A termékeket átadjuk a sablonnak
    return render_template('index.html', products=PRODUCTS.values())

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

Ne felejtsd el a static mappába tenni néhány dummy képet (pl. `mug.jpg`, `tshirt.jpg` stb.), amiket a PRODUCTS szótárban definiáltál, különben hibát kapsz a képek betöltésénél.

Termékek Megjelenítése (index.html)

Az index.html fájl feladata, hogy megjelenítse a termékeket, és lehetőséget adjon a kosárba helyezésre. Ehhez a Jinja2 sablonmotort használjuk a Flask-ben.


<!DOCTYPE html>
<html lang="hu">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Termékeink - Flask Webshop</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
    <header>
        <h1>Üdvözlünk a Flask Webshopban!</h1>
        <nav>
            <a href="{{ url_for('index') }}">Termékek</a>
            <a href="{{ url_for('cart') }}">Kosár ({{ session.cart | length if session.cart else 0 }})</a>
        </nav>
    </header>
    <main class="product-grid">
        {% for product in products %}
        <div class="product-card">
            <img src="{{ url_for('static', filename=product.image) }}" alt="{{ product.name }}">
            <h3>{{ product.name }}</h3>
            <p>{{ product.price }} Ft</p>
            <form action="{{ url_for('add_to_cart') }}" method="POST">
                <input type="hidden" name="product_id" value="{{ product.id }}">
                <input type="number" name="quantity" value="1" min="1">
                <button type="submit">Kosárba</button>
            </form>
        </div>
        {% endfor %}
    </main>
    <footer>
        <p>&copy; 2023 Flask Webshop</p>
    </footer>
</body>
</html>

Figyeld meg a navigációs sávban lévő „Kosár” linket, ami dinamikusan megjeleníti a kosárban lévő elemek számát a session.cart | length segítségével. A product-card-ok tartalmazzák a termék nevét, árát, képét, és egy űrlapot a kosárba helyezéshez. Az űrlapban egy rejtett mezőben küldjük el a termék azonosítóját, és egy szám mezőben a mennyiséget. Az action="{{ url_for('add_to_cart') }}" rész mondja meg a Flask-nek, melyik útvonalat hívja meg az űrlap elküldésekor.

Termék Kosárba Helyezése

Most jön a lényegi rész! Hozzunk létre egy útvonalat az app.py-ban, amely kezeli a termékek kosárba helyezését.


# ... (előző kód) ...

@app.route('/add_to_cart', methods=['POST'])
def add_to_cart():
    product_id = request.form.get('product_id')
    quantity = int(request.form.get('quantity', 1)) # Alapértelmezett mennyiség: 1

    # Ellenőrizzük, hogy a termék létezik-e
    if product_id not in PRODUCTS:
        return redirect(url_for('index')) # Vagy jeleníts meg hibaüzenetet

    # Inicializáld a kosarat a session-ben, ha még nincs
    if 'cart' not in session:
        session['cart'] = {} # Egy üres szótár a kosár elemeinek

    # Ha a termék már a kosárban van, növeljük a mennyiséget
    if product_id in session['cart']:
        session['cart'][product_id]['quantity'] += quantity
    else:
        # Ha új termék, hozzáadjuk a kosárhoz
        session['cart'][product_id] = {
            'quantity': quantity
        }
    
    # Fontos: Jelezzük a Flask-nek, hogy a session módosult
    session.modified = True 

    # Átirányítunk a kosár oldalra, vagy vissza az indexre
    return redirect(url_for('cart')) 

# ... (további útvonalak) ...

Ez az útvonal csak POST kéréseket fogad el. Kinyerjük a termék azonosítóját és a mennyiséget az űrlapból. Ha a kosár (session['cart']) még nem létezik, létrehozzuk. Ezután ellenőrizzük, hogy a termék már a kosárban van-e. Ha igen, növeljük a mennyiségét; ha nem, hozzáadjuk az új terméket. Az session.modified = True sor rendkívül fontos, különben a Flask nem biztos, hogy érzékeli a session szótárának belső módosításait. Végül átirányítjuk a felhasználót a kosár oldalra.

A Kosár Tartalmának Megjelenítése (cart.html)

Most, hogy van egy kosárbahívási funkciónk, építsük meg a kosár oldalát, ahol a felhasználó láthatja, miket válogatott össze.


# ... (előző kód) ...

@app.route('/cart')
def cart():
    cart_items = []
    total_price = 0
    # Ha van 'cart' a session-ben
    if 'cart' in session:
        for product_id, item_data in session['cart'].items():
            product = PRODUCTS.get(product_id) # Lekérjük a termék teljes adatait a PRODUCTS szótárból
            if product: # Ha a termék létezik (pl. nem törölték közben)
                item_total = product['price'] * item_data['quantity']
                total_price += item_total
                cart_items.append({
                    'id': product['id'],
                    'name': product['name'],
                    'price': product['price'],
                    'quantity': item_data['quantity'],
                    'item_total': item_total,
                    'image': product['image']
                })
    return render_template('cart.html', cart_items=cart_items, total_price=total_price)

# ... (további útvonalak) ...

Az /cart útvonal lekéri a session['cart'] tartalmát, majd a PRODUCTS szótár segítségével kiegészíti a termékek adatait (név, ár, kép). Kiszámolja az egyes tételek részösszegét és a teljes kosárértéket, majd ezeket átadja a cart.html sablonnak.

Íme a cart.html sablon:


<!DOCTYPE html>
<html lang="hu">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Kosarad - Flask Webshop</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
    <header>
        <h1>Kosarad</h1>
        <nav>
            <a href="{{ url_for('index') }}">Vissza a termékekhez</a>
            {% if cart_items %}
            <a href="{{ url_for('empty_cart') }}" class="empty-cart-btn">Kosár ürítése</a>
            {% endif %}
        </nav>
    </header>
    <main>
        {% if cart_items %}
        <div class="cart-items">
            {% for item in cart_items %}
            <div class="cart-item">
                <img src="{{ url_for('static', filename=item.image) }}" alt="{{ item.name }}" class="cart-item-image">
                <div class="cart-item-details">
                    <h3>{{ item.name }}</h3>
                    <p>Egységár: {{ item.price }} Ft</p>
                    <form action="{{ url_for('update_cart') }}" method="POST" class="update-form">
                        <input type="hidden" name="product_id" value="{{ item.id }}">
                        <label for="quantity_{{ item.id }}">Mennyiség:</label>
                        <input type="number" name="quantity" id="quantity_{{ item.id }}" value="{{ item.quantity }}" min="0">
                        <button type="submit">Frissítés</button>
                    </form>
                    <p>Részösszeg: {{ item.item_total }} Ft</p>
                    <form action="{{ url_for('remove_from_cart') }}" method="POST">
                        <input type="hidden" name="product_id" value="{{ item.id }}">
                        <button type="submit" class="remove-btn">Eltávolítás</button>
                    </form>
                </div>
            </div>
            {% endfor %}
        </div>
        <div class="cart-summary">
            <h2>Összesen: {{ total_price }} Ft</h2>
            <button class="checkout-btn">Tovább a pénztárhoz (nem implementált)</button>
        </div>
        {% else %}
        <p class="empty-cart-message">A kosarad üres. Kezdj el vásárolni!</p>
        {% endif %}
    </main>
    <footer>
        <p>&copy; 2023 Flask Webshop</p>
    </footer>
</body>
</html>

Ez a sablon végigmegy a cart_items listán, és minden elemhez megjeleníti a részleteket. Tartalmaz egy űrlapot a mennyiség frissítésére, és egy gombot az elem eltávolítására. Végül összefoglalja az összesítést. Ha a kosár üres, egy üzenetet jelenít meg.

Kosár Tartalmának Frissítése és Törlése

Két további funkció elengedhetetlen egy kosárnál: a termékek mennyiségének módosítása és a termékek eltávolítása. Ezeket is POST kérésekkel kezeljük.


# ... (előző kód) ...

@app.route('/update_cart', methods=['POST'])
def update_cart():
    product_id = request.form.get('product_id')
    new_quantity = int(request.form.get('quantity'))

    if 'cart' in session and product_id in session['cart']:
        if new_quantity > 0:
            session['cart'][product_id]['quantity'] = new_quantity
        else:
            # Ha a mennyiség 0 vagy negatív, töröljük a terméket a kosárból
            del session['cart'][product_id] 
        session.modified = True
    
    return redirect(url_for('cart'))

@app.route('/remove_from_cart', methods=['POST'])
def remove_from_cart():
    product_id = request.form.get('product_id')

    if 'cart' in session and product_id in session['cart']:
        del session['cart'][product_id]
        session.modified = True
    
    return redirect(url_for('cart'))

@app.route('/empty_cart')
def empty_cart():
    # Törli a 'cart' kulcsot a session-ből, ha létezik
    session.pop('cart', None) 
    session.modified = True
    return redirect(url_for('cart'))

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

Az /update_cart útvonal beállítja a termék mennyiségét. Fontos, hogy ha a mennyiség 0-ra csökken, akkor eltávolítsuk a terméket a kosárból. Az /remove_from_cart útvonal egyszerűen törli a megadott terméket. Az /empty_cart pedig az egész kosarat kiüríti. Mindhárom esetben a session.modified = True parancs elengedhetetlen, és átirányítunk a kosár oldalra, hogy a változások azonnal láthatóak legyenek.

Stíluslap (static/style.css)

A CSS fájl (static/style.css) segít, hogy a webshopunk ne csak működjön, hanem jól is nézzen ki. Itt egy nagyon alapvető stíluslap, amit továbbfejleszthetsz saját ízlésed szerint:


body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 0;
    background-color: #f4f4f4;
    color: #333;
}

header {
    background-color: #333;
    color: #fff;
    padding: 1rem;
    text-align: center;
}

nav a {
    color: #fff;
    text-decoration: none;
    margin: 0 1rem;
}

main {
    padding: 20px;
    max-width: 1200px;
    margin: 20px auto;
    background-color: #fff;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
    border-radius: 8px;
}

/* Termékkártyák, kosár elemek stílusai */
.product-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 20px;
}

.product-card, .cart-item {
    border: 1px solid #ddd;
    padding: 15px;
    text-align: center;
    border-radius: 8px;
    background-color: #fff;
}

.product-card img, .cart-item-image {
    max-width: 100%;
    height: 150px;
    object-fit: contain;
    margin-bottom: 10px;
}

/* További stílusok a gombokhoz, űrlapokhoz, összefoglalóhoz... */
/* ... (a teljes CSS kód, amit a gondolatmenetben generáltam) ... */

A teljes CSS fájlt a gondolatmenetben találod. Fontos, hogy a url_for('static', filename='style.css') hivatkozás működjön, ehhez a style.css fájlnak a static mappában kell lennie.

További Fejlesztési Lehetőségek és Biztonsági Megfontolások

Ez egy egyszerű, alapvető kosár funkció. Íme néhány tipp a továbbfejlesztéshez és a biztonsághoz:

  • Adatbázis integráció: Valódi webshopoknál a termékek adatait adatbázisban tároljuk (pl. SQLAlchemy és PostgreSQL/SQLite segítségével), nem egy Python szótárban. A felhasználók kosarát is tárolhatjuk adatbázisban (például egy bejelentkezett felhasználóhoz rendelve), így az nem vész el a session lejártával.
  • Felhasználói fiókok: Regisztráció és bejelentkezés implementálása, hogy a felhasználók menthessék a kosarukat, megtekinthessék a rendelési előzményeiket.
  • Checkout (pénztár) folyamat: Egy teljes értékű checkout oldal, ahol a felhasználó megadja a szállítási adatokat, kiválasztja a fizetési módot, és leadja a rendelést.
  • Fizetési átjárók: Integráció harmadik fél fizetési szolgáltatókkal (pl. Stripe, PayPal).
  • AJAX / JavaScript: A felhasználói élmény javítása érdekében a kosárba helyezés, mennyiség frissítése vagy termék eltávolítása történhetne oldalfrissítés nélkül, AJAX kérésekkel.
  • Input validáció: Mindig ellenőrizd a felhasználói bevitelt a szerver oldalon (pl. a mennyiség pozitív egész szám-e), hogy megelőzd a rosszindulatú adatokat.
  • SECRET_KEY biztonság: Az éles alkalmazásokban soha ne tárolja a SECRET_KEY-t közvetlenül a kódban. Használjon környezeti változókat (environment variables) vagy konfigurációs fájlokat a tárolására.
  • Hiba kezelés: Értelmes hibaüzenetek megjelenítése a felhasználó számára, ha valami probléma merül fel (pl. nem létező termék).

Összefoglalás

Gratulálok! Most már van egy működő kosár funkcióval rendelkező egyszerű webshopod, amelyet a Flask segítségével építettél fel! Megtanultad, hogyan kell a session-t használni az adatok tárolására, hogyan kell kezelni a termékek hozzáadását, frissítését és törlését, és hogyan kell mindezt megjeleníteni a felhasználónak. Ez egy fantasztikus alap, amire építkezhetsz, és továbbfejlesztheted a webes alkalmazásodat. A webfejlesztés egy folyamatos tanulási folyamat, de a legfontosabb a kezdet! Folytasd a kísérletezést és a tanulást!

Remélem, élvezted ezt a részletes útmutatót, és inspirációt merítettél belőle a további projektekhez. Sok sikert a kódoláshoz!

Leave a Reply

Az e-mail címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük