Files
maria_flask/site/app.py
T
2026-10-02 11:47:52 +03:00

148 lines
5.2 KiB
Python

"""
app.py — Flask CRUD-интерфейс для MariaDB.
Переменные окружения (из json_env):
- DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD — подключение к БД
- TABLE_NAME — имя таблицы (по умолчанию crud_items)
При старте: CREATE TABLE IF NOT EXISTS (БЕЗ DROP).
"""
import os
import re
import pymysql
from flask import Flask, render_template, request, redirect, url_for, g
VERSION = "1.0.0"
TABLE_NAME = os.environ.get("TABLE_NAME", "crud_items")
if not re.fullmatch(r"[A-Za-z_][A-Za-z0-9_]*", TABLE_NAME):
raise ValueError("TABLE_NAME must be a simple SQL identifier")
TABLE_SQL = f"`{TABLE_NAME}`"
# SERVICE_NAME — какое приложение добавило строку (колонка created_by).
# Задаётся в json_env манифеста отдельно для каждого сервиса (flask / lucee / nodejs),
# чтобы три приложения, пишущие в ОДНУ таблицу, были различимы.
SERVICE_NAME = os.environ.get("SERVICE_NAME", "flask")
app = Flask(__name__)
def get_db():
"""Ленивое подключение к MariaDB. Один коннект на запрос."""
if "db" not in g:
g.db = pymysql.connect(
host=os.environ.get("DB_HOST", "127.0.0.1"),
port=int(os.environ.get("DB_PORT", "3306")),
database=os.environ.get("DB_NAME", "maria"),
user=os.environ.get("DB_USER", ""),
password=os.environ.get("DB_PASSWORD", ""),
charset="utf8mb4",
cursorclass=pymysql.cursors.DictCursor,
connect_timeout=5,
autocommit=True,
)
return g.db
def init_db():
"""Создать таблицу, если её нет, и досыпать новые колонки.
Таблица выставочная — кроме id/value храним только две метки:
created_at — когда строка добавлена (ставит сама СУБД);
created_by — какое приложение её добавило (flask / lucee / nodejs).
ALTER TABLE ... ADD COLUMN IF NOT EXISTS нужен, чтобы таблица, созданная
предыдущей версией приложения, получила новые колонки без потери данных.
"""
db = get_db()
cur = db.cursor()
cur.execute(
f"""
CREATE TABLE IF NOT EXISTS {TABLE_SQL} (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`value` TEXT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_by VARCHAR(255) NOT NULL DEFAULT ''
)
"""
)
cur.execute(
f"ALTER TABLE {TABLE_SQL} ADD COLUMN IF NOT EXISTS created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP"
)
cur.execute(
f"ALTER TABLE {TABLE_SQL} ADD COLUMN IF NOT EXISTS created_by VARCHAR(255) NOT NULL DEFAULT ''"
)
cur.close()
@app.teardown_appcontext
def close_db(exc):
db = g.pop("db", None)
if db is not None:
db.close()
@app.route("/", methods=["GET", "POST"])
def index():
db = get_db()
cur = db.cursor()
# --- Обработка POST (create / update / delete) — POST-redirect-GET ---
if request.method == "POST":
action = request.form.get("action", "")
if action == "create":
# created_at ставит СУБД (DEFAULT now()), created_by — имя этого сервиса
cur.execute(
f"INSERT INTO {TABLE_SQL} (`value`, created_by) VALUES (%s, %s)",
(request.form.get("value", ""), SERVICE_NAME),
)
elif action == "update":
cur.execute(
f"UPDATE {TABLE_SQL} SET `value` = %s WHERE id = %s",
(request.form.get("value", ""), int(request.form.get("id", 0))),
)
elif action == "delete":
cur.execute(
f"DELETE FROM {TABLE_SQL} WHERE id = %s",
(int(request.form.get("id", 0)),),
)
cur.close()
return redirect(url_for("index"))
# --- GET: список + форма редактирования ---
edit_row = None
edit_id = request.args.get("edit")
if edit_id:
cur.execute(
f"SELECT id, `value`, created_at, created_by FROM {TABLE_SQL} WHERE id = %s",
(int(edit_id),),
)
row = cur.fetchone()
if row:
edit_row = dict(row)
# Список всех записей — вместе с метками «когда» и «кем» добавлено
cur.execute(f"SELECT id, `value`, created_at, created_by FROM {TABLE_SQL} ORDER BY id")
rows = cur.fetchall()
cur.close()
return render_template(
"index.html",
table_name=TABLE_NAME,
rows=rows,
edit_row=edit_row,
version=VERSION,
)
# --- Инициализация БД при старте (до первого запроса) ---
with app.app_context():
init_db()
if __name__ == "__main__":
app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 5000)), debug=False)