字段和基础字段 - Django

16

创建一个平面页面时,我希望用户可以从预定义的列表中选择模板。为了不改变Flatpage模型,我更喜欢使用ChoiceField而不是ModelChoiceField(后者提供模板的PK,但我需要模板名称用于template_name字段):

class NewFlatpageForm(FlatpageForm):

    template_name = forms.ChoiceField(choices = [])
    def __init__(self, *args, **kwargs):
        self.base_fields['template_name'].choices = ProjectTemplate.objects.values_list('path', 'name')
        super(NewFlatpageForm, self).__init__(*args, **kwargs)

我覆盖了__init__,或者Django在服务器启动时填充选项,然后不会更新列表。

我没有任何管理经验,但是在不使用管理时,我使用fields属性进行类似的操作。但是在这种情况下,我收到了一个异常,告诉我fields不是表单的属性。__dict__向我展示了一个base_fields属性,并使用它可以解决问题。因此,在这里为什么要使用base_fields?为什么不存在fields,最后,我是否在做一些 hacky 的事情?

3个回答

17

fields 直到你调用 super 之后才存在。因此,只需交换行的顺序,让 super 先被调用。


16
我从自己的经验中学到了一个教训:修改base_fields意味着您的修改会一直保留下去,直到Python退出。在你的情况下,这可能不是问题,因为你总是使用相同的字段名称,并用ProjectTemplate的分配值替换它们...

而我想要根据构造函数中的参数完全不同的字段。由于我的字段名称通常不同,每次我实例化一个表单时,我都会添加新的字段,但不会消除上一次的字段。

通过早期调用super(如此处所示),然后对self.fields进行动态更改而不是对self.base_fields进行更改,我能够消除不断增长的字段列表的问题。现在它非常合理,但我以前对所有语法细节并不熟悉,一直在试错而不是先理解它们。


还请参阅文档中的警告:"请注意不要修改base_fields属性..." - undefined

4

除了Joe Germuska之外,如果您真的需要根据请求更改表单,您可以使用深拷贝(deepcopy)来确保没有通过引用进行任何更改:

def get_form(self, request, obj=None, **kwargs):
    form = super(ResourceAdmin, self).get_form(request, obj, **kwargs)
    form = copy.deepcopy(form)

    if obj:
        form.base_fields['email'] = EmailField(initial=obj.user.email)
    if not request.user.is_superuser:
        form.base_fields['user'].widget = HiddenInput(attrs={'class': 'hide_form_row'})

    return form

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接