Подтвердить что ты не робот

Форма 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.

4b9b3361

Ответ 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:

Первая строка никогда не будет работать, потому что "==" не используется с логическим типом. Надеюсь, что это не так, но я хотел пометить это здесь, так как я продолжал пробовать и искать по всему Интернету, не обращая внимания на тип переменной, которую я использовал.