More fixes and additions for forms. We are also haunted by detached sessions constantly.

This commit is contained in:
Yaro Kasear 2025-09-23 13:49:59 -05:00
parent 979a329d6a
commit a3f2c794f5
6 changed files with 160 additions and 49 deletions

View file

@ -1,10 +1,15 @@
from typing import List, Optional, TYPE_CHECKING
from flask import current_app
from sqlalchemy import Boolean, Integer, ForeignKey, Unicode, case, func, literal
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.sql import expression as sql
import crudkit
from crudkit.backend import make_backend_info, sql_trim
from crudkit.core.base import Base, CRUDMixin
if TYPE_CHECKING:
@ -12,6 +17,10 @@ if TYPE_CHECKING:
class User(Base, CRUDMixin):
__tablename__ = 'users'
__crud_label__ = "{label}"
__crudkit_field_requires__ = {
"label": ["first_name", "last_name", "title"] # whatever the hybrid touches
}
first_name: Mapped[Optional[str]] = mapped_column(Unicode(255), nullable=True, index=True)
last_name: Mapped[Optional[str]] = mapped_column(Unicode(255), nullable=True, index=True)
@ -48,17 +57,19 @@ class User(Base, CRUDMixin):
@label.expression
def label(cls):
engine = current_app.extensions["crudkit"]["runtime"].engine
backend = make_backend_info(engine)
first = func.coalesce(cls.first_name, "")
last = func.coalesce(cls.last_name, "")
title = func.coalesce(cls.title, "")
have_first = func.length(func.trim(first)) > 0
have_last = func.length(func.trim(last)) > 0
have_first = func.length(sql_trim(first, backend)) > 0
have_last = func.length(sql_trim(last, backend)) > 0
space = case((have_first & have_last, literal(" ")), else_=literal(""))
title_part = case(
(func.length(func.trim(title)) > 0, func.concat(" (", title, ")")),
(func.length(sql_trim(title, backend)) > 0, func.concat(" (", title, ")")),
else_=literal("")
)

View file

@ -42,7 +42,7 @@ def init_entry_routes(app):
{"name": "owner", "row": "status", "label": "Contact", "wrap": {"class": "col"},
"attrs": {"class": "form-control"}, "label_attrs": {"class": "form-label"},
"label_spec": "{first_name} {last_name}"},
"label_spec": "{label}"},
{"name": "location", "row": "status", "label": "Location", "wrap": {"class": "col"},
"attrs": {"class": "form-control"}, "label_attrs": {"class": "form-label"},
"label_spec": "{name} - {room_function.description}"},
@ -50,8 +50,8 @@ def init_entry_routes(app):
"attrs": {"class": "form-control"}, "label_attrs": {"class": "form-label"}},
{"name": "image", "label": "", "row": "image", "type": "template", "label_spec": "{filename}",
"template": "image_display.html", "attrs": {"class": "img-fluid img-thumbnail h-100"},
"wrap": {"class": "h-100"}},
"template": "image_display.html", "attrs": {"class": "img-fluid img-thumbnail h-auto"},
"wrap": {"class": "h-100 w-100"}},
{"name": "notes", "type": "textarea", "label": "Notes", "row": "notes", "wrap": {"class": "col"},
"attrs": {"class": "form-control", "rows": 10}, "label_attrs": {"class": "form-label"}},
@ -85,7 +85,7 @@ def init_entry_routes(app):
"row": "name", "wrap": {"class": "col-3"}},
{"name": "supervisor", "label": "Supervisor", "label_attrs": {"class": "form-label"},
"label_spec": "{first_name} {last_name}", "row": "details", "wrap": {"class": "col-3"},
"label_spec": "{label}", "row": "details", "wrap": {"class": "col-3"},
"attrs": {"class": "form-control"}},
{"name": "location", "label": "Room", "label_attrs": {"class": "form-label"},
@ -111,7 +111,7 @@ def init_entry_routes(app):
"attrs": {"class": "display-6 mb-3"}, "row": "label"},
{"name": "contact", "row": "ownership", "wrap": {"class": "col"}, "label": "Contact",
"label_spec": "{first_name} {last_name}", "attrs": {"class": "form-control"},
"label_spec": "{label}", "attrs": {"class": "form-control"},
"label_attrs": {"class": "form-label"}},
{"name": "work_item", "row": "ownership", "wrap": {"class": "col"}, "label": "Work Item",
"label_spec": "{label}", "attrs": {"class": "form-control"}, "label_attrs": {"class": "form-label"}},

View file

@ -2,6 +2,5 @@
<img src="{{ url_for('static', filename=field['value_label']) }}" alt="{{ value }}" {% if field['attrs'] %}{% for k,v in
field['attrs'].items() %} {{k}}{% if v is not sameas true %}="{{ v }}" {% endif %} {% endfor %}{% endif %}>
{% else %}
<img src="{{ url_for('static', filename='images/noimage.svg') }}" {% if field['attrs'] %}{% for k,v in field['attrs'].items() %} {{k}}{% if v is not sameas true
%}="{{ v }}" {% endif %} {% endfor %}{% endif %}>
<img src="{{ url_for('static', filename='images/noimage.svg') }}" class="img-fluid img-thumbnail h-100">
{% endif %}