11

使用这种形式:

class Form(forms.Form):
    name = forms.CharField(required=False, initial='Hello world')

如果我在视图中做这样的事情:

form = Form(request.GET)
if form.is_valid():
    name = form.cleaned_data['name']

即使 request.GET 不包含name作为键,名称的初始值也会丢失。有什么解决方法吗?我希望初始值能够将表单绑定为“默认值”。

4

7 回答 7

11

通过稍微修改 Gonzalo 的解决方案,这是正确的方法:

class Form(forms.Form):
    name = forms.CharField(required=False, initial='Hello world')

    def clean_name(self):
        if not self['name'].html_name in self.data:
            return self.fields['name'].initial
        return self.cleaned_data['name']

如果你需要这个,你可以看看 django-filter app。我最近才发现它。

于 2013-06-22T12:14:55.723 回答
5

initial并不是真的用来设置表单字段的默认值。相反,在向用户显示表单时,它实际上更像是一个占位符实用程序,如果不需要该字段(如您的示例中),它将无法正常工作。

您可以做的是定义一个clean_<fieldname>方法来检查该字段是否有空值并返回默认值:

class Form(forms.Form):
    name = forms.CharField(required=False, initial='Hello world')

    def clean_name(self):
        name = self.cleaned_data['name']
        if name is None:
            return self.fields['name'].initial
        return name
于 2013-04-16T00:39:26.337 回答
4

我使用以下模式将默认值设置为表单给出的初始值 -

class InitialDefaultForm(forms.Form):
    def clean(self):
        cleaned_data = super(InitialDefaultForm, self).clean()
        # if data is not provided for some fields and those fields have an
        # initial value, then set the values to initial value
        for name in self.fields:
            if not self[name].html_name in self.data and self.fields[name].initial is not None:
                cleaned_data[name] = self.fields[name].initial
        return cleaned_data

这可确保所有具有初始值且未从用户获取值的字段都由其初始值填充。

于 2013-12-01T07:21:58.777 回答
2

这会起作用吗:

initial_form_data = {'name': 'Hello World'}   #put all the initial for fields in this dict
initial_form_data.update(request.GET)  #any field available in request.GET will override that field in initial_form_data
form = Form(initial_form_data)
if form.is_valid():
    name = form.cleaned_data['name']
于 2013-04-16T11:38:06.553 回答
2

request.GET是像字典一样的对象。

initial仅在未绑定形式的情况下有效。

表单有一个名为 的属性datadata此属性在表单初始化期间作为第一个位置参数或关键字参数提供。

绑定表单是您将一些数据作为表单的第一个参数提供的表单,而未绑定表单的data属性设置为无。

在这里,在 form 的初始化中form=Form(request.GET),您提供了第一个位置参数,因此data在表单上设置了属性,它变成了绑定表单。即使request.GET是空字典也会发生这种情况。而且由于您的表单成为绑定表单,因此initial字段name对其没有影响。

因此,在您的 GET 请求中,您应该执行以下操作:

form = Form()

initialname领域将受到尊重。

或者,如果您想name从 request.GET 中读取并且如果它在那里然后想要使用它而不是字段的初始值,那么在您的视图中具有以下内容。

name = request.GET.get(name)
form_level_initial = {}
if name:
    form_level_initial['name'] = name
form = Form(initial=form_level_initial)
于 2013-04-16T06:55:58.803 回答
2

提议的解决方案要么对我不起作用,要么看起来不是很优雅。该文档指定 initial 不适用于绑定表单,这似乎是原始提问者(和我的)用例:

这就是为什么只为未绑定的表单显示初始值的原因。对于绑定表单,HTML 输出将使用绑定数据。

https://docs.djangoproject.com/en/1.10/ref/forms/fields/#initial

我的解决方案是查看表单是否应该绑定:

initial = {'status': [Listing.ACTIVE], 'min_price': 123}     # Create default options

if request.method == 'GET':
    # create a form instance and populate it with data from the request:
    if len(request.GET):
        form = ListingSearchForm(request.GET)       # bind the form
    else:
        form = ListingSearchForm(initial=initial)   # if GET is empty, use default form

您还可以使用其他方式来初始化表单(如上所述)。

于 2016-09-02T05:31:58.303 回答
0

没有一个答案实际上完全符合 clime 的要求。所以这是我对同样问题的解决方案:

class LeadsFiltersForm(forms.Form):
    TYPE_CHOICES = Lead.TYPES
    SITE_CHOICES = [(site.id, site.name) for site in Site.objects.all()]

    type = forms.MultipleChoiceField(
        choices=TYPE_CHOICES, widget=forms.CheckboxSelectMultiple(),
        required=False
    )
    site = forms.MultipleChoiceField(
        widget=forms.CheckboxSelectMultiple(), required=False,
        choices=SITE_CHOICES
    )
    date_from = forms.DateField(input_formats=['%m-%d-%Y',], required=False,
                                widget=forms.TextInput(attrs={'placeholder': 'Date From'}),
                                initial=timezone.now() - datetime.timedelta(days=30))
    date_to = forms.DateField(input_formats=['%m-%d-%Y',], required=False,
                                widget=forms.TextInput(attrs={'placeholder': 'Date To'}))

    defaults = {
        'type': [val[0] for val in TYPE_CHOICES],
        'site': [val[0] for val in SITE_CHOICES],
        'date_from': (timezone.now() - datetime.timedelta(days=30)).strftime('%m-%d-%Y'),
        'date_to': timezone.now().strftime('%m-%d-%Y')
    }

    def __init__(self, data, *args, **kwargs):
        super(LeadsFiltersForm, self).__init__(data, *args, **kwargs)
        self.data = self.defaults.copy()
        for key, val in data.iteritems():
            if not data.get(key):
                continue
            field = self.fields.get(key)
            if field and getattr(field.widget, 'allow_multiple_selected', False):
                self.data[key] = data.getlist(key)
            else:
                self.data[key] = data.get(key)
于 2014-04-02T06:19:38.207 回答