eugene
eugene

Reputation: 41665

giving initial value raises 'value for field is required' error in django

Django form trips me many times...

I gave initial value to a ChoiceField (init of Form class)

self.fields['thread_type'] = forms.ChoiceField(choices=choices, 
    widget=forms.Select, 
    initial=thread_type)  

The form which is created with thread_type with the above code doesn't pass is_valid() because 'this field(thread_type) is required'.

-EDIT-
found the fix but it still perplexes me quite a bit.

I had a code in my template

   {% if request.user.is_administrator() %}
      <div class="select-post-type-div">                                                                                                                                                                                                                                        
        {{form.thread_type}}                                                                                                                                                                                                                                                    
      </div> 
   {% endif %}

and when this form gets submitted, request.POST doesn't have 'thread_type' when user is not admin.

the view function creates the form with the following code:

form = forms.MyForm(request.POST, otherVar=otherVar)

I don't understand why giving initial value via the the following(the same as above) is not enough.

self.fields['thread_type'] = forms.ChoiceField(choices=choices, 
        widget=forms.Select, 
        initial=thread_type)  

And, including the thread_type variable in request.POST allows the form to pass the is_valid() check.

The form class code looks like the following

class EditQuestionForm(PostAsSomeoneForm, PostPrivatelyForm):
    title = TitleField()
    tags = TagNamesField()


    #some more fields.. but removed for brevity, thread_type isn't defined here 

    def __init__(self, *args, **kwargs):
        """populate EditQuestionForm with initial data"""
        self.question = kwargs.pop('question')
        self.user = kwargs.pop('user')#preserve for superclass                                                                                                                                                                                                                  
        thread_type = kwargs.pop('thread_type', self.question.thread.thread_type)
        revision = kwargs.pop('revision')
        super(EditQuestionForm, self).__init__(*args, **kwargs)
        #it is important to add this field dynamically     

        self.fields['thread_type'] = forms.ChoiceField(choices=choices, widget=forms.Select, initial=thread_type)

Upvotes: 3

Views: 1073

Answers (1)

YardenST
YardenST

Reputation: 5257

Instead of adding this field dynamically, define it in the class appropriately:

class EditQuestionForm(PostAsSomeoneForm, PostPrivatelyForm):
    title = TitleField()
    tags = TagNamesField()
    thread_type = forms.ChoiceField(choices=choices, widget=forms.Select)

When creating the form instance set an intitial value if needed:

form = EditQuestionForm(initial={'tread_type': thread_type})

And if you dont need this field, just delete it:

class EditQuestionForm(PostAsSomeoneForm, PostPrivatelyForm):
    def __init__(self, *args, **kwargs):
        super(EditQuestionForm, self).__init__(*args, **kwargs)
        if some_condition:
            del self.fields['thread_type']

When saving form, check:

thread_type = self.cleaned_data['thread_type'] if 'thread_type' in self.cleaned_data  else None

This approach always works well for me.

Upvotes: 1

Related Questions