Let `ListFilter` be a `MediaDefiningClass` so that they can define custom CSS and JS

There currently no way to define custom CSS or JS in ListFilter unless by overriding its template. I propose to make MediaDefiningClass the metaclass for ListFilter to allow creation of much more complex components. It would look something like this:

from django.forms import Media


class FilterWithCustomTemplate(admin.SimpleListFilter):
    @property
    def media(self):
        return Media(
            js=("path/to/script.js",),
            css={"screen": ("path/to/stylesheet.css",)},
        )

I have already opened the PR for this request if you want to look how it looks like.

1 Like

I’m curious, what feature or functionality does this buy you over defining those assets on the page level?

JavaScript and CSS definitions are not local to that portion of the page, and the filters are specific to a page.

I was thinking, if that filter is used multiple times on the page, those CSS and JS are sourced multiple times, which might slightly degrade performence.

I’m not following you here. If those assets are defined in the model admin class, they’re only going to be sourced once. What makes you think that they would be sourced multiple times?

No, that’s the trick: the assets are not necessarily defined in the model admin class since a ListFilter could be used for mutiples instances of them. The idea is to let the filter define all it need to display. That would allow creating much more complex widgets.

For instance: think of a model that has a creation date and a modification date. You could create a complex widget that lets you select dates on a calendar. But since there are 2 dates on the model, the widget is here twice. So the assets would be sourced by the template twice.

I agree this is not a common use case but this could be useful in some cases and it’s really not hard to implement.

1 Like

That indicates a problem with the construction of your JavaScript. The JavaScript asset should be sufficiently flexible to work with “n” number of instances. It should be defined once, then instances created as needed.

There is no need for multiple copies to be sourced. It provides no benefit.

I’m sorry but what does the JS have to do with this? What I’m saying here is: if the template is used multiple times because the widget is used multiple times, then <script src="path/to/my_script.js"></script> will be present multiple times in the HTML. It seems cleaner to me to source it using Media.

Because you’re adding the script in the wrong place. We’re still talking about the admin, right?

If so, then your script should be defined as a page-level media entry, not included directly in the template.

Isn’t it what Media is for? Putting the scripts in the right place? If I put the scripts here, then the filter is not self-sufficient. You need to both use the filter and remeber putting the <script> in the admin template. Plus, there may not be a custom admin template.

I really don"t understand why opposing using a tool that already exists and that is doing that exact job.

That’s why the Django admin provide the page-level functionality of the Media within the ModelAdmin class.

I’m not opposing using the tool that already exists - the ModelAdmin-level Media class. What I am opposing is the addition of a second way of doing something that already exists.

What I am opposing is the addition of a second way of doing something that already exists.

It’s not. The idea is for the filter to be self sufficient. To have it declare its own assets instead of forcing the user to both add the filter and delcare the assets in ModelAdmin.