More fixes and additions for forms. We are also haunted by detached sessions constantly.
This commit is contained in:
parent
979a329d6a
commit
a3f2c794f5
6 changed files with 160 additions and 49 deletions
|
|
@ -54,15 +54,30 @@ def _get_loaded_attr(obj: Any, name: str) -> Any:
|
|||
"""
|
||||
try:
|
||||
st = inspect(obj)
|
||||
# 1) Mapped attribute?
|
||||
attr = st.attrs.get(name)
|
||||
if attr is not None:
|
||||
val = attr.loaded_value
|
||||
return None if val is NO_VALUE else val
|
||||
# 2) Already present value (e.g., eager-loaded or set on the dict)?
|
||||
if name in st.dict:
|
||||
return st.dict.get(name)
|
||||
return getattr(obj, name, None)
|
||||
# 3) If object is detached or attr is not mapped, DO NOT eval hybrids
|
||||
# or descriptors that could lazy-load. That would explode.
|
||||
if st.session is None:
|
||||
return None
|
||||
# 4) As a last resort on attached instances only, try simple getattr,
|
||||
# but guard against DetachedInstanceError anyway.
|
||||
try:
|
||||
return getattr(obj, name, None)
|
||||
except Exception:
|
||||
return None
|
||||
except Exception:
|
||||
return getattr(obj, name, None)
|
||||
# If we can't even inspect it, be conservative
|
||||
try:
|
||||
return getattr(obj, name, None)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def _normalize_rows_layout(layout: Optional[List[dict]]) -> Dict[str, dict]:
|
||||
"""
|
||||
|
|
@ -293,7 +308,21 @@ def _value_label_for_field(field: dict, mapper, values_map: dict, instance, sess
|
|||
rel_obj = q.get(rid)
|
||||
|
||||
if rel_obj is not None:
|
||||
return _label_from_obj(rel_obj, label_spec)
|
||||
try:
|
||||
s = _label_from_obj(rel_obj, label_spec)
|
||||
except Exception:
|
||||
s = None
|
||||
# If we couldn't safely render and we have a session+id, do one lean retry.
|
||||
if (s is None or s == "") and session is not None and rid is not None:
|
||||
mdl = rel_prop.mapper.class_
|
||||
try:
|
||||
rel_obj2 = session.get(mdl, rid) # attached instance
|
||||
s2 = _label_from_obj(rel_obj2, label_spec)
|
||||
if s2:
|
||||
return s2
|
||||
except Exception:
|
||||
pass
|
||||
return s
|
||||
return str(rid) if rid is not None else None
|
||||
|
||||
class _SafeObj:
|
||||
|
|
@ -406,7 +435,7 @@ def _fk_options(session, related_model, label_spec):
|
|||
if simple_cols:
|
||||
first = simple_cols[0]
|
||||
if hasattr(related_model, first):
|
||||
q = q.order_by(getattr(related_model, first))
|
||||
q = q.order_by(None).order_by(getattr(related_model, first))
|
||||
|
||||
rows = q.all()
|
||||
return [
|
||||
|
|
@ -559,7 +588,10 @@ def _label_from_obj(obj: Any, spec: Any) -> str:
|
|||
for f in fields:
|
||||
root = f.split(".", 1)[0]
|
||||
if root not in data:
|
||||
data[root] = _SafeObj(_get_loaded_attr(obj, root))
|
||||
try:
|
||||
data[root] = _SafeObj(_get_loaded_attr(obj, root))
|
||||
except Exception:
|
||||
data[root] = _SafeObj(None)
|
||||
try:
|
||||
return spec.format(**data)
|
||||
except Exception:
|
||||
|
|
@ -1007,11 +1039,6 @@ def render_form(
|
|||
base.update(f.get("template_ctx") or {})
|
||||
f["template_ctx"] = base
|
||||
|
||||
for f in fields:
|
||||
vl = _value_label_for_field(f, mapper, values_map, instance, session)
|
||||
if vl is not None:
|
||||
f["value_label"] = vl
|
||||
|
||||
for f in fields:
|
||||
# existing FK label resolution
|
||||
vl = _value_label_for_field(f, mapper, values_map, instance, session)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue