2

这只是困扰我的好奇心。我创建了一个 Form 类来处理从数据库中选择的文档。自然,必须从数据库中获取文档列表以填充可用选项。通过手动构建选择并使用 ChoiceField,我得到了“陈旧”的行为。但是当使用 ModelChoiceField 选项“queryset”时,我得到了准确的结果。

“陈旧”是指如果我上传新文档并呈现页面,列表仅显示旧文档集(有时即使在刷新页面后仍然存在,根据视图逻辑应该重新生成表单 - 证明这是事实,无论用例如何,第二种方法都按预期工作)。示例如下:

旧版本:

class GetDocumentForm(forms.Form):
    document_query   = Document.objects.all().order_by('docfile')
    document_choices = []

    for document in document_query:
        document_choices.append((document.id, document.docfile.name))

    document         = forms.ChoiceField(label='', choices=document_choices)

准确版:

class GetDocumentForm(forms.Form):
    document         = forms.ModelChoiceField(queryset=Document.objects.all())

是什么赋予了?有什么不同?为什么他们的行为不同?

4

1 回答 1

3

陈旧版本的类主体应该在__init__方法内部!– 马里奥德夫

谢谢马里奥德夫。

遵循这条线索,我能够生成运行正常的代码。我的第一次尝试仍然无法正常工作:

class GetDocumentForm(forms.Form):
    def __init__(self):
        ...
        self.base_fields['document'].choices = self.document_choices[:]

这将允许我创建一个表单,但是当我尝试渲染时:

In [1]: from WebSite.forms import *

In [2]: doc_form = GetDocumentForm()

In [3]: print doc_form.as_p()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)

AttributeError: 'GetDocumentForm' object has no attribute '_errors'

解决方案在这里:StackOverflow - Django: Overloading init for Custom Forms。你需要超级类。

最终,工作代码:

class GetDocumentForm(forms.Form):
    document          = forms.ChoiceField()

    def __init__(self, *args, **kwargs):
        super(GetDocumentForm, self).__init__(*args, **kwargs)

        for doc in Document.objects.all().order_by('docfile'):
            self.fields['document'].choices.append((doc.id, doc.docfile.name))

显然使用ModelChoiceField(queryset=Document.objects.all())要简洁得多。但关键是要了解如何让它双向工作。

干杯。

于 2013-09-06T18:39:52.483 回答