Пост формы Django не содержит значений
У меня есть простая несвязанная форма:
class TeamMemberMapForm(forms.Form):
remote_id = forms.CharField(widget=forms.HiddenInput())
project = forms.ModelChoiceField(queryset=Project.objects.none())
Инициальные значения заполняются в 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)
На фронтенде я могу выбирать значения, отображая форму следующим образом. Это нормально.
{% block form %}
<form method="post">{% csrf_token %}
<fieldset class="uk-fieldset">
<!-- {{ form.errors }} -->
<!-- {{ form.non_field_errors }} -->
{{ form.as_p }}
</fieldset>
<button class="uk-button uk-button-primary" type="submit">
{% if object %}
Save {{ object }}
{% else %}
Create new entry
{% endif %}
</button>
</form>
{% endblock %}
Далее, представление. Я принимаю запрос и заполняю форму:
def post(self, request, remote_id, remote_name, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
# Do whatever
В итоге форма никогда не проверяется. Осмотр заполненной формы из POST показывает, что значения так и не получены.
<tr>
<th><label for="id_remote_id">Remote id:</label></th>
<td>
<ul class="errorlist"><li>This field is required.</li></ul>
<input class="uk-input uk-text " type="text" name="remote_id" required id="id_remote_id">
</td>
</tr>
<tr>
<th><label for="id_project">Project:</label></th>
<td>
<ul class="errorlist"><li>Select a valid choice. That choice is not one of the available choices.</li></ul>
<select class="uk-select" name="project" required id="id_project">
<option value="">---------</option>
</select>
</td>
</tr>
Объект post, похоже, содержит что-то для 'project', но не для remote_id.
<QueryDict: {'csrfmiddlewaretoken': ['zPpsQSHao0BynQWxotu95LiaeF9otrRte3mjYctQuJXgA5ODNi0u8hDDPBfQWaeK'], 'project': ['10']}>
Что я упускаю?
Вы можете попробовать добавить класс Meta в класс вашей формы:
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']
И выполните эту функцию в файле views.py:
def post(request):
form = TeamMemberMapForm(request.POST)
if form.is_valid():
# Do whatever
render('url to template', 'form': form)
Когда вы используете скрытый ввод, вам нужно передать значение в это поле. Обычно это делается путем передачи в форму словаря;
MyForm(initial={'myfield': "value"})
Как вы впишете это в ваше представление, зависит от вас, но вы могли бы сделать что-то вроде:
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)
И я сделал замечание о том, где сделать запрос для поля формы, потому что, делая это в объявлении поля, вы будете запрашивать базу данных при запуске приложения, а не при создании экземпляра формы. Это может привести к ошибкам, хотя я не могу вспомнить, какая именно ошибка.
Оказалось, что если инициализировать форму пустым набором запросов, то настроить ее уже не удастся. Однако другой способ, похоже, работает.
class TeamMemberMapForm(forms.Form):
remote_id = forms.CharField(widget=forms.HiddenInput())
project = forms.ModelChoiceField(queryset=Project.objects.all())
И отфильтруйте вниз в представлении:
form.fields['project'].queryset = Project.objects.\
filter(owned_by_company=self.request.user.owned_by_company, active=True)
Похоже, это уменьшает количество получаемых результатов.