From 93a0acf36a0d8cd24cbd0dcc9dee1166a9b0a044 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Tue, 17 Feb 2026 11:12:48 +0400 Subject: [PATCH] Add Flask Postgres CRUD demo --- .gitignore | 2 + README.md | 6 +- requirements.txt | 3 +- site/app.py | 216 +++++++++++++++++++++++------------------------ 4 files changed, 114 insertions(+), 113 deletions(-) diff --git a/.gitignore b/.gitignore index eba74f4..5cdf96c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ +site/templates/ +site/static/ venv/ \ No newline at end of file diff --git a/README.md b/README.md index 1988acc..3338497 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ -# Baulder-s-Gate-test -A test to find out who you are from the game Baldur's Gate. \ No newline at end of file +# Flask + Postgres Demo + +Простое CRUD-приложение на Flask, которое пишет и читает из таблицы `nubes_test_table`. +Если поле ввода пустое, вставляется запись "Это Flask сделал". \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 26bba31..b46927f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ Flask==2.0.1 -Werkzeug==2.3.7 \ No newline at end of file +Werkzeug==2.3.7 +psycopg2-binary==2.9.9 \ No newline at end of file diff --git a/site/app.py b/site/app.py index 4aa9c37..7a8f646 100644 --- a/site/app.py +++ b/site/app.py @@ -1,121 +1,117 @@ -from flask import Flask, render_template, request +import os -class BaldursGateQuizApp: - def __init__(self): - self.app = Flask(__name__, template_folder="templates", static_folder="static") - self.add_routes() +import psycopg2 +from flask import Flask, redirect, render_template_string, request - def add_routes(self): - self.app.add_url_rule('/', 'index', self.index) - self.app.add_url_rule('/result', 'result', self.result, methods=["POST"]) - self.app.add_url_rule('/tests', 'tests', self.tests) - self.app.add_url_rule('/about', 'about', self.about) +app = Flask(__name__) - def index(self): - return render_template("index.html") - def tests(self): - return render_template("tests.html") +def get_conn(): + db_url = os.getenv("DATABASE_URL") + if db_url: + return psycopg2.connect(db_url) + return psycopg2.connect( + host=os.getenv("PGHOST"), + port=os.getenv("PGPORT", "5432"), + user=os.getenv("PGUSER"), + password=os.getenv("PGPASSWORD"), + dbname=os.getenv("PGDATABASE", "postgres"), + sslmode=os.getenv("PGSSLMODE", "require"), + ) - def result(self): - answers = request.form - character = self.determine_character(answers) - return render_template("result.html", character=character) - def about(self): - return render_template("about.html") +def ensure_table(): + with get_conn() as conn, conn.cursor() as cur: + cur.execute( + """ + CREATE TABLE IF NOT EXISTS nubes_test_table ( + id SERIAL PRIMARY KEY, + test_data TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + """ + ) - @staticmethod - def determine_character(answers): - traits = { - "brave": "Минск", - "wise": "Гейл", - "kind": "Карлах", - "cunning": "Астарион", - "strict": "Лаэзель", - "dark": "Шэдоухарт" - } - roles = { - "leader": "Минск", - "healer": "Хальсин", - "fighter": "Карлах", - "rogue": "Астарион", - "mage": "Гейл" - } - goals = { - "glory": "Минск", - "knowledge": "Гейл", - "protect": "Шэдоухарт", - "power": "Лаэзель" - } - rules = { - "strict": "Лаэзель", - "flexible": "Гейл", - "pragmatic": "Астарион", - "chaotic": "Шэдоухарт" - } - weapons = { - "sword": "Минск", - "staff": "Гейл", - "dagger": "Астарион", - "mace": "Карлах", - "bow": "Лаэзель" - } - places = { - "tavern": "Карлах", - "library": "Гейл", - "wilderness": "Хальсин", - "castle": "Лаэзель", - "dark_alley": "Шэдоухарт" - } - mood_fix = { - "training": "Лаэзель", - "reading": "Гейл", - "adventure": "Минск", - "meditation": "Шэдоухарт", - "drinking": "Карлах" - } - colors = { - "red": "Карлах", - "blue": "Гейл", - "green": "Хальсин", - "black": "Шэдоухарт", - "gold": "Лаэзель" - } - choices = [ - traits.get(answers.get("question1")), - roles.get(answers.get("question2")), - goals.get(answers.get("question3")), - rules.get(answers.get("question4")), - weapons.get(answers.get("question5")), - places.get(answers.get("question6")), - mood_fix.get(answers.get("question7")), - colors.get(answers.get("question8")) - ] - - choices = [choice for choice in choices if choice is not None] - - if not choices: - return {"name": "Неизвестно", "image": "unknown.jpg", "description": "Не удалось определить персонажа."} - - most_common = max(set(choices), key=choices.count) - - characters_info = { - "Минск": {"name": "Минск", "image": "minsk.jpg", "description": "Герой, идущий напролом с верным хомяком Бу"}, - "Гейл": {"name": "Гейл", "image": "gale.jpg", "description": "Могущественный маг, жаждущий знаний и силы"}, - "Карлах": {"name": "Карлах", "image": "karlach.jpg", "description": "Добрая, но грозная воительница"}, - "Астарион": {"name": "Астарион", "image": "astarion.jpeg", "description": "Хитрый вампир, любящий свободу"}, - "Лаэзель": {"name": "Лаэзель", "image": "laezel.jpg", "description": "Жесткая и бескомпромиссная гитянка-воительница"}, - "Шэдоухарт": {"name": "Шэдоухарт", "image": "shadowheart.jpg", "description": "Таинственная жрица с темным прошлым"}, - "Хальсин": {"name": "Хальсин", "image": "halsin.jpg", "description": "Мудрый друид, защитник природы."} - } +PAGE = """ + + + + + Flask + Postgres Demo + + +

Flask + Postgres Demo

+ {% if error %}

{{ error }}

{% endif %} +
+ + +
+ + + {% for row in rows %} + + + + + + {% endfor %} +
IDСодержимоеДействия
{{ row[0] }} +
+ + + +
+
+
+ + +
+
+ + +""" + + +@app.route("/", methods=["GET", "POST"]) +def index(): + ensure_table() + error = None + if request.method == "POST": + content = request.form.get("txt_content") or "Это Flask сделал" + try: + with get_conn() as conn, conn.cursor() as cur: + cur.execute( + "INSERT INTO nubes_test_table (test_data) VALUES (%s)", + (content,), + ) + return redirect("/") + except Exception as exc: + error = str(exc) + with get_conn() as conn, conn.cursor() as cur: + cur.execute( + "SELECT id, test_data FROM nubes_test_table ORDER BY id DESC LIMIT 20" + ) + rows = cur.fetchall() + return render_template_string(PAGE, rows=rows, error=error) + + +@app.post("/update") +def update(): + with get_conn() as conn, conn.cursor() as cur: + cur.execute( + "UPDATE nubes_test_table SET test_data=%s WHERE id=%s", + (request.form.get("txt_content"), request.form.get("id")), + ) + return redirect("/") + + +@app.post("/delete") +def delete(): + with get_conn() as conn, conn.cursor() as cur: + cur.execute("DELETE FROM nubes_test_table WHERE id=%s", (request.form.get("id"),)) + return redirect("/") - return characters_info.get(most_common, {"name": "Неизвестно", "image": "unknown.jpg", "description": "Не удалось определить персонажа."}) - - def run(self): - self.app.run(debug=True, host="0.0.0.0", port=5000) if __name__ == "__main__": - app_instance = BaldursGateQuizApp() - app_instance.run() + app.run(debug=True, host="0.0.0.0", port=5000)