创建平面页面时,我希望用户从预定义列表中选择模板。为了保持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?
答案 0 :(得分:12)
fields
在之后调用super
后才会存在。所以只需交换行的顺序,以便super
首先出现。
答案 1 :(得分:10)
根据我自己的经验教训:修改basefields意味着你的修改“永远”(直到python退出)。在您的情况下,这可能不是问题,因为您始终使用相同的字段名称,并且您正在使用ProjectTemplate中的赋值替换其值...
就我而言,我希望根据构造函数中的参数完全不同的字段。由于我的字段名称通常不同,每次我实例化一个表单时,我都添加了新字段,但没有消除上一次的字段。
通过调用超级早期(如此处所示)然后对self.fields而不是self.basefields进行动态更改,我能够消除不断增长的字段列表的问题。它现在非常有意义,但我不熟悉所有语法细节,并且正在进行攻击,而不是先尝试理解它。
答案 2 :(得分:3)
除了Joe Germuska。如果您确实需要根据请求更改表单,可以使用深度检查来确保通过引用不会更改任何内容:
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