From e98f82dced23012a4de5856dca6a9e05733322f1 Mon Sep 17 00:00:00 2001 From: Padreug Date: Sat, 9 May 2026 07:02:40 +0200 Subject: [PATCH] fix(views): make Restaurant JSON-safe before passing to Jinja All four CMS pages (menu / orders / kds / settings) crashed with TypeError: JSONEncoder.default() missing 1 required positional argument: 'o' because templates do `{{ restaurant | tojson | safe }}`. `tojson` runs Python's stdlib `json.JSONEncoder` which can't serialize the `datetime` on `Restaurant.time` (or any other datetime nested in the model). The browser saw '500 / 'o'' (KeyError-flavored). Pydantic v1's .json() handles datetime correctly (ISO 8601). New helper _restaurant_jsonable rounds-trips the Restaurant via .json() + json.loads() and returns a fully JSON-safe dict, then all four view handlers pass that instead of restaurant.dict(). --- views.py | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/views.py b/views.py index 33825f1..ec6451f 100644 --- a/views.py +++ b/views.py @@ -15,6 +15,7 @@ Pages All pages require a logged-in LNbits user (check_user_exists). """ +import json from http import HTTPStatus from fastapi import APIRouter, Depends, Request @@ -26,6 +27,7 @@ from lnbits.decorators import check_user_exists from lnbits.helpers import template_renderer from .crud import get_restaurant_by_slug +from .models import Restaurant restaurant_generic_router = APIRouter() @@ -34,6 +36,21 @@ def restaurant_renderer(): return template_renderer(["restaurant/templates"]) +def _restaurant_jsonable(restaurant: Restaurant) -> dict: + """ + Convert a Restaurant pydantic model to a plain JSON-serializable + dict for Jinja's `tojson` filter. + + `restaurant.dict()` returns a dict with a `datetime` on `time`, + which Python's stdlib `JSONEncoder` (used by Jinja `tojson`) can't + serialize — it errors out as + TypeError: JSONEncoder.default() missing 1 required positional argument: 'o' + Pydantic v1's `.json()` knows how to serialize datetime as + ISO-8601, so we round-trip via JSON to get a clean dict. + """ + return json.loads(restaurant.json()) + + @restaurant_generic_router.get("/", response_class=HTMLResponse) async def index(request: Request, user: User = Depends(check_user_exists)): return restaurant_renderer().TemplateResponse( @@ -56,7 +73,7 @@ async def menu_builder( { "request": request, "user": user.json(), - "restaurant": restaurant.dict(), + "restaurant": _restaurant_jsonable(restaurant), }, ) @@ -75,7 +92,7 @@ async def orders( { "request": request, "user": user.json(), - "restaurant": restaurant.dict(), + "restaurant": _restaurant_jsonable(restaurant), }, ) @@ -94,7 +111,7 @@ async def kds( { "request": request, "user": user.json(), - "restaurant": restaurant.dict(), + "restaurant": _restaurant_jsonable(restaurant), }, ) @@ -113,6 +130,6 @@ async def settings_page( { "request": request, "user": user.json(), - "restaurant": restaurant.dict(), + "restaurant": _restaurant_jsonable(restaurant), }, )