Django ModelChoiceField:过滤查询集并将默认值设置为对象

时间:2011-03-16 17:55:54

标签: django django-forms

我在Models中定义了一个Django Form类:

class AccountDetailsForm(forms.Form):
    ...
    adminuser = forms.ModelChoiceField(queryset=User.objects.all())

这样可行,但它有一些限制我似乎无法解决:

(1)我想在查询集上使用过滤器,基于传递给表单的变量accountid,如下所示:

User.objects.filter(account=accountid)

这在模型中不起作用,因为accountid当然不能作为变量传递。

因此queryset必须以某种方式在Views中定义,但据我所知,它是Form类中的必填字段。

(2)我想在数据库中默认选择AccountDetailsForm一个对象,我可以在Views中选择这样的对象:

User.objects.filter(account=accountid).filter(primary_user=1)

我尝试将adminuser指定为表单中的默认值(适用于其他标准表单字段,如CharField):

adminuser = User.objects.filter(account=accountid).filter(primary_user=1)

...

form = AccountDetailsForm({'adminuser': adminuser})
return render_to_response('accounts/edit/accountdetails.html', 
{'form': form, 'account':account})

但没有运气。

我是否应该使用ModelChoiceField之外的其他内容,因为我需要灵活性?

感谢。

4 个答案:

答案 0 :(得分:100)

覆盖init方法并接受新的关键字参数

class AccountDetailsForm(forms.Form):
    ...
    adminuser = forms.ModelChoiceField(queryset=User.objects.all())
    def __init__(self, *args, **kwargs):
        accountid = kwargs.pop('accountid', None)
        super(AccountDetailsForm, self).__init__(*args, **kwargs)

        if accountid:
            self.fields['adminuser'].queryset = User.objects.filter(account=accountid)

form = AccountDetailsForm(accountid=3)

您也可以随时在视图中手动设置选项。

form = AccountDetailsForm()
form.fields['adminuser'].queryset = User.objects.filter(account=accountid)

警告:您通过将字典传递到示例中的表单来设置默认值。

您实际上正在创建一个绑定表单,可能会触发验证和所有爵士乐。

设置默认值use the initials argument.

form = AccountDetailsForm(initial={'adminuser':'3'})

答案 1 :(得分:6)

您可以覆盖视图中的字段

yourForm = AccountDetailsForm()

yourForm.fields['accomodation'] = forms.ModelChoiceField(User.objects.filter(account=accountid).filter(primary_user=1))

答案 2 :(得分:1)

Form.clean()方法尚未在此处提及。此方法专门用于自定义验证。

对于您的示例,您可以执行以下操作:

class AccountDetailsForm(forms.Form):
    adminuser = forms.ModelChoiceField(queryset=User.objects.all())
    account_id = forms.IntegerField()  # or ModelChoiceField if that applies

    def clean(self):
        account_id = self.cleaned_data['account_id']
        self.cleaned_data['adminuser'] = User.objects.filter(account_id=account_id)

    return self.cleaned_data

clean()方法在默认的clean方法之后被调用,因此您可以使用self.cleaned_data(与视图中的form.cleaned_data相同)并根据需要返回它。

更好的是,您可以根据要清理的字段(def clean_adminuser)命名方法,并使其更易于阅读。

def clean_adminuser(self):
    account_id = self.cleaned_data['account_id']
    return User.objects.filter(account_id=account_id)

如果您要处理任何问题,也可以使用此方法致电Form.add_error()

答案 3 :(得分:0)

在Django 2.0中,您可以像这样将对象(在您的情况下为User)从view传递到form(您必须首先从数据库检索obj):

form = AccountDetailsForm(initial={'adminuser': adminuser})

它将为您提供一个默认的选定对象(回答您的2个问题)