Hi Djangonauts, I’m working on a library (similar to Iommi) and found that django.forms.utils.flatatt is adding ~100ms of overhead when rendering thousands of elements in a table. I’m considering using the following custom implementation for better performance, since Python 3.7+ dicts are ordered, I’m skipping sorted()
_is_valid_key = re.compile(r"^[a-zA-Z0-9\-_@:\.]+$").match
def _render_attrs(attrs: dict[str, Any]) -> SafeString:
if not attrs:
return mark_safe("")
chunks = []
for key, value in attrs.items():
if not _is_valid_key(key):
raise ValueError(f"Invalid attribute name: {key}")
if value is None or value is False:
continue
if value is True:
chunks.append(f" {key}")
continue
chunks.append(f' {key}="{conditional_escape(value)}"')
return mark_safe("".join(chunks))
- are there
flatattedge cases this would break? - Also can I replace conditional escape with the following snippet I copied from Iommi? I’m building a similar library where attrs are defined by developers at the code level.
# replacing: chunks.append(f' {key}="{conditional_escape(value)}"')
if isinstance(value, Promise):
value = str(value)
if hasattr(value, "__html__"):
v = value.__html__()
else:
v = f"{value}".replace("&", "&").replace('"', """)
chunks.append(f' {key}="{v}"')
Given that these attributes will be mostly developer-defined, is this ok, or is conditional_escape the non-negotiable standard here?
I’ve added a regex check (_is_valid_key) for the attribute keys. In my profiling, this only adds about 10ms of overhead, which I find acceptable for the added safety. I noticed flatatt itself doesn’t escape keys but I am concerned I might be missing some context that allows Django to skips it. can I skip key escaping?
Appreciate any insights!