Add Flask Postgres CRUD demo

This commit is contained in:
“Naeel” 2026-02-17 11:12:48 +04:00
parent e0859a05c6
commit 93a0acf36a
4 changed files with 114 additions and 113 deletions

2
.gitignore vendored
View File

@ -1 +1,3 @@
site/templates/
site/static/
venv/ venv/

View File

@ -1,2 +1,4 @@
# Baulder-s-Gate-test # Flask + Postgres Demo
A test to find out who you are from the game Baldur's Gate.
Простое CRUD-приложение на Flask, которое пишет и читает из таблицы `nubes_test_table`.
Если поле ввода пустое, вставляется запись "Это Flask сделал".

View File

@ -1,2 +1,3 @@
Flask==2.0.1 Flask==2.0.1
Werkzeug==2.3.7 Werkzeug==2.3.7
psycopg2-binary==2.9.9

View File

@ -1,121 +1,117 @@
from flask import Flask, render_template, request import os
class BaldursGateQuizApp: import psycopg2
def __init__(self): from flask import Flask, redirect, render_template_string, request
self.app = Flask(__name__, template_folder="templates", static_folder="static")
self.add_routes()
def add_routes(self): app = Flask(__name__)
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)
def index(self):
return render_template("index.html")
def tests(self): def get_conn():
return render_template("tests.html") 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): def ensure_table():
return render_template("about.html") 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 = [ PAGE = """
traits.get(answers.get("question1")), <!doctype html>
roles.get(answers.get("question2")), <html lang="ru">
goals.get(answers.get("question3")), <head>
rules.get(answers.get("question4")), <meta charset="utf-8">
weapons.get(answers.get("question5")), <title>Flask + Postgres Demo</title>
places.get(answers.get("question6")), </head>
mood_fix.get(answers.get("question7")), <body>
colors.get(answers.get("question8")) <h3>Flask + Postgres Demo</h3>
] {% if error %}<p style="color:red">{{ error }}</p>{% endif %}
<form method="post">
<input type="text" name="txt_content" placeholder="Новое сообщение...">
<button type="submit">Добавить</button>
</form>
<table border="1" cellpadding="6" cellspacing="0">
<tr><th>ID</th><th>Содержимое</th><th>Действия</th></tr>
{% for row in rows %}
<tr>
<td>{{ row[0] }}</td>
<td>
<form method="post" action="/update">
<input type="hidden" name="id" value="{{ row[0] }}">
<input type="text" name="txt_content" value="{{ row[1] }}">
<button type="submit">💾</button>
</form>
</td>
<td>
<form method="post" action="/delete" onsubmit="return confirm('Удалить?')">
<input type="hidden" name="id" value="{{ row[0] }}">
<button type="submit">🗑</button>
</form>
</td>
</tr>
{% endfor %}
</table>
</body>
</html>
"""
choices = [choice for choice in choices if choice is not None]
if not choices: @app.route("/", methods=["GET", "POST"])
return {"name": "Неизвестно", "image": "unknown.jpg", "description": "Не удалось определить персонажа."} 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)
most_common = max(set(choices), key=choices.count)
characters_info = { @app.post("/update")
"Минск": {"name": "Минск", "image": "minsk.jpg", "description": "Герой, идущий напролом с верным хомяком Бу"}, def update():
"Гейл": {"name": "Гейл", "image": "gale.jpg", "description": "Могущественный маг, жаждущий знаний и силы"}, with get_conn() as conn, conn.cursor() as cur:
"Карлах": {"name": "Карлах", "image": "karlach.jpg", "description": "Добрая, но грозная воительница"}, cur.execute(
"Астарион": {"name": "Астарион", "image": "astarion.jpeg", "description": "Хитрый вампир, любящий свободу"}, "UPDATE nubes_test_table SET test_data=%s WHERE id=%s",
"Лаэзель": {"name": "Лаэзель", "image": "laezel.jpg", "description": "Жесткая и бескомпромиссная гитянка-воительница"}, (request.form.get("txt_content"), request.form.get("id")),
"Шэдоухарт": {"name": "Шэдоухарт", "image": "shadowheart.jpg", "description": "Таинственная жрица с темным прошлым"}, )
"Хальсин": {"name": "Хальсин", "image": "halsin.jpg", "description": "Мудрый друид, защитник природы."} return redirect("/")
}
return characters_info.get(most_common, {"name": "Неизвестно", "image": "unknown.jpg", "description": "Не удалось определить персонажа."})
def run(self): @app.post("/delete")
self.app.run(debug=True, host="0.0.0.0", port=5000) 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("/")
if __name__ == "__main__": if __name__ == "__main__":
app_instance = BaldursGateQuizApp() app.run(debug=True, host="0.0.0.0", port=5000)
app_instance.run()