Add Flask Postgres CRUD demo
This commit is contained in:
parent
e0859a05c6
commit
93a0acf36a
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1,3 @@
|
|||||||
|
site/templates/
|
||||||
|
site/static/
|
||||||
venv/
|
venv/
|
||||||
@ -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 сделал".
|
||||||
@ -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
|
||||||
216
site/app.py
216
site/app.py
@ -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">
|
||||||
choices = [choice for choice in choices if choice is not None]
|
<input type="text" name="txt_content" placeholder="Новое сообщение...">
|
||||||
|
<button type="submit">Добавить</button>
|
||||||
if not choices:
|
</form>
|
||||||
return {"name": "Неизвестно", "image": "unknown.jpg", "description": "Не удалось определить персонажа."}
|
<table border="1" cellpadding="6" cellspacing="0">
|
||||||
|
<tr><th>ID</th><th>Содержимое</th><th>Действия</th></tr>
|
||||||
most_common = max(set(choices), key=choices.count)
|
{% for row in rows %}
|
||||||
|
<tr>
|
||||||
characters_info = {
|
<td>{{ row[0] }}</td>
|
||||||
"Минск": {"name": "Минск", "image": "minsk.jpg", "description": "Герой, идущий напролом с верным хомяком Бу"},
|
<td>
|
||||||
"Гейл": {"name": "Гейл", "image": "gale.jpg", "description": "Могущественный маг, жаждущий знаний и силы"},
|
<form method="post" action="/update">
|
||||||
"Карлах": {"name": "Карлах", "image": "karlach.jpg", "description": "Добрая, но грозная воительница"},
|
<input type="hidden" name="id" value="{{ row[0] }}">
|
||||||
"Астарион": {"name": "Астарион", "image": "astarion.jpeg", "description": "Хитрый вампир, любящий свободу"},
|
<input type="text" name="txt_content" value="{{ row[1] }}">
|
||||||
"Лаэзель": {"name": "Лаэзель", "image": "laezel.jpg", "description": "Жесткая и бескомпромиссная гитянка-воительница"},
|
<button type="submit">💾</button>
|
||||||
"Шэдоухарт": {"name": "Шэдоухарт", "image": "shadowheart.jpg", "description": "Таинственная жрица с темным прошлым"},
|
</form>
|
||||||
"Хальсин": {"name": "Хальсин", "image": "halsin.jpg", "description": "Мудрый друид, защитник природы."}
|
</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>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@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__":
|
if __name__ == "__main__":
|
||||||
app_instance = BaldursGateQuizApp()
|
app.run(debug=True, host="0.0.0.0", port=5000)
|
||||||
app_instance.run()
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user