The code I use is:
class VoteForm(forms.ModelForm):
other_choice1 = forms.BooleanField(required=False)
other_choice2 = forms.BooleanField(required=False)
other_choice3 = forms.BooleanField(required=False)
other_choice4 = forms.BooleanField(required=False)
class Meta:
model = Vote
exclude = ('choic开发者_JS百科e', 'other_choices',)
def __init__(self, poll_id, *args, **kwargs):
super(VoteForm, self).__init__(*args, **kwargs)
p = get_object_or_404(Poll, pk=poll_id)
choices = p.choice_set.all()
choices_len = len(choices)
f = ['other_choice1','other_choice2','other_choice3','other_choice4']
for i in range(0,choices_len):
self.fields[f[i]].label = str(choices[i])
for i in range(choices_len,4):
del self.fields[f[i]]
This is the best way I've found to modify form's fields at runtime. It seems a bit like hacking the implementation. What's the well-defined way to do that?
Thanks, Alex
Use base_fields
as explained in Monkey patching a Django form class? :
ContactForm.another_field = forms.CharField(...)
ContactForm.base_fields['another_field'] = ContactForm.another_field
(Or BaseForm
as explained here http://snipt.net/danfreak/how-to-generate-a-dynamic-at-runtime-form-in-django/ :
def make_contact_form(user):
fields = { 'name': forms.CharField(max_length=50),
'email': forms.EmailField(),
'message': forms.CharField(widget=forms.Textarea) }
if not user.is_authenticated:
fields['captcha'] = CaptchaField()
return type('ContactForm', [forms.BaseForm], { 'base_fields': fields })
)
Yes, this does seem hacky. But the reason for that is that you're thinking in the wrong direction. What you seem to want is a single checkbox for each item in a relationship, and you're trying to implement that by having one BooleanField per item. But that's not how you should be thinking at all - you should be thinking of a single field to represent the items in that relationship, and a ChecbkoxMultipleSelect widget to actually display the checkboxes.
精彩评论