I'm trying to resize a many to many field of django 1.8 admin.
models.py
from django.db import models
class Material(models.Model):
type = models.CharField(max_length=20, primary_key=True)
def __unicode__(self):
return self.type
class Pen(models.Model):
label = models.CharField(max_length=20, blank=True, default='')
materials = models.ManyToManyField(Material)
admin.py
from django.contrib import admin
from django.conf.urls import url
from .models import *
from django.forms import SelectMultiple
@admin.register(Pen)
class PenAdmin(admin.ModelAdmin):
filter_horizontal = ('materials',)
#formfield_overrides = { models.ManyToManyField: {'widget': SelectMultiple(attrs={'size':'5', 'width': '50px', 'style': 'width:50px'})}, }
def get_form(self, request, obj=None, **kwargs):
form = super(PenAdmin, self).get_form(request, obj, **kwargs)
form.base_fields['materials'].widget.attrs['style'] = 'width: 70px;'
return form
class Media:
js = ("js/resize_fields.js",)
@admin.register(Material)
class MaterialAdmin(admin.ModelAdmin):
pass
resize_fields.js
document.onload = function() {
document.getElementById("id_materials_to").style.width="70px";
};
As you can see I tried 3 approaches:
1: using formfield_overrides. It did not make any difference.
2: loading a javascript to resize the html object. It's firing up but not resizing it because the script seems to run before the widget is loaded.
3: using get_form. As shown below, it only resizes one of the select boxes.
Does anyone know how to resize it horizontally?
UPDATE: I discovered that:
class PenAdmin(admin.ModelAdmin):
formfield_overrides = {
models.ManyToManyField: {'widget': SelectMultiple(attrs={'size':'5', 'style': 'color:blue;width:250px'})},
}
would work since I removed filter_horizontal but I want to use filter_horizontal! If I'm not mistaken, the filter_horizontal option will use the MultiWidget which is apparently not passing the override attributes to sub-widgets. Still, I think there must be a solution where I can run a javascript after the page load. plz help
You can resize the widget by overriding CSS styles.
You'll need to override the following CSS classes:
.selector
- this div contains both the widgets.
.selctor-available
- this div contains the widget on the left.
.selector-chosen
- this div contains the widget on the right.
First, create a CSS file called resize-widget.css
inside your project's static
directory. Add the following code to the file:
UPDATE: For Django v2, these CSS rules will not work. See the other answer posted below.
.selector-available,
.selector-chosen {
width: 200px;
}
.selector .selector-available input {
width: 184px;
}
.selector select {
width: 200px;
}
.selector {
width: 450px;
}
In admin.py, supply that CSS file via class Media
:
@admin.register(Pen)
class PenAdmin(admin.ModelAdmin):
filter_horizontal = ('materials',)
class Media:
css = {
'all': ('resize-widget.css',), # if you have saved this file in `static/css/` then the path must look like `('css/resize-widget.css',)`
}
Visit admin site. The select widget must look like this:
I tried xyres answer and found that it worked BUT some of the CSS rules were being overridden by other rules that used more specific selectors.
To fix this I modified resize-widget.css
to the following:
.form-horizontal .control-group .controls .selector {
width: 100%;
}
.form-horizontal .control-group .controls .selector .selector-available,
.form-horizontal .control-group .controls .selector .selector-chosen {
max-width: 45%;
}
.form-horizontal .control-group .controls .selector select {
min-height: 200px;
}
These more specific rules were not being overridden and made it work for me.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With