14

似乎如果给 ModelForm 一个实例,它会忽略您提供的任何值initial,而是将其设置为实例的值——即使该实例是空模型记录。

有没有办法创建一个带有实例的表单设置初始数据?

我需要它,因为我正在保存相关记录,除非在创建时为 ModelForm 提供了一个实例,否则它们似乎无法正确保存。

我敢肯定,这个问题的答案很简单,我只是遗漏了一些明显的东西。

以下是相关代码:

在视图中:

form = form_class(person=person, conference=conference, initial=initial, instance=registration)

form_class 在哪里RegistrationForm,然后在注册表单中:

class RegisterForm(forms.ModelForm):
    ... fields here ...

    def __init__(self, *args, **kwargs):
        ... other code ...
        self.person = kwargs.pop('person')
        super(RegisterForm, self).__init__(*args, **kwargs)
        for key, in self.fields.keys():
            if hasattr(self.person, key):
                self.fields[k].initial = getattr(self.person, key)

然后当我调用该字段时,相关字段为空。

4

3 回答 3

8

经过一番谷歌搜索后发现了这一点。

您必须在调用之前设置初始值super

因此,我不必循环遍历self.fields.keys(),而是输入我想要的字段列表并循环遍历:

class RegisterForm(forms.ModelForm):
    ... fields here ...
    initial_fields = ['first_name', 'last_name', ... ]

    def __init__(self, *args, **kwargs):
        ... other code ...
        self.person = kwargs.pop('person')
        for key in self.initial_fields:
            if hasattr(self.person, key):
                self.fields[k].initial = getattr(self.person, key)
        super(RegisterForm, self).__init__(*args, **kwargs)

@Daria 正确地指出,self.fields在调用 super 之前你没有。我很确定这会起作用:

class RegisterForm(forms.ModelForm):
    ... fields here ...
    initial_fields = ['first_name', 'last_name', ... ]

    def __init__(self, *args, **kwargs):
        ... other code ...
        initial = kwargs.pop('initial', {})
        self.person = kwargs.pop('person')
        for key in self.initial_fields:
            if hasattr(self.person, key):
                initial[key] = initial.get(key) or getattr(self.person, key)
        kwargs['initial'] = initial
        super(RegisterForm, self).__init__(*args, **kwargs)

在这个版本中,我们使用initial参数来传递值。它也被写入,以便如果我们已经为该字段初始值,我们不会覆盖它。

于 2013-08-15T14:04:13.300 回答
2

在我看来,您可能正在寻找绑定表格。不完全确定,我正在尝试取消选择类似的问题:

Django 表单可以用两个控制这种事情的参数来实例化。据我了解:

form = MyForm(initial={...}, data={...}, ...)

initial 将设置字段的可能值——就像设置查询集一样——<em>data 将设置表单的实际(或选定)值并创建绑定表单。也许这就是你想要的。另一个你可能会感兴趣的切线点是考虑工厂方法而不是构造函数,我认为语法更自然:

class MyForm(forms.ModelForm):

    ...

    @staticmethod
    def makeBoundForm(user):
        myObjSet = MyObject.objects.filter(some_attr__user=user)
        if len(myObjSet) is not 0:
            data = {'myObject': myObjSet[0]}
        else:
            raise ValueError()
        initial = {'myObject': myObjSet}
        return MyForm(initial=initial, data=data)
于 2015-06-11T07:25:45.140 回答
1

您还可以在初始化时将额外的变量传递给类。然后,您传递的值可以覆盖初始数据或 POST 数据。

class RegisterForm(forms.ModelForm):
    ... fields here ...

    def __init__(self, person, conference, *args, **kwargs):
        ... other code ...
        super(RegisterForm, self).__init__(*args, **kwargs)
        self.fields['person'] = person
        self.fields['conference'] = conference

form = RegisterForm(person, conference, initial=initial, instance=registration)
于 2015-01-20T15:43:29.330 回答