Flask i SQLite: zapisują dane w bazie danych
Lista Python w sekcji 22.5 staje się tabelą SQLite, która przetrwa restart.
Teraz lista Python z sekcji 22.5 został zastąpiony bazą danych SQLite. Schemat jest prosty — Jedna tabela:
CREATE TABLE IF NOT EXISTS tasks (
id INTEGER PRIMARY KEY,
title TEXT NOT NULL,
done INTEGER NOT NULL DEFAULT 0 CHECK (done IN (0, 1))
);
CHECK (done IN (0, 1)) jest dodatkowym ograniczeniem:
SQLite nie pozwoli ci pisać do done nic poza 0 lub 1,
Nawet jeśli gdzieś w kodzie aplikacji pojawi się jakiś błąd.
Jedno połączenie na żądanie
Otwieranie połączenia z bazą przy każdym małym połączeniu to marnotrawstwo, ale utrzymanie jednego
Wspólne połączenie w całej aplikacji bez ostrożności jest ryzykowne przy równoległych rozwiązaniach
zapytania. Flask oferuje wygodne miejsce na dane, które muszą być dokładnie w jednym miejscu
zapytanie, jest obiektem g:
import sqlite3
from flask import Flask, g
app = Flask(__name__)
app.config["DATABASE"] = "zadachi.db"
def get_db():
if "db" not in g:
g.db = sqlite3.connect(app.config["DATABASE"])
g.db.row_factory = sqlite3.Row
return g.db
@app.teardown_appcontext
def close_db(exception=None):
db = g.pop("db", None)
if db is not None:
db.close()
g przechowuje dane w kontekst aplikacji Flask. W normalnym przetwarzaniu HTTP- żądania ten kontekst występuje dokładnie od początku jego zakończenia i jest tworzony na nowo dla każdego kolejnego żądania — zatem w praktyce, g zachowuje się jak magazyn jednego zapytania, a nie jak wspólna zmienna, z której dane mogą przypadkowo „wyciec” do innego zapytania. teardown_appcontext jest wywoływane, gdy kontekst aplikacji jest zamknięty, nawet jeśli handler zawiodł, połączenie jest zawsze zamykane.Trasy na górze bazy danych
@app.route("/")
def glavnaya():
db = get_db()
zadachi = db.execute("SELECT id, title, done FROM tasks ORDER BY id").fetchall()
return render_template("index.html", zadachi=zadachi)
@app.route("/dobavit", methods=["POST"])
def dobavit():
title = clean_title(request.form.get("zadacha", ""))
if title is None:
flash(„Nazwa zadania nie może być pusta i nie dłuższa niż 200 znaków.”)
return redirect(url_for("glavnaya"), code=303)
db = get_db()
db.execute("INSERT INTO tasks (title) VALUES (?)", (title,))
db.commit()
return redirect(url_for("glavnaya"), code=303)
Proszę zauważyć: ? w SQL- zapytaniu i wartość jako osobny argument — to samo parametryzowane zapytanie z rozdziału 22.22, teraz wewnątrz aplikacji roboczej. flash(...) zapisuje pojawioną wiadomość
Na następnej stronie po przekierowaniu następna pokazuje dokładnie, jak to działa
Rozdział, 22:30. clean_title(...) jest prostą funkcją kontrolną z
Rozdział 22.31: Pusta lub zbyt długa nazwa jest odrzucana przed dostępem do bazy danych.
Pełny plik roboczy — ze wszystkimi trasami, obsługą błędów i API — można znaleźć tutaj:
projects/flask/todo-app/app.py
python app.pydodaj kilka zadań, zatrzymaj proces (Ctrl+C) i zacznij od nowa. Lista pozostanie taka sama – dokładnie to, czego brakowało wersji w sekcji 22.5.