You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

新版Chrome中Django-autocomplete-light模态框表单渲染异常

问题描述

我有一个基于Python 3.7和Django 2.2.10的Django应用,使用Django Admin,模板采用Materialize CSS。自Chrome最新版本更新后,模态框中的表单出现渲染问题(其他浏览器可正常运行)。

自定义Widget代码

class Select2Widget(Select2WidgetMixin):

    def _get_language_code(self):
        return 'pt-BR'

    @property
    def media(self):
        """Return JS/CSS resources for the widget."""
        return forms.Media(
            js=(
                   'autocomplete_light/jquery.init.js',
                   STATIC_URL + 'js/select2.full.js',
                   # 'vendor/select2/dist/js/select2.full.js',
                   'autocomplete_light/autocomplete.init.js',
                   'autocomplete_light/forward.js',
                   'autocomplete_light/select2.js',
                   'autocomplete_light/jquery.post-setup.js',
               ),
            css={
                'screen': (
                    'vendor/select2/dist/css/select2.min.css',
                    'admin/css/autocomplete.css',
                    'autocomplete_light/select2.css',
                ),
            },
        )

    autocomplete_function = 'select2'

"""
retorna queryset na ordem que foi selecionado no field
"""
class QuerySetSelect(WidgetMixin):

    def filter_choices_to_render(self, selected_choices):
        preserved = Case(*[When(pk=pk, then=pos) for pos, pk in enumerate(selected_choices)])
        """Filter out un-selected choices if choices is a QuerySet."""
        self.choices.queryset = self.choices.queryset.filter(pk__in=[c for c in selected_choices if c]).order_by(preserved)


class ModelSelect2(QuerySetSelectMixin, Select2Widget, forms.Select):
    ...


class ModelSelect2Multiple(QuerySetSelectMixin, Select2Widget, forms.SelectMultiple):
    ...


class Select2Multiple(Select2Widget, SelectMultiple):
    ...

表单使用代码

class PessoaForm(ModelForm):    
    ativo = forms.BooleanField(required=False)    
    cpf_cnpj = BRCPFCNPJField(label='CPF/CNPJ', max_length=14)    
    logradouro = forms.ModelChoiceField(queryset=Logradouro.objects,
                                        required=False,
                                        label='CEP',
                                        widget=ModelSelect2(url='logradouro_autocomplete',
                                                             attrs={'data-placeholder': 'Informe o CEP',
                                                                    'style': 'width: 100%;',
                                                                    'data-minimum-input-length': 8,
                                                                    'class':'material-ignore',
                                                                    'material-ignore': True}),)    
    municipio = forms.ModelChoiceField(queryset=Municipio.objects,
                                       label='Município',
                                       required=False,
                                       widget=ModelSelect2(url='logradouro_municipio_autocomplete',
                                                            forward=['logradouro'],
                                                            attrs={'style': 'width: 100%;',
                                                                   'data-placeholder': 'Selecione',
                                                                   'class': 'material-ignore',
                                                                   'material-ignore': True }))    
    local_emissao_cnh = forms.ModelChoiceField(queryset=Municipio.objects,
                                               label='Municipio Emissão da CNH',
                                               required=False,
                                               widget=ModelSelect2(url='logradouro_municipio_autocomplete',
                                                                    forward=['logradouro'],
                                                                    attrs={'style': 'width: 100%;',
                                                                           'data-placeholder': 'Selecione',
                                                                           'class': 'material-ignore',
                                                                           'material-ignore': True }))    
    bairro = forms.ModelChoiceField(queryset=Bairro.objects,
                                    label='Bairro',
                                    required=False,
                                    widget=ModelSelect2(url='bairro_autocomplete',
                                                        forward=['municipio', 'logradouro'],
                                                        attrs={'style': 'width: 100%;',
                                                               'data-placeholder': 'Selecione',
                                                               'class': 'material-ignore',
                                                               'material-ignore': True}))    
    qualificacao = forms.ModelChoiceField(queryset=Qualificacao.objects,
                                          label='Qualificação',
                                          required=False,
                                          widget=ModelSelect2Multiple(url='qualificacao_autocomplete',
                                                                       attrs={'style': 'width: 100%;',
                                                                              'data-placeholder': 'Selecione',
                                                                              'class': 'material-ignore',
                                                                              'material-ignore': True}))    
    ocupacao = forms.ModelChoiceField(queryset=Qualificacao.objects,
                                      label='Ocupação',
                                      required=False,
                                      widget=ModelSelect2Multiple(url='ocupacao_autocomplete',
                                                                   attrs={'style': 'width: 100%;',
                                                                          'data-placeholder': 'Selecione',
                                                                          'class': 'material-ignore',
                                                                          'material-ignore': True}))    

    class Meta:
        fields = '__all__'
        model = Pessoa    

    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop('request', None)
        super(PessoaForm, self).__init__(*args, **kwargs)        

        if self.instance.pk and self.instance.user:
            self.initial['is_active'] = self.instance.user.is_active
            self.initial['is_staff'] = self.instance.user.is_staff
            self.initial['grupos'] = self.instance.user.groups.all()  

问题表现

Chrome最新版本中,模态框内的Select2表单控件渲染异常(如布局错乱、下拉框不显示或样式冲突),其他浏览器无此问题。已尝试更换相关库、社区搜索,均未解决。

可能的解决方案

1. 升级依赖库版本

Chrome新版本可能对DOM渲染、事件机制有更新,旧版Select2或django-autocomplete-light可能存在适配问题:

  • 升级Select2到最新稳定版(当前为4.0.13+),替换项目中select2.full.js和select2.min.css文件;
  • 同步升级django-autocomplete-light到兼容Django 2.2的最新版本,避免版本不匹配引发的冲突。

2. 修复样式冲突

Materialize与Select2的样式优先级在Chrome新版本中可能冲突,添加自定义CSS强制修正:

/* 确保模态框内Select2容器宽度正常 */
.modal .select2-container {
    width: 100% !important;
    z-index: 10000 !important; /* 避免被模态框遮罩覆盖 */
}

/* 修复下拉框定位问题 */
.modal .select2-dropdown {
    z-index: 10001 !important;
    position: fixed !important;
}

将上述代码添加到Admin自定义样式文件中,确保在Materialize和Select2样式之后加载。

3. 调整Select2初始化时机

Chrome可能修改了模态框shown事件的触发时机,导致Select2在模态框未完全渲染时初始化:

// 手动初始化Select2,确保模态框完全显示后执行
$(document).on('shown.bs.modal', '.modal', function() {
    $(this).find('.select2').select2({
        language: 'pt-BR',
        dropdownParent: $(this) // 将下拉框挂载到模态框内,避免溢出或定位错误
    });
});

同时移除Widget media中自动初始化的相关代码,改用上述手动初始化逻辑。

4. 检查jQuery版本兼容性

确保项目使用的jQuery版本与Select2、django-autocomplete-light兼容:

  • Django 2.2默认jQuery为2.x版本,Select2 4.x兼容jQuery 1.8+,建议升级到jQuery 3.x稳定版;
  • 替换项目中的jQuery文件,测试是否解决问题。

5. 临时禁用Chrome实验性特性

若问题由Chrome新特性导致,可临时禁用测试:

  • 地址栏输入chrome://flags/;
  • 搜索LayoutNG或CSS Container Queries等布局相关特性,设置为Disabled;
  • 重启Chrome测试,若问题解决,等待库方发布适配补丁后再恢复特性。

内容的提问来源于stack exchange,提问作者Dev Orea

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 20:14:55