Django ModelForm Hidden Field to 'True' in only a certain situation?

I've got the following Django Form; it has a field called 'finished', that is hidden. I set the default to False because there is only one situation where I want it set to True.

The problem is that it still marks it as "False" and I can't figure out how to change it in that one situation.

In my views.py I have this:

        context["test_form"] = TestForm(
            instance=self.object, hide_status=True, is_finished=True
        )

the form looks like this:

class TestForm(ModelForm):
    finished = forms.BooleanField(
        widget=forms.HiddenInput(), initial=False, required=False
    )
    status = forms.Select(attrs={"class": "form-control"})

    def __init__(self, *args, **kwargs):
        hide_status = kwargs.pop("hide_status", None)
        is_finished = kwargs.pop("is_finished", None)
        super().__init__(*args, **kwargs)
        self.fields["status"].queryset = Status.objects.filter(active=True)
        self.fields["status"].widget.attrs["class"] = "form-control"
        if hide_status:
            self.fields["status"].widget = HiddenInput()
        if is_finished:
            self.fields["finished"].initial = True

    class Meta:
        model = Test
        fields = ["finished", "status"]

The HTML is super simple:

<form method="post" action="{% url 'my_app:test-update' %}">
{% csrf_token %}
{{ test_form.as_p }}
<button type="submit" class="btn btn-primary">Finish</button>
</form>

The rendered HTML looks like this:

<input type="hidden" name="finished" value="False" id="id_finished">

What is the best way to get that set to True in this case?

You can try setting the value of the hidden field directly in the template before rendering the form. This can be done by using the attrs attribute in the forms.BooleanField to set a custom value for the value attribute.

In the TestForm class, you can update the finished field to include the attrs attribute:

finished = forms.BooleanField(
    widget=forms.HiddenInput(), initial=False, required=False, attrs={'value': 'False'}
)

Then in the view, you can update the value of the attribute based on the is_finished variable:

context["test_form"] = TestForm(
    instance=self.object, hide_status=True, is_finished=True
)

if context["test_form"].is_valid(): context["test_form"].fields['finished'].widget.attrs['value'] = 'True' Finally, in the template, you can display the form as usual:

<form method="post" action="{% url 'my_app:test-update' %}">
    {% csrf_token %}
    {{ test_form.as_p }}
    <button type="submit" class="btn btn-primary">Finish</button>
</form>

This way when the form is displayed, the hidden field will have the correct value and when the form is submitted, it will also have the correct value.

EDIT:

Yes, it is possible to handle the case of the initial value of the 'finished' field in the form's init method.

You can add a parameter, such as is_finished to the form's constructor and use it to set the initial value of the 'finished' field. For example:

class TestForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        is_finished = kwargs.pop('is_finished', False)
        super().__init__(*args, **kwargs)
        self.fields['finished'].initial = is_finished
...

And then in your view you can use the is_finished variable to pass to the form

form = TestForm(request.POST, instance=test, is_finished=True)

You can also use the same approach in the form_valid() method of the UpdateView as you've done, but it's probably better to set the initial value in the init method so that it's done when the form is first created, rather than every time the form is valid.

Back to Top