How to add script type="module" in django admin
Question:
If I want some javascript functionality in my Django admin, I usually go about it using the Media
class like this:
@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
class Media:
js = ('js/my_script.js',)
But I now have a script that is a ES6 module so I would like Django to render it like:
<script src="path/to/static/js/my_script" type="module"></script>
and using the Media
class doesn’t render the type="module"
attribute.
Any help or tips to achieve this? Thanks
Answers:
In your custom change_form.html template, extend the admin_change_form_document_ready block and add the event listener code
{% extends 'admin/change_form.html' %}
{% load static %}
{% block admin_change_form_document_ready %}
{{ block.super }}
<script type="text/javascript" src="{% static 'app/your_file.js' %}"></script>
{% endblock %}
You won’t be able to use Media
class for this, if you check at the code, the method will always render the same type="text/javascript"
.
If you really want to go with the Media
way, you could create your own Media
class and inherit from forms.Media
, then you could try using Media
as a dynamic property that would be able to generate a script with type="module"
.
Another option is to use a custom template as suggested before, or even considering adding a templatetag to your app in order to add ES6 modules in your template.
@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
class Media:
module = ('js/my_script.js',)
You can just change js to replace module its define is type of src
It‘s working for me.
We can overwrite the Media.render_js
to add anything we want to add to tag.
from django.forms.widgets import Media
def render_js(self) -> List[str]:
script_js = []
for path in self._js:
module_mark = ""
# Put your own condition here, in my case it generates
# <script type="module" src="http://localhost:5173/@vite/client"></script>
# and <script type="module" src="http://localhost:5173/src/custom_admin.ts"></script>
# into head scripts
if isinstance(path, str) and (
"custom_admin" in path or "@vite/client" in path
):
module_mark = ' type="module"'
js = format_html(
'<script%s src="{}"></script>' % module_mark,
self.absolute_path(path),
)
script_js.append(js)
return script_js
Media.render_js = render_js
class MyModelAdmin(admin.ModelAdmin):
class Media:
js = (
"http://localhost:5173/@vite/client",
"http://localhost:5173/src/custom_admin.ts",
)
Just adjust above code to adapt your logic and add it to your admin.py.
If I want some javascript functionality in my Django admin, I usually go about it using the Media
class like this:
@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
class Media:
js = ('js/my_script.js',)
But I now have a script that is a ES6 module so I would like Django to render it like:
<script src="path/to/static/js/my_script" type="module"></script>
and using the Media
class doesn’t render the type="module"
attribute.
Any help or tips to achieve this? Thanks
In your custom change_form.html template, extend the admin_change_form_document_ready block and add the event listener code
{% extends 'admin/change_form.html' %}
{% load static %}
{% block admin_change_form_document_ready %}
{{ block.super }}
<script type="text/javascript" src="{% static 'app/your_file.js' %}"></script>
{% endblock %}
You won’t be able to use Media
class for this, if you check at the code, the method will always render the same type="text/javascript"
.
If you really want to go with the Media
way, you could create your own Media
class and inherit from forms.Media
, then you could try using Media
as a dynamic property that would be able to generate a script with type="module"
.
Another option is to use a custom template as suggested before, or even considering adding a templatetag to your app in order to add ES6 modules in your template.
@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
class Media:
module = ('js/my_script.js',)
You can just change js to replace module its define is type of src
It‘s working for me.
We can overwrite the Media.render_js
to add anything we want to add to tag.
from django.forms.widgets import Media
def render_js(self) -> List[str]:
script_js = []
for path in self._js:
module_mark = ""
# Put your own condition here, in my case it generates
# <script type="module" src="http://localhost:5173/@vite/client"></script>
# and <script type="module" src="http://localhost:5173/src/custom_admin.ts"></script>
# into head scripts
if isinstance(path, str) and (
"custom_admin" in path or "@vite/client" in path
):
module_mark = ' type="module"'
js = format_html(
'<script%s src="{}"></script>' % module_mark,
self.absolute_path(path),
)
script_js.append(js)
return script_js
Media.render_js = render_js
class MyModelAdmin(admin.ModelAdmin):
class Media:
js = (
"http://localhost:5173/@vite/client",
"http://localhost:5173/src/custom_admin.ts",
)
Just adjust above code to adapt your logic and add it to your admin.py.