I have a simple unbound form:
class TeamMemberMapForm(forms.Form):
remote_id = forms.CharField(widget=forms.HiddenInput())
project = forms.ModelChoiceField(queryset=Project.objects.none())
Initial values are populated in the get_context_data:
form.fields['remote_id'].value = remote_id
form.fields['remote_id'].initial = remote_id
form.fields['remote_id'].disabled = True
form.fields['project'].queryset = Project.objects.\
filter(owned_by_company=self.request.user.owned_by_company, active=True)
On the frontend, I can select the values, by rendering the form like so. This is fine.
{% block form %}
<form method="post">{% csrf_token %}
<fieldset >
<!-- {{ form.errors }} -->
<!-- {{ form.non_field_errors }} -->
{{ form.as_p }}
</fieldset>
<button type="submit">
{% if object %}
Save {{ object }}
{% else %}
Create new entry
{% endif %}
</button>
</form>
{% endblock %}
Next, the view. I take the request and populate the form:
def post(self, request, remote_id, remote_name, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
# Do whatever
In the end, the form never validates. Inspecting the populated form from the POST shows that the values are never received.
<tr>
<th><label for="id_remote_id">Remote id:</label></th>
<td>
<ul ><li>This field is required.</li></ul>
<input type="text" name="remote_id" required id="id_remote_id">
</td>
</tr>
<tr>
<th><label for="id_project">Project:</label></th>
<td>
<ul ><li>Select a valid choice. That choice is not one of the available choices.</li></ul>
<select name="project" required id="id_project">
<option value="">---------</option>
</select>
</td>
</tr>
The post object looks like it contains something for 'project', but not for the remote_id.
<QueryDict: {'csrfmiddlewaretoken': ['zPpsQSHao0BynQWxotu95LiaeF9otrRte3mjYctQuJXgA5ODNi0u8hDDPBfQWaeK'], 'project': ['10']}>
What am I missing?
CodePudding user response:
You can try adding class Meta in your form class:
class TeamMemberMapForm(forms.Form):
remote_id = forms.CharField(widget=forms.HiddenInput())
team_member = forms.ModelChoiceField(queryset=TeamMember.objects.none())
class Meta:
model = your_model
fields = ['remote_id','team_member']
And do this function in views.py:
def post(request):
form = TeamMemberMapForm(request.POST)
if form.is_valid():
# Do whatever
render('url to template', 'form': form)
CodePudding user response:
When you're using a hidden input, you'll need to pass a value to that field. Typically you do this by passing a dictionary to the form;
MyForm(initial={'myfield': "value"})
How you fit this into your view is up to you, but you could do something like;
class MyView(View):
def get_form(self, form_class=None):
"""Return an instance of the form to be used in this view."""
if form_class is None:
form_class = self.get_form_class()
return form_class(**self.get_form_kwargs())
def get_form_kwargs(self):
"""Return the keyword arguments for instantiating the form."""
kwargs = {
'initial': self.get_initial(),
'prefix': self.get_prefix(),
}
if self.request.method in ('POST', 'PUT'):
kwargs.update({
'data': self.request.POST,
'files': self.request.FILES,
})
return kwargs
def get_context_data(self, **kwargs):
"""Insert the form into the context dict."""
if 'form' not in kwargs:
kwargs['form'] = self.get_form()
return super().get_context_data(**kwargs)
And I made the comment about where to make the query for your form field because by doing it in the field declaration, you're going to be querying the database when your application starts, rather than when you create an instance of the form. This can lead to errors, though I can't recall exactly what error.