diff --git a/crudkit/html/templates/crudkit/_macros.html b/crudkit/html/templates/crudkit/_macros.html
index bac6692..127ba0b 100644
--- a/crudkit/html/templates/crudkit/_macros.html
+++ b/crudkit/html/templates/crudkit/_macros.html
@@ -56,7 +56,7 @@
{% else %}
-
{{ label }}
@@ -103,18 +103,6 @@
-
- {# keep hidden pager-state in sync with one handler instead of inline click spam #}
-
{%- endmacro %}
{% macro form(schema, action, method="POST", obj_id=None, hx=False, csrf_token=None) -%}
diff --git a/crudkit/service.py b/crudkit/service.py
index a62ae18..b45a0e2 100644
--- a/crudkit/service.py
+++ b/crudkit/service.py
@@ -56,7 +56,7 @@ def _apply_dotted_ordering(stmt, Model, sort_tokens):
rel = current_mapper.relationships.get(rel_name)
if rel is None:
# invalid sort key; skip quietly or raise
- # raise ValueError(f"Unknown relationship {current_mapper.class_.__name__}.{rel_name}")
+ print(f"Unknown relationship {current_mapper.class_.__name__}.{rel_name}")
entity = None
break
@@ -78,13 +78,20 @@ def _apply_dotted_ordering(stmt, Model, sort_tokens):
continue
col_name = parts[-1]
- # Validate final column
- if col_name not in current_mapper.columns:
- # raise ValueError(f"Unknown column {current_mapper.class_.__name__}.{col_name}")
- continue
+ # # Validate final column
+ # if col_name not in current_mapper.columns:
+ # print(f"Unknown column {current_mapper.class_.__name__}.{col_name}")
+ # continue
- col = getattr(entity, col_name) if entity is not Model else getattr(Model, col_name)
- stmt = stmt.order_by(col.desc() if direction == "desc" else col.asc())
+ # col = getattr(entity, col_name) if entity is not Model else getattr(Model, col_name)
+
+ attr = getattr(entity, col_name, None)
+ if attr is None:
+ attr = getattr(current_mapper.class_, col_name, None)
+ if attr is None:
+ print(f"Unknown column {current_mapper.class_.__name__}.{col_name}")
+ continue
+ stmt = stmt.order_by(attr.desc() if direction == "desc" else attr.asc())
return stmt
diff --git a/inventory/models/__init__.py b/inventory/models/__init__.py
index 83d2e78..5d6208e 100644
--- a/inventory/models/__init__.py
+++ b/inventory/models/__init__.py
@@ -29,22 +29,9 @@ worklog_images = image_links.worklog_images
User = users.User
# Now it’s safe to configure mappers and set global eagerloads
-from sqlalchemy.orm import configure_mappers, joinedload, selectinload
+from sqlalchemy.orm import configure_mappers
configure_mappers()
-User.ui_eagerload = (
- joinedload(User.supervisor),
- joinedload(User.location).joinedload(Room.room_function),
-)
-
-Room.ui_eagerload = (
- joinedload(Room.area),
- joinedload(Room.room_function),
- selectinload(Room.inventory),
- selectinload(Room.users)
-)
-
-
registry = {
"area": Area,
"brand": Brand,
diff --git a/inventory/models/rooms.py b/inventory/models/rooms.py
index 0f8df32..e65c62e 100644
--- a/inventory/models/rooms.py
+++ b/inventory/models/rooms.py
@@ -1,12 +1,13 @@
from typing import Optional, TYPE_CHECKING, List
if TYPE_CHECKING:
from .areas import Area
- from .room_functions import RoomFunction
from .inventory import Inventory
from .users import User
+from .room_functions import RoomFunction
from crudkit import CrudMixin
-from sqlalchemy import ForeignKey, Identity, Integer, Unicode
+from sqlalchemy import ForeignKey, Identity, Integer, Unicode, func, select, literal
+from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import Mapped, mapped_column, relationship
from . import db
@@ -27,18 +28,6 @@ class Room(db.Model, CrudMixin):
ui_eagerload = tuple()
ui_extra_attrs = ('area_id', 'function_id')
- @classmethod
- def ui_update(cls, session, id_, payload):
- print(payload)
- obj = session.get(cls, id_)
- if not obj:
- return None
- obj.name = payload.get("name", obj.name)
- obj.area_id = payload.get("area_id", obj.area_id)
- obj.function_id = payload.get("function_id", obj.function_id)
- session.commit()
- return obj
-
def __init__(self, name: Optional[str] = None, area_id: Optional[int] = None, function_id: Optional[int] = None):
self.name = name
self.area_id = area_id
@@ -47,8 +36,22 @@ class Room(db.Model, CrudMixin):
def __repr__(self):
return f""
- @property
+ @hybrid_property
def identifier(self):
name = self.name or ""
- func = self.room_function.description if self.room_function else ""
- return f"{name} - {func}".strip(" -")
+ function = self.room_function.description if self.room_function else ""
+ return f"{name} - {function}".strip(" -")
+
+ @identifier.expression
+ def identifier(cls):
+ rf_desc = (
+ select(RoomFunction.description)
+ .where(RoomFunction.id == cls.function_id)
+ .correlate(cls)
+ .scalar_subquery()
+ )
+ return func.concat(
+ func.coalesce(cls.name, ''), # left part
+ literal(' - '), # separator
+ func.coalesce(rf_desc, '') # right part via correlated subquery
+ )
diff --git a/inventory/templates/fragments/_table_fragment.html b/inventory/templates/fragments/_table_fragment.html
index ff84d69..b20559b 100644
--- a/inventory/templates/fragments/_table_fragment.html
+++ b/inventory/templates/fragments/_table_fragment.html
@@ -70,7 +70,9 @@ refresh_url=none, model=none, sort=none) %}
{% for h in headers %}
- | {{ h }} |
+ {{ h }} |
{% endfor %}
@@ -82,7 +84,7 @@ refresh_url=none, model=none, sort=none) %}
- {% if sort %}{% endif %}
+
{% for k,v in (filters or {}).items() %}
{% endfor %}
@@ -90,4 +92,31 @@ refresh_url=none, model=none, sort=none) %}
+
+{# keep hidden pager-state in sync with one handler instead of inline click spam #}
+
+
{% endmacro %}
\ No newline at end of file