use database

development
Thomas Lindner 2023-10-31 01:00:31 +01:00
parent 6e0023497c
commit ca762f41c9
6 changed files with 59 additions and 45 deletions

View File

@ -20,9 +20,11 @@ package_dir =
packages = find:
python_requires = >=3.10
install_requires =
aiosqlite
jinja2
python-multipart
starlette
tortoise-orm
uvicorn[standard]
[options.packages.find]

View File

@ -1,5 +1,3 @@
from uuid import UUID, uuid4
from jinja2 import PackageLoader
from starlette.applications import Starlette
from starlette.requests import Request
@ -7,19 +5,32 @@ from starlette.responses import Response
from starlette.routing import Route, Mount
from starlette.staticfiles import StaticFiles
from starlette.templating import Jinja2Templates
from uvicorn import run
from tortoise import fields, Tortoise
from tortoise.models import Model
from uvicorn import Config, Server
from uvloop import run
class Note(Model):
id = fields.UUIDField(pk=True)
paragraphs: fields.ReverseRelation["Paragraph"]
class Paragraph(Model):
id = fields.UUIDField(pk=True)
note: fields.ForeignKeyRelation[Note] = fields.ForeignKeyField(
"model.Note", related_name="paragraphs"
)
content = fields.TextField(default="")
templates = Jinja2Templates(
directory="/nonexistent", # just a dummy, FileSystemLoader is not used
loader=PackageLoader("wikinotes"),
)
notes: dict[UUID, list[UUID]] = {}
paragraphs: dict[UUID, str] = {}
async def home(request: Request) -> Response:
only_body = request.headers.get("hx-request", "false") == "true"
return templates.TemplateResponse(
"home.html",
headers={
@ -27,89 +38,79 @@ async def home(request: Request) -> Response:
},
context={
"request": request,
"only_body": only_body,
},
)
async def create_note(request: Request) -> Response:
note_id = uuid4()
notes[note_id] = []
note = await Note.create()
await note.fetch_related("paragraphs")
return templates.TemplateResponse(
"note.html",
headers={
"HX-Push-Url": str(request.url_for("note", note_id=note_id)),
"HX-Push-Url": str(request.url_for("note", note_id=note.id)),
},
context={
"request": request,
"only_body": True,
"note_id": note_id,
"paragraphs": [],
"note": note,
},
)
async def note(request: Request) -> Response:
note_id = request.path_params["note_id"]
only_body = request.headers.get("hx-request", "false") == "true"
note = await Note.get(id=request.path_params["note_id"])
await note.fetch_related("paragraphs")
return templates.TemplateResponse(
"note.html",
headers={
"HX-Push-Url": str(request.url_for("note", note_id=note_id)),
"HX-Push-Url": str(request.url_for("note", note_id=note.id)),
},
context={
"request": request,
"only_body": only_body,
"note_id": note_id,
"paragraphs": [(id, paragraphs[id]) for id in notes[note_id]],
"note": note,
},
)
async def create_paragraph(request: Request) -> Response:
note_id = request.path_params["note_id"]
paragraph_id = uuid4()
note = await Note.get(id=request.path_params["note_id"])
async with request.form() as form:
paragraphs[paragraph_id] = str(form["content"])
notes[note_id] = [paragraph_id]
paragraph = await Paragraph.create(note=note, content=str(form["content"]))
return templates.TemplateResponse(
"paragraph.html",
context={
"request": request,
"note_id": note_id,
"paragraph_id": paragraph_id,
"content": paragraphs[paragraph_id],
"note": note,
"paragraph": paragraph,
},
)
async def paragraph(request: Request) -> Response:
note_id = request.path_params["note_id"]
paragraph_id = request.path_params["paragraph_id"]
note = await Note.get(id=request.path_params["note_id"])
paragraph = await Paragraph.get(id=request.path_params["paragraph_id"])
if request.method == "PUT":
async with request.form() as form:
paragraphs[paragraph_id] = str(form["content"])
await paragraph.update_from_dict({"content": str(form["content"])}).save()
return templates.TemplateResponse(
"paragraph.html",
context={
"request": request,
"note_id": note_id,
"paragraph_id": paragraph_id,
"content": paragraphs[paragraph_id],
"note": note,
"paragraph": paragraph,
},
)
async def edit_paragraph(request: Request) -> Response:
note_id = request.path_params["note_id"]
paragraph_id = request.path_params["paragraph_id"]
note = await Note.get(id=request.path_params["note_id"])
paragraph = await Paragraph.get(id=request.path_params["paragraph_id"])
return templates.TemplateResponse(
"edit.html",
context={
"request": request,
"note_id": note_id,
"paragraph_id": paragraph_id,
"content": paragraphs[paragraph_id],
"note": note,
"paragraph": paragraph,
},
)
@ -147,5 +148,16 @@ app = Starlette(
)
async def async_main() -> None:
await Tortoise.init(db_url="sqlite://:memory:", modules={"model": ["wikinotes"]})
await Tortoise.generate_schemas()
config = Config("wikinotes:app", port=8080, log_level="info")
server = Server(config)
await server.serve()
await Tortoise.close_connections()
def main() -> None:
run("wikinotes:app", port=8080, log_level="info")
run(async_main())

View File

@ -1,4 +1,4 @@
{% if not only_body %}
{% if request.headers.get("hx-request", "false") != "true" %}
{% extends "base.html" %}
{% endif %}
{% block body %}

View File

@ -1,5 +1,5 @@
<form hx-put="{{ url_for("paragraph", note_id=note_id, paragraph_id=paragraph_id) }}" hx-target="this" hx-swap="outerHTML">
<textarea class="form-control mb-3" name="content" rows="10" autofocus>{{ content }}</textarea>
<form hx-put="{{ url_for("paragraph", note_id=note.id, paragraph_id=paragraph.id) }}" hx-target="this" hx-swap="outerHTML">
<textarea class="form-control mb-3" name="content" rows="10" autofocus>{{ paragraph.content }}</textarea>
<button class="btn btn-primary">Submit</button>
<button class="btn" hx-get="{{ url_for("paragraph", note_id=note_id, paragraph_id=paragraph_id) }}">Cancel</button>
<button class="btn" hx-get="{{ url_for("paragraph", note_id=note.id, paragraph_id=paragraph.id) }}">Cancel</button>
</form>

View File

@ -5,10 +5,10 @@
</div>
{% endblock %}
{% block main %}
{% for paragraph_id, content in paragraphs %}
{% for paragraph in note.paragraphs %}
{% include "paragraph.html" %}
{% else %}
<form hx-post="{{ url_for("create_paragraph", note_id=note_id) }}" hx-target="this" hx-swap="outerHTML">
<form hx-post="{{ url_for("create_paragraph", note_id=note.id) }}" hx-target="this" hx-swap="outerHTML">
<textarea class="form-control mb-3" name="content" rows="10" autofocus></textarea>
<button class="btn btn-primary">Submit</button>
</form>

View File

@ -1 +1 @@
<p class="editable" title="Click to edit" hx-get="{{ url_for("edit_paragraph", note_id=note_id, paragraph_id=paragraph_id) }}" hx-target="this" hx-swap="outerHTML">{{ content }}</p>
<p class="editable" title="Click to edit" hx-get="{{ url_for("edit_paragraph", note_id=note.id, paragraph_id=paragraph.id) }}" hx-target="this" hx-swap="outerHTML">{{ paragraph.content }}</p>