Hey there!
As stated #34864 that is a duplicate of #29490 people wanted to be able to add more functionality specially to the js
attribute of the Media
class on forms/widgets. And i think that this was a great addition on 4.1
.
The documentation on this addition was really narrow and didn’t cover a “useful” use case and also contains a invalid attribute to the script tag (rel
is not valid for a script tag). So i wonder if i should open a ticket to state this problem?
And another thing is that i still think that we could perhaps have a more simple way for people wanting this behavior. I myself just needed this feature, and had to implement it on my own, just to add a defer
attribute to a script tag. If the said ticket is open i would be happy to had a more “useful” example, or even, add this to the django project itself. Below is my initial implementation of a custom Js Path that is “smarter” and more flexible.
# python 3.11
from django.utils.html import html_safe
from django.templatetags.static import static
@html_safe
class JsScriptMedia:
"""An object that can be used in Media classes to define additional attributes to the script tag"""
def __init__(
self,
src: str,
*,
async_: bool = False,
defer: bool = False,
cross_origin: str | None = None,
integrity: str | None = None,
type: str | None = None,
):
if src.startswith(("http://", "https://", "/")):
self.src = src
else:
self.src = static(src)
self.async_ = async_
self.defer = defer
self.cross_origin = cross_origin
self.integrity = integrity
self.type = type
self.attrs = []
named_attr_values = {
"src": self.src,
"crossorigin": self.cross_origin,
"integrity": self.integrity,
"type": self.type,
}
for attr, value in named_attr_values.items():
if value is not None:
self.attrs.append(f'{attr}="{value}"')
bool_attr_values = {
"defer": self.defer,
"async": self.async_,
}
for attr, value in bool_attr_values.items():
if value:
self.attrs.append(attr)
def __str__(self):
return f'<script src="{self.src}" {" ".join(self.attrs)}></script>'
Edit:
Almost forgot, here’s how this class can be used:
from django import forms
class SomeForm(forms.Form):
class Media:
js = [JsScriptMedia("https://code.jquery.com/jquery-3.3.1.min.js", defer=True)]
I believe that the above snippet may also need some improvements if added to the Django codebase, like validating the crossorigin possible values.
Again, thanks for adding the feature that allowed this behavior.
Cheers!