Quantcast
Channel: CodeSection,代码区,Python开发技术文章_教程 - CodeSec
Viewing all articles
Browse latest Browse all 9596

Chosen.js in the Django admin

$
0
0

Update Nov 23, 2013: I've written a little app ( django-chosenadmin ) that'll automatically add this to every app.

Quite some time ago, I ran across the chosen.js plugin for jQuery and Prototype (I'm using the jQuery flavor). My first thought upon seeing this was, " This would rock in Django's admin app. " Yet for some reason, I didn't make that happen.

Until recently.

I maintain a project where about 10 people use the admin app extensively. They manage several apps that have foreign keys to django's User model. This works well enough, but there are a few thousand user accounts. That makes the default <select> elements fairly unwieldy, and the <select multiple> widgets are just horrendous!

Fortunately, the chosen.js plugin is fairly straighforward to install for the admin. You'll first need to grab a copy of chosen.js and (if you want to use them) the default CSS and sprite files. I just grabbed the most current version from github .

chosen.js : https://github.com/harvesthq/chosen/blob/master/chosen/chosen.jquery.min.js chosen.css : https://github.com/harvesthq/chosen/blob/master/chosen/chosen.css chosen-sprite.png : https://github.com/harvesthq/chosen/blob/master/chosen/chosen-sprite.png

My static files are organized as follows. Note that I put chosen's CSS & sprite files in a subdirectory named chosen :

project_directory/
static/
css/
chosen/
chosen.css
chosen-sprite.png
js/
chosen.js

Now, you can override the admin app's change_form.html template (be sure to get a copy for your version of django. You can do this by putting your own copy of the template in your project's templates directory (see your TEMPLATE_DIRS setting). For me, that looks like this:

project_directory/
templates/
admin/
change_form.html

In that template, there's an extrahead block. At the bottom of that block, you need to include a link to the plugin and the css file. Since this is a jQuery plugin, you'll also need to include a link to jQuery. ( Even though django's admin comes bundled with jQuery, it's namespaced, so to use a 3rd-party plugin, you need your own copy of the library. See this note )

<script
src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"
type="text/javascript"></script>
<script
src="{{ STATIC_URL }}js/chosen.jquery.min.js"
type="text/javascript"></script>
<link rel="stylesheet" href="{{ STATIC_URL }}css/chosen/chosen.css"/>

Now, you can apply the chosen plugin to all <select> elements!

<script type="text/javascript">
$(document).ready(function() {
$('select').chosen();
});
</script>

However, this has one unfortunate side effect. Django's admin app contains a custom multi-select widget, that normally looks like this:


Chosen.js in the Django admin

The chosen plugin dutifully mangles the custom widget, which is probably not what you want:


Chosen.js in the Django admin

The admin app's custom widget includes javascript that gets loaded after the page loads. Luckily, it includes a filtered class on the elements to which it is applied. So, we need the chosen plugin to load after the admin app's javascript has run.

The only what I got that to work was to use setTimeout . This is definitely a hack, and I'd love to see a more elegant solution... but it works. So, the previous code to initialize the chosen plugin would be replaced with the following:

<script type="text/javascript">
setTimeout(function() {
$('select').not('.filtered').chosen();
}, 1000);
</script>

Now the plugin gets loaded about 1 second after the page is finished loading, so you get both the admin app's custom multi-select widget and the chosen.js plugin. There's a visible delay before the plugin gets loaded, but you could tweak the second argument to minimize this somewhat. For my needs, the benefits of the more usable interface for <select> elements outweigh the cost of loading the plugin.


Viewing all articles
Browse latest Browse all 9596

Trending Articles