sless-primer/POSTGRES/code/table-rw/table_rw.py
2026-03-19 10:29:26 +04:00

131 lines
5.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 2026-03-19
# table_rw.py — чтение и запись строк в terraform_demo_table.
# Два entrypoint в одном файле: list_rows (JSON API) и add_row (HTML-страница + POST-обработчик).
# ENV: PGHOST, PGPORT, PGDATABASE, PGUSER, PGPASSWORD, PGSSLMODE
import os
import json
import psycopg2
import psycopg2.extras
def _connect():
return psycopg2.connect(
host=os.environ["PGHOST"],
port=os.environ.get("PGPORT", "5432"),
dbname=os.environ["PGDATABASE"],
user=os.environ["PGUSER"],
password=os.environ["PGPASSWORD"],
sslmode=os.environ.get("PGSSLMODE", "require"),
)
def list_rows(event):
# Возвращает все строки terraform_demo_table, отсортированные по убыванию created_at.
conn = _connect()
try:
cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
cur.execute(
"SELECT id, title, created_at::text FROM terraform_demo_table ORDER BY created_at DESC"
)
rows = [dict(r) for r in cur.fetchall()]
return {"rows": rows, "count": len(rows)}
finally:
conn.close()
def _render_page(rows, message=""):
# HTML-страница с формой ввода и таблицей строк.
# message — статус последней операции (успех / ошибка).
rows_html = "".join(
f"<tr><td>{r['id']}</td><td>{r['title']}</td><td>{r['created_at']}</td></tr>"
for r in rows
)
msg_html = f'<p class="msg">{message}</p>' if message else ""
return f"""<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>pg-table-writer</title>
<style>
body {{ font-family: sans-serif; max-width: 700px; margin: 40px auto; background: #111; color: #eee; }}
h1 {{ color: #7dd3fc; }}
form {{ display: flex; gap: 8px; margin-bottom: 24px; }}
input[type=text] {{ flex: 1; padding: 8px 12px; border-radius: 6px; border: 1px solid #444; background: #1e1e1e; color: #eee; font-size: 15px; }}
button {{ padding: 8px 18px; background: #2563eb; color: #fff; border: none; border-radius: 6px; cursor: pointer; font-size: 15px; }}
button:hover {{ background: #1d4ed8; }}
table {{ width: 100%; border-collapse: collapse; }}
th, td {{ padding: 8px 10px; border-bottom: 1px solid #333; text-align: left; }}
th {{ color: #7dd3fc; }}
.msg {{ color: #4ade80; margin-bottom: 12px; }}
</style>
</head>
<body>
<h1>pg-table-writer</h1>
<form method="POST">
<input type="text" name="title" placeholder="Введите строку..." autofocus required>
<button type="submit">Добавить</button>
</form>
{msg_html}
<table>
<thead><tr><th>#</th><th>title</th><th>created_at</th></tr></thead>
<tbody>{rows_html}</tbody>
</table>
</body>
</html>"""
def add_row(event):
# GET → HTML-страница с формой и списком строк.
# POST → вставляет строку из form-поля title или JSON-поля title,
# затем возвращает обновлённую HTML-страницу.
# POST с Content-Type: application/json (curl/API) → возвращает JSON.
method = event.get("_method", "GET")
if method == "GET":
conn = _connect()
try:
cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
cur.execute("SELECT id, title, created_at::text FROM terraform_demo_table ORDER BY created_at DESC")
rows = [dict(r) for r in cur.fetchall()]
finally:
conn.close()
return _render_page(rows)
# POST — вставка строки
# Поле title приходит либо из JSON-тела, либо из application/x-www-form-urlencoded.
# Сервер уже распарсил JSON в event; form-данные приходят как event["body"] = "title=...".
title = event.get("title", "").strip()
if not title:
# Попытка распарсить form-encoded body (браузерная форма)
body = event.get("body", "")
if body.startswith("title="):
from urllib.parse import unquote_plus
title = unquote_plus(body[len("title="):].split("&")[0]).strip()
if not title:
return {"ok": False, "error": "title is required"}
conn = _connect()
try:
cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
cur.execute(
"INSERT INTO terraform_demo_table (title) VALUES (%s) RETURNING id, title, created_at::text",
(title,),
)
row = dict(cur.fetchone())
conn.commit()
# Если запрос из браузера (form POST) — возвращаем обновлённую страницу.
# Если из curl/API — возвращаем JSON.
accept = event.get("_accept", "")
if "application/json" in accept:
return {"ok": True, "row": row}
# Перечитываем все строки для обновлённой страницы
cur.execute("SELECT id, title, created_at::text FROM terraform_demo_table ORDER BY created_at DESC")
rows = [dict(r) for r in cur.fetchall()]
return _render_page(rows, message=f"Добавлено: «{row['title']}»")
finally:
conn.close()