Форма Django с BooleanField всегда недействительна, если не проверена
У меня есть приложение, которое использует следующую форму:
class ConfirmForm(forms.Form):
account_name = forms.CharField(widget=forms.HiddenInput)
up_to_date = forms.BooleanField(initial=True)
Я использую форму в следующем шаблоне exerpt:
<form class="confirmform" action="/foo/" enctype="multipart/form-data" method="post">
{{ confirm_form.up_to_date }} Check if this data brings the account up to date.<br>
{{ confirm_form.account_name }} <input type="submit" name="confirm" value="Confirm" />
</form>
В моем представлении используется следующая базовая структура кода:
if request.method == 'POST':
#check for 'confirm' because I actually have multiple forms in this page
if 'confirm' in request.POST:
confirm_form = ConfirmForm(request.POST)
if confirm_form.is_valid():
#do stuff
else:
c['confirm_form'] = confirm_form
else:
c['confirm_form'] = ConfirmForm({'account_name':'provided_value'})
Две вещи ошибочны:
1) Несмотря на то, что у меня есть initial = True, флажок не установлен, когда страница загружается
2) Форма всегда недействительна, если я не установил флажок. Он дает ошибки только для up_to_date: "Это поле необходимо".
Я прочитал этот похожий вопрос, но его решение не относится к моему проекту.
Итак... что происходит?
Edit:
Я обновил приведенный выше код, чтобы быть более верным моему фактическому коду.
Проблема №1 была моей ошибкой, потому что я переопределял начальное значение путем привязки данных при создании экземпляра формы.
Проблема №2 Я все еще рассматриваю проблему. Использование required=False
на up_to_date
устранит проблему, однако не представляется правильным, что с использованием виджета по умолчанию a BooleanField
может быть либо NULL
(вызывает проверку достоверности) или True
, но никогда False
.
Ответы
Ответ 1
initial=True
должен отображать виджет с checked="checked"
, поэтому я не вижу проблемы там.. но причина, по которой форма недействительна, состоит в том, что по умолчанию все поля требуются, если вы не указали иначе.
Field.required¶ По умолчанию каждый класс Field предполагает, что значение равно требуется, поэтому, если вы передадите пустое значение - либо None, либо пустое string ("") - then clean() приведет к возникновению исключения ValidationError:
Если вы хотите, чтобы флажок или любое другое значение было необязательным, вам нужно передать required=False
в конструктор поля формы.
up_to_date = forms.BooleanField(initial=True, required=False)
# no longer required..
Ответ 2
В формах Django булевые поля должны быть созданы с помощью required=False
.
Если флажок не установлен, браузеры не отправляют поле в параметрах POST запросов. Не указывая, что поле является необязательным, Django будет рассматривать это как недостающее поле, если не в параметрах POST.
Imho было бы неплохо, если бы Django по умолчанию выполнял это поведение для полей логической формы.
(об этом уже ответили в комментариях Юдзи, но это было бы полезно в качестве ответа)
Ответ 3
В соответствии с официальными документами:
Если вы хотите включить логическое выражение в свою форму, которое может быть либо True
, либо False
(например, флажок отмечен или не отмечен), вы должны помнить, чтобы передать required=False
, когда создавая BooleanField.
Ответ 4
Убедитесь, что вы не перезаписываете начальную форму при первом загрузке страницы.
Я изначально не проверял, было ли что-нибудь в запросе .GET. В первый раз, когда страница загружает request.GET - None, а вызов SomeForm (request.GET) фактически уничтожит начальные значения.
def some_view(request):
form = SomeForm()
if request.method == 'GET':
form = SomeForm(request.GET)
Добавление проверки, чтобы убедиться, что в запросе есть что-то. GET исправил это.
def some_view(request):
form = SomeForm()
if request.method == 'GET' and request.GET:
form = SomeForm(request.GET)
Ответ 5
Если вы сделаете, как предложено, ваше поле up_to_date, скорее всего, всегда будет False. И вы никогда не узнаете, потому что пользователь этого хочет или потому, что пользователь пропустил поле!
У меня та же проблема с юридически обязательным вопросом OPT_IN. При регистрации мне нужно, чтобы пользователь принял решение совести, чтобы разрешить моей системе отправлять им нежелательные электронные письма (или нет). Я работаю с Джанго-Аллахом и пользовательской базой данных.
Ниже я поделюсь своим решением в надежде, что вы сможете адаптировать его к вашей ситуации - я адаптировал его из DOCS.
forms.py:
# ExtraFieldsSignup as per https://stackoverflow.com/a/12308807
class SignupFormExtraFields(forms.Form):
CHOICES = (('1', 'YES, keep in touch',), ('2', 'No',))
first_name = forms.CharField(max_length=30, label='Voornaam')
last_name = forms.CharField(max_length=30, label='Achternaam')
opt_in = forms.ChoiceField(widget=forms.RadioSelect, choices=CHOICES)
def signup(self, request, user):
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
# Now we figure out what the user chose:
if self.cleaned_data['opt_in'] == '1':
user.opt_in = True
else:
user.opt_in = False
user.save()
Ответ 6
Просто догадка, но это может быть из-за основ - потерял несколько часов, пока не понял, что нечто похожее было только о базовых типах переменных.
В моем случае после создания ФОРМЫ (очень простой, см. Ниже)
class para_selection(forms.Form):
first=forms.BooleanField(initial=False, required=False)
second=forms.BooleanField(initial=False, required=False)
third=forms.BooleanField(initial=False, required=False)
fourth=forms.BooleanField(initial=False, required=False)
... Я использовал if selection == 'True':.. на мой взгляд. Но так как форма использует логические значения, правильный код будет следующим: если выбор равен True:
Первая строка никогда не будет работать, потому что "==" не используется с логическим типом. Надеюсь, что это не так, но я хотел пометить это здесь, так как я продолжал пробовать и искать по всему Интернету, не обращая внимания на тип переменной, которую я использовал.