Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Admin: How to customize autocomplete_fields width to adapt to the content?

I'm trying to customize the widget rendered by autocomplete_fields for a ForeignKey Model field. Basically the problem is that the widget is too narrow for the content and it's breaking in two lines inside the select:

screenshot of current issue

I have seen that the JS library or JQuery plugin is called Select2 and it has a "dropdownAutoWidth" to make it adapt to the parent element size that kind of works but I'm completely clueless on how to set that option from admin.py since it seems that options are never passed in the code at django.contrib.admin.widgets.AutocompleteMixin.media:

    def media(self):
    extra = '' if settings.DEBUG else '.min'
    i18n_name = SELECT2_TRANSLATIONS.get(get_language())
    i18n_file = ('admin/js/vendor/select2/i18n/%s.js' % i18n_name,) if i18n_name else ()
    return forms.Media(
        js=(
            'admin/js/vendor/jquery/jquery%s.js' % extra,
            'admin/js/vendor/select2/select2.full%s.js' % extra,
        ) + i18n_file + (
            'admin/js/jquery.init.js',
            'admin/js/autocomplete.js',
        ),
        css={
            'screen': (
                'admin/css/vendor/select2/select2%s.css' % extra,
                'admin/css/autocomplete.css',
            ),
        },
    )
like image 845
Vlax Avatar asked May 08 '20 12:05

Vlax


People also ask

How to show autocomplete search dropdown for manytomanyfield fields in Django?

Show autocomplete search dropdown for ManyToManyField fields in Django admin. autocomplete_fields is a list of ForeignKey and/or ManyToManyField fields you would like to change to autocomplete inputs. By default, the admin uses a select-box interface ( <select>) for those fields.

Why can’t I customize Django admin?

The reason for not doing complete customization is wasting time. You see, you need to learn in-depth if you want an admin to be fully customized. Django Admin is not meant to be customized that deeply and the official docs are also clear about that. Although, there are more customizations available.

What is the default title of an admin page in Django?

By default, this is “Django administration”. The text to put at the end of each admin page’s <title> (a string). By default, this is “Django site admin”. The URL for the “View site” link at the top of each admin page.

What is Django’s automatic admin interface?

One of the most powerful parts of Django is the automatic admin interface. It reads metadata from your models to provide a quick, model-centric interface where trusted users can manage content on your site.


2 Answers

Django 3.0.9:

forms.py

from django import forms
from django.contrib import admin
from django.contrib.admin.widgets import AutocompleteSelect

from .models import MyModel

    class MyModelForm(forms.ModelForm):
        class Meta:
            fields = ('my_field', )
            widgets = {
                'my_field': AutocompleteSelect(
                    MyModel.my_field.field.remote_field,
                    admin.site,
                    attrs={'style': 'width: 400px'}  # You can put any width you want.
                ),
            }

admin.py

from django.contrib import admin

from .forms import MyModelForm


MyModelAdmin(admin.ModelAdmin):
    form = MyModelForm
like image 81
CentOS Avatar answered Nov 15 '22 22:11

CentOS


You can pass data-* attributes to select2 by including them in the autocomplete widget's attrs. One way to do this is to initialize the widget yourself using a custom form.

Note that if you also include the field in autocomplete_fields then the widget will be initialized by your ModelAdmin instance and your custom initialization won't have any effect.

Also note that the AutocompleteSelect and AutocompleteSelectMultiple widgets require a couple of positional arguments.

Something like this should work:

from django import forms
from django.contrib import admin
from django.contrib.admin.widgets import AutocompleteSelect

class MyForm(forms.ModelForm):
    class Meta:
        widgets = {
            'my_field': AutocompleteSelect(
                MyModel._meta.get_field('my_field').remote_field,
                admin.site,
                attrs={'data-dropdown-auto-width': 'true'}
            ),
        }

class MyAdmin(admin.ModelAdmin):
    #autocomplete_fields = ['my_field']
    form = MyForm
like image 28
DanS Avatar answered Nov 15 '22 23:11

DanS