Django modelform小部件属性被替换或被忽略

时间:2019-07-07 17:50:26

标签: django django-forms django-views

最近一段时间,我一直在为此挠头。我已经能够更改modelfield的字段queryset和小部件属性了!

class InvoiceItemForm(ModelForm):
    UOM = forms.ChoiceField (choices =  site_defaults.UOM)

    class meta:
        model = InvoiceItem
        fields = ['name', 'costcode', 'rate', 'quantity',]
        labels = {'name': 'Item', 'rate': 'Cost Per Unit', 'quantity': 'Base Quantity'}
        widgets = {'UOM': forms.Select(choices = site_defaults.UOM )}

    def __init__(self, current_user, current_project, *args, **kwargs):
            ''' Rendering custom ModelForm '''
            super(InvoiceItemForm, self).__init__(*args, **kwargs)

            the_title = None

            the_instance = kwargs.get('instance', None)
            if the_instance:
                the_costcode = the_instance.costcode

                if the_costcode:
                    the_title = the_costcode.title

            self.fields['costcode'].queryset =  CostCode.objects.filter(project = current_project, item = 0)
            self.fields['costcode'].widget = forms.TextInput(attrs={'class': 'site-flex-select-large', 'value': the_title})

呈现此代码时,costcode字段采用正确的实例。另外,该类显示为site-flex-select-large,但标题显示为instance.id,而不显示为instance.title的the_title(显示的值为192的文本字段,而不是发票项目)。

为什么Django忽略某些更改并接受对该字段的其他更改?

我不确定它是否是一个相关的细节,但是模型表单用于inlineformset:

expenses_forms = self.InvoiceItem_InlineFormSet(instance = the_invoice, prefix='expenses', form_kwargs={'current_user': user, 'current_project': project})

2 个答案:

答案 0 :(得分:2)

字段小部件不是您应该为字段设置初始值的地方。您应该在“初始” kwarg中将其设置为表单的__init__方法,您可以将其传递给对super的调用。然后,您可以在Meta中设置costcode小部件

class InvoiceItemForm(ModelForm):
    UOM = forms.ChoiceField (choices =  site_defaults.UOM)

    class Meta:
        model = InvoiceItem
        fields = ['name', 'costcode', 'rate', 'quantity',]
        labels = {'name': 'Item', 'rate': 'Cost Per Unit', 'quantity': 'Base Quantity'}
        widgets = {
            'UOM': forms.Select(choices = site_defaults.UOM ),
            'costcode': forms.TextInput(attrs={'class': 'site-flex-select-large'})
        }

    def __init__(self, current_user, current_project, *args, **kwargs):
        the_instance = kwargs.get('instance', None)
        if the_instance:
            the_costcode = the_instance.costcode
            if the_costcode:
                initial = kwargs.get('initial', {})
                initial['costcode'] = the_costcode.title
                kwargs['initial'] = initial
        super(InvoiceItemForm, self).__init__(*args, **kwargs)

编辑:就像Willem所说的那样,costcode字段是一个TextInput,因此除非将其更改为select,否则在其上设置queryset属性是没有意义的

答案 1 :(得分:1)

不是从attrs中获取的,而是从该字段的值中获取的。您可以设置字段的.initial属性,例如:

    def __init__(self, current_user, current_project, *args, **kwargs):
        ''' Rendering custom ModelForm '''
        super(InvoiceItemForm, self).__init__(*args, **kwargs)

        the_title = None
        the_instance = kwargs.get('instance', None)
        if the_instance:
            the_costcode = the_instance.costcode
            if the_costcode:
                the_title = the_costcode.title

        self.fields['costcode'].queryset =  CostCode.objects.filter(project=current_project, item=0)
        self.fields['costcode'].initial = the_title
        self.fields['costcode'].widget = forms.TextInput(attrs={'class': 'site-flex-select-large'})

话虽这么说,据我所知,通过使用TextInput,它只会忽略queryset,并且不会正确地验证数据。我认为您最好在这里使用Select widget [Django-doc],然后使用一些CSS / JavaScript使其可通过文本进行搜索。