Hogyan készíts egy URL rövidítő szolgáltatást Flask-kel

Üdvözöllek a webfejlesztés izgalmas világában! Ma egy olyan projektbe vágunk bele, ami nemcsak rendkívül hasznos, de kiváló lehetőséget biztosít arra is, hogy mélyebben megértsük a webes alkalmazások működését: egy saját URL rövidítő szolgáltatás elkészítését fogjuk bemutatni a népszerű Flask keretrendszer segítségével. Gondoltad volna, hogy a „bit.ly” vagy a „tinyurl.com” mögött meghúzódó logika valójában nem is olyan bonyolult? Nos, hamarosan magad is meggyőződhetsz róla!

Miért érdemes URL rövidítőt építeni?

Az URL rövidítők mára a digitális kommunikáció szerves részévé váltak. Gondoljunk csak a Twitterre, ahol a karakterkorlát miatt elengedhetetlen a hosszú linkek lerövidítése, vagy a marketing kampányokra, ahol az átláthatóbb és esztétikusabb URL-ek jelentősen javíthatják a felhasználói élményt. De nem csak ezért érdemes belevágni egy ilyen projektbe:

  • Tanulás és gyakorlás: Kiváló módja a Flask alapok, az adatbázis kezelés és a webes logika elsajátításának.
  • Személyes projekt: Hozzáadhatod a portfóliódhoz, megmutatva a programozási képességeidet.
  • Testreszabhatóság: Saját domain alatt futtathatod, egyedi funkciókkal bővítheted, ami a publikus szolgáltatásoknál nem lehetséges.
  • A web működésének megértése: Betekintést nyersz abba, hogyan működik a HTTP átirányítás és a szerver-oldali logika.

Miért pont a Flask?

A Flask egy Python alapú mikro webes keretrendszer. Ez azt jelenti, hogy minimalista és rugalmas, nincsenek beépített, kötelező eszközei vagy könyvtárai. Te döntöd el, mit használsz, ami hihetetlen szabadságot ad, és ideális választássá teszi kisebb, célzott projektekhez. Könnyű elkezdeni, gyorsan tanulható, és fantasztikus a prototípusok készítéséhez. Pontosan az, amire szükségünk van egy URL rövidítő szolgáltatás felépítéséhez!

Előfeltételek és a környezet beállítása

Mielőtt belekezdenénk a kódolásba, győződjünk meg róla, hogy minden szükséges eszköz rendelkezésünkre áll:

  • Python 3: Győződj meg róla, hogy telepítve van a gépeden. (Ajánlott a 3.8+ verzió)
  • Alapvető ismeretek: Legyen némi ismereted a Pythonról, HTML-ről és a parancssor használatáról.

Virtuális környezet létrehozása

A virtuális környezet használata kritikus fontosságú a Python projektekben. Segít elkülöníteni a projektfüggőségeket, elkerülve a különböző projektek közötti konfliktusokat. Nyisd meg a terminált/parancssort, és kövesd az alábbi lépéseket:


# Hozzunk létre egy új mappát a projektünknek
mkdir flask_shortener
cd flask_shortener

# Hozzunk létre egy virtuális környezetet
python3 -m venv venv

# Aktiváljuk a virtuális környezetet
# Linux/macOS esetén:
source venv/bin/activate

# Windows esetén:
.venvScriptsactivate

Látni fogod, hogy a parancssor elején megjelenik a `(venv)` jelzés, ami azt jelenti, hogy a virtuális környezet aktív.

Flask és az adatbázis csomagok telepítése

Most telepítsük a Flask-et és a Flask-SQLAlchemy bővítményt. A Flask-SQLAlchemy egy nagyszerű ORM (Object-Relational Mapper) eszköz, amely megkönnyíti az adatbázisokkal való interakciót Flask alkalmazásokban.


pip install Flask Flask-SQLAlchemy

A projekt szerkezete

Kezdjük el felépíteni a projektünk alapvető struktúráját:


flask_shortener/
├── venv/
├── app.py
├── templates/
│   └── index.html
└── static/
    └── style.css
  • app.py: Itt lesz a fő Flask alkalmazás kódja.
  • templates/: Ez a mappa fogja tartalmazni az összes HTML sablonunkat.
  • static/: Ide kerülnek a statikus fájlok, mint a CSS és a JavaScript.

Adatbázis beállítása: Flask-SQLAlchemy és SQLite

Egy URL rövidítőnek valahol tárolnia kell az eredeti URL-eket és a hozzájuk tartozó rövid kódokat. Ehhez egy adatbázist fogunk használni. Egyszerűség kedvéért a SQLite-ot választjuk, ami egy fájl alapú adatbázis, ideális kis és közepes alkalmazásokhoz, és nem igényel külön szerver telepítést.

Az adatbázis modell definiálása

Nyissuk meg az app.py fájlt, és írjuk bele az alapvető Flask alkalmazás konfigurációját és az adatbázis modellünket. A modell fogja leírni, hogy milyen adatokkal dolgozunk az adatbázisban.


import string
import random
from datetime import datetime
from flask import Flask, render_template, request, redirect, url_for, flash
from flask_sqlalchemy import SQLAlchemy

# Flask alkalmazás inicializálása
app = Flask(__name__)

# Konfiguráció
app.config['SECRET_KEY'] = 'egy_nagyon_hosszu_es_biztonsagos_titkos_kulcs' # Cseréld le egy valódira!
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///urls.db' # Az adatbázis fájl neve
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# SQLAlchemy inicializálása
db = SQLAlchemy(app)

# Adatbázis modell
class ShortURL(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    original_url = db.Column(db.String(500), nullable=False)
    short_code = db.Column(db.String(10), unique=True, nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    clicks = db.Column(db.Integer, default=0)

    def __repr__(self):
        return f'<ShortURL {self.short_code}: {self.original_url}>'

# Adatbázis létrehozása az első kérés előtt
with app.app_context():
    db.create_all()

Magyarázat:

  • app.config['SECRET_KEY']: Fontos a Flask biztonságos működéséhez (pl. session kezelés). Ne felejtsd el lecserélni egy valós, komplex kulcsra éles környezetben!
  • app.config['SQLALCHEMY_DATABASE_URI']: Meghatározza az adatbázisunk helyét és típusát. Itt egy urls.db nevű SQLite fájlra mutat.
  • ShortURL osztály: Ez a modellünk, ami a db.Model osztályból öröklődik. Ez fogja reprezentálni az adatbázisunk egy tábláját.
    • id: Egyedi azonosító, elsődleges kulcs.
    • original_url: Az eredeti, hosszú URL.
    • short_code: A generált rövid kód, egyedi és nem lehet üres.
    • created_at: Az URL rövidítésének időpontja.
    • clicks: Hány alkalommal kattintottak a rövidített linkre (alapértelmezésben 0).
  • with app.app_context(): db.create_all(): Ez a sor gondoskodik róla, hogy az adatbázis táblái létrejöjjenek, amikor az alkalmazás először elindul. Csak egyszer kell futtatni, vagy amikor módosítjuk a modellt.

Az URL rövidítés logikája

Most, hogy van egy adatbázisunk, szükségünk van egy logikára, amely generálja az egyedi rövid kódokat. Ehhez egy egyszerű, véletlenszerű karakterlánc generálást használunk, és ellenőrizzük, hogy létezik-e már az adatbázisban.


def generate_short_code(length=6):
    characters = string.ascii_letters + string.digits # Kis- és nagybetűk, számok
    while True:
        short_code = ''.join(random.choice(characters) for _ in range(length))
        # Ellenőrizzük, hogy a kód egyedi-e
        existing_url = ShortURL.query.filter_by(short_code=short_code).first()
        if not existing_url:
            return short_code

Ez a függvény addig generál véletlenszerű, 6 karakter hosszúságú kódokat, amíg egy egyedi kódot nem talál. Ez egy egyszerű megoldás, de nagyobb forgalom esetén érdemes lehet egy robusztusabb módszert (pl. Base62 kódolás egy auto-inkrementáló ID-ból) használni.

Routing és nézetek (Views)

Most térjünk rá a Flask legfontosabb részére: a routingra és a nézetekre. Ezek határozzák meg, hogy az URL-ek hogyan kerülnek feldolgozásra, és milyen HTML tartalmat jelenít meg az alkalmazásunk.

Főoldal és URL rövidítés (/)

Ez lesz az az oldal, ahol a felhasználó beírja a hosszú URL-t, és megkapja a rövidített verziót.


@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'POST':
        original_url = request.form['original_url']
        if not original_url:
            flash('Kérjük, adjon meg egy érvényes URL-t!', 'error')
            return render_template('index.html')

        # Ellenőrizzük, hogy az URL már létezik-e az adatbázisban
        existing_short_url = ShortURL.query.filter_by(original_url=original_url).first()
        if existing_short_url:
            flash(f'Ez az URL már rövidítve lett: {request.url_root}{existing_short_url.short_code}', 'info')
            return render_template('index.html', short_url=f'{request.url_root}{existing_short_url.short_code}')

        short_code = generate_short_code()
        new_url = ShortURL(original_url=original_url, short_code=short_code)
        db.session.add(new_url)
        db.session.commit()
        
        # A flash üzenetek megjelenítéséhez szükség van a secret_key-re!
        flash('Az URL sikeresen rövidítve lett!', 'success')
        return render_template('index.html', short_url=f'{request.url_root}{short_code}')
    
    return render_template('index.html')

Magyarázat:

  • @app.route('/', methods=['GET', 'POST']): Ez a dekorátor összekapcsolja a / útvonalat az index() függvénnyel. Képes kezelni a GET (oldal betöltése) és a POST (űrlap elküldése) kéréseket is.
  • request.method == 'POST': Ellenőrzi, hogy az űrlapot küldték-e be.
  • request.form['original_url']: Lekéri az űrlapból az „original_url” nevű mező értékét.
  • flash(): Üzeneteket jelenít meg a felhasználónak (pl. hibaüzenetek, sikeres műveletek).
  • ShortURL.query.filter_by(...): Lekérdez az adatbázisból.
  • db.session.add(new_url) és db.session.commit(): Elmenti az új URL-t az adatbázisba.
  • render_template('index.html', short_url=...): Betölti az index.html sablont, és átadja neki a short_url változót.
  • request.url_root: A futó alkalmazás gyökér URL-je (pl. `http://127.0.0.1:5000/`).

URL átirányítása (/<short_code>)

Ez az útvonal felelős azért, hogy amikor valaki rákattint egy rövidített linkre, az átirányítsa őt az eredeti URL-re.


@app.route('/<short_code>')
def redirect_to_original(short_code):
    short_url_obj = ShortURL.query.filter_by(short_code=short_code).first()

    if short_url_obj:
        short_url_obj.clicks += 1 # Növeljük a kattintások számát
        db.session.commit()
        return redirect(short_url_obj.original_url)
    else:
        flash('Ez a rövidített URL nem található!', 'error')
        return redirect(url_for('index')) # Vissza az index oldalra

Magyarázat:

  • @app.route('/<short_code>'): A <short_code> egy változó rész az URL-ben, amit a Flask átad a függvénynek paraméterként.
  • ShortURL.query.filter_by(short_code=short_code).first(): Megkeresi az adatbázisban a megfelelő rövid kódot.
  • redirect(short_url_obj.original_url): Átirányítja a felhasználót az eredeti URL-re.
  • url_for('index'): Generál egy URL-t az index függvényhez. Ez jobb, mint a „hardkódolt” URL-ek, mert ha az útvonal változik, nem kell mindenhol javítani.

Front-end: HTML sablon és alap CSS

Most, hogy a háttérrendszer kész van, építsük meg a felhasználói felületet.

templates/index.html

Hozd létre a templates mappát, és benne az index.html fájlt a következő tartalommal:


<!DOCTYPE html>
<html lang="hu">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Flask URL Rövidítő</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
    <div class="container">
        <h1>URL Rövidítő Flask-kel</h1>

        {% with messages = get_flashed_messages(with_categories=true) %}
            {% if messages %}
                <ul class="flashes">
                    {% for category, message in messages %}
                        <li class="{{ category }}">{{ message }}</li>
                    {% endfor %}
                </ul>
            {% endif %}
        {% endwith %}

        <form method="POST">
            <input type="url" name="original_url" placeholder="Illessze be ide a hosszú URL-t" required>
            <button type="submit">Rövidítés</button>
        </form>

        {% if short_url %}
            <div class="result-box">
                <p>A rövidített URL:</p>
                <input type="text" value="{{ short_url }}" readonly id="shortUrlInput">
                <button onclick="copyToClipboard()">Másolás</button>
            </div>
        {% endif %}
    </div>

    <script>
        function copyToClipboard() {
            var copyText = document.getElementById("shortUrlInput");
            copyText.select();
            copyText.setSelectionRange(0, 99999); // Mobiles
            document.execCommand("copy");
            alert("Rövidített URL másolva: " + copyText.value);
        }
    </script>
</body>
</html>

Magyarázat:

  • <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">: Betölti a CSS fájlunkat.
  • {% with messages = get_flashed_messages(with_categories=true) %}...{% endwith %}: Ez egy Jinja2 sablonkód, ami megjeleníti a Flask alkalmazásunk által küldött flash() üzeneteket.
  • <form method="POST">: Az űrlap, ahol a felhasználó beírja az URL-t.
  • {% if short_url %}...{% endif %}: Csak akkor jeleníti meg a rövidített URL-t, ha az létezik (azaz sikeresen rövidítettek egyet).
  • copyToClipboard() JavaScript funkció: Lehetővé teszi, hogy egy gombnyomással kimásoljuk a rövidített URL-t.

static/style.css

Hozd létre a static mappát, és benne a style.css fájlt a következő alapvető stílusokkal:


body {
    font-family: Arial, sans-serif;
    background-color: #f4f4f4;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    margin: 0;
}

.container {
    background-color: #ffffff;
    padding: 30px;
    border-radius: 8px;
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
    text-align: center;
    max-width: 500px;
    width: 100%;
}

h1 {
    color: #333;
    margin-bottom: 25px;
}

form {
    display: flex;
    margin-bottom: 20px;
}

input[type="url"] {
    flex-grow: 1;
    padding: 12px 15px;
    border: 1px solid #ddd;
    border-radius: 5px 0 0 5px;
    font-size: 16px;
    outline: none;
}

button[type="submit"] {
    background-color: #007bff;
    color: white;
    border: none;
    padding: 12px 20px;
    border-radius: 0 5px 5px 0;
    cursor: pointer;
    font-size: 16px;
    transition: background-color 0.3s ease;
}

button[type="submit"]:hover {
    background-color: #0056b3;
}

.result-box {
    background-color: #e9ecef;
    padding: 15px;
    border-radius: 5px;
    margin-top: 20px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap; /* Hosszabb URL esetén törje a sort */
}

.result-box p {
    margin: 0;
    color: #555;
    font-weight: bold;
    flex-basis: 100%; /* Elfoglalja a teljes szélességet */
    margin-bottom: 10px;
}

.result-box input[type="text"] {
    flex-grow: 1;
    padding: 10px 12px;
    border: 1px solid #ccc;
    border-radius: 5px;
    font-size: 16px;
    margin-right: 10px;
    outline: none;
    min-width: 200px; /* Alap méret a reszponzivitáshoz */
}

.result-box button {
    background-color: #28a745;
    color: white;
    border: none;
    padding: 10px 15px;
    border-radius: 5px;
    cursor: pointer;
    font-size: 16px;
    transition: background-color 0.3s ease;
}

.result-box button:hover {
    background-color: #218838;
}

.flashes {
    list-style: none;
    padding: 0;
    margin: 0 0 20px 0;
}

.flashes li {
    padding: 10px 15px;
    border-radius: 5px;
    margin-bottom: 10px;
    font-weight: bold;
    font-size: 14px;
}

.flashes li.error {
    background-color: #f8d7da;
    color: #721c24;
    border: 1px solid #f5c6cb;
}

.flashes li.success {
    background-color: #d4edda;
    color: #155724;
    border: 1px solid #c3e6cb;
}

.flashes li.info {
    background-color: #d1ecf1;
    color: #0c5460;
    border: 1px solid #bee5eb;
}

@media (max-width: 600px) {
    form {
        flex-direction: column;
    }

    input[type="url"],
    button[type="submit"] {
        border-radius: 5px;
        margin-bottom: 10px;
    }

    .result-box {
        flex-direction: column;
    }

    .result-box input[type="text"] {
        margin-right: 0;
        margin-bottom: 10px;
        width: 100%; /* Teljes szélesség mobilon */
    }
}

Az alkalmazás futtatása

Most, hogy minden készen áll, futtassuk az alkalmazásunkat! Győződj meg róla, hogy a virtuális környezet továbbra is aktív, és a projekt mappájában vagy.


# Indítsuk el a Flask fejlesztői szervert
flask run

Vagy ha a FLASK_APP környezeti változó nincs beállítva:


export FLASK_APP=app.py # Linux/macOS
$env:FLASK_APP = "app.py" # Windows PowerShell
flask run

Ezután látni fogsz egy üzenetet, valami hasonlót:


 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

Nyisd meg a böngésződben a http://127.0.0.1:5000/ címet, és máris tesztelheted a saját URL rövidítő szolgáltatásodat!

További fejlesztési lehetőségek és gondolatok

Ez az alap URL rövidítő egy remek kiindulópont, de számos módon továbbfejleszthető:

  • Egyedi rövid kódok: Lehetővé tenni a felhasználóknak, hogy saját maguk válasszák meg a rövid kódot (feltéve, hogy az még szabad).
  • Statisztikák és analitika: Készíts egy oldalt, ahol megtekinthetők a kattintások száma, a hivatkozó oldalak (referrer), földrajzi adatok stb.
  • Felhasználói fiókok: Hozzáadhatsz felhasználókezelést, így mindenki csak a saját rövidített URL-jeit láthatja és kezelheti.
  • API: Készíts egy REST API-t, amellyel programatikusan is lehet URL-eket rövidíteni.
  • Érvényesítés: Robusztusabb URL érvényesítést valósíts meg (pl. regex-szel ellenőrizni, hogy valóban URL-e a bemenet).
  • Hiba kezelés: Szebb 404-es oldal, logolás.
  • Deployment: Ha szeretnéd, hogy az alkalmazásod a világ számára is elérhető legyen, meg kell tanulnod az alkalmazások telepítését (pl. Herokura, PythonAnywhere-re, Vercelre vagy saját szerverre Gunicorn és Nginx segítségével).
  • Frontend fejlesztés: Bootstrap vagy Tailwind CSS integrálása a szebb és reszponzívabb felület érdekében.

Konklúzió

Gratulálok! Sikeresen elkészítetted a saját URL rövidítő szolgáltatásodat Flask-kel. Ez a projekt nemcsak egy működő webalkalmazást eredményezett, hanem értékes ismereteket is adott a webfejlesztés alapjairól, az adatbázis kezelésről és a Flask keretrendszerről. Láthatod, hogy egy viszonylag egyszerű ötletből, megfelelő eszközökkel és némi programozási tudással egy hasznos és működő szolgáltatás hozható létre.

Remélem, ez az útmutató inspirációt adott a további felfedezésekhez és projektekhez a Python és Flask világában! Ne állj meg itt, kísérletezz, bővítsd a tudásod, és építs még nagyszerűbb dolgokat!

Leave a Reply

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