175

I have a Django form with a RegexField, which is very similar to a normal text input field.

In my view, under certain conditions I want to hide it from the user, and trying to keep the form as similar as possible. What's the best way to turn this field into a HiddenInput field?

I know I can set attributes on the field with:

form['fieldname'].field.widget.attr['readonly'] = 'readonly'

And I can set the desired initial value with:

form.initial['fieldname'] = 'mydesiredvalue'

However, that won't change the form of the widget.

What's the best / most "django-y" / least "hacky" way to make this field a <input type="hidden"> field?

daaawx
  • 3,273
  • 2
  • 17
  • 16
Amandasaurus
  • 58,203
  • 71
  • 188
  • 248

12 Answers12

263

This may also be useful: {{ form.field.as_hidden }}

Community
  • 1
  • 1
semente
  • 7,265
  • 3
  • 34
  • 35
  • 6
    This is the best answer IMHO. I've always hated using my "controller" Python code to determine the display of a form field. – trpt4him Jun 29 '18 at 13:27
  • 1
    I often make generic form template with crispyforms. If you use crispyforms or you display fields in a simple forloop because you want your form structure in your form class, the widget overriding in the form is the good way to do it. Bu if you manage your form rendering into your template, indeed, this solution is much more clear/clean. – christophe31 Aug 28 '19 at 14:00
  • It's worth noting that this seems to erase any classes you've applied to the field beforehand... – John Aaron Jan 03 '20 at 23:38
  • brilliant, helped me a lot – callmebob Mar 29 '22 at 07:41
221

If you have a custom template and view you may exclude the field and use {{ modelform.instance.field }} to get the value.

also you may prefer to use in the view:

field = form.fields['field_name']
field.widget = field.hidden_widget()

but I'm not sure it will protect save method on post.

edit: field with multiple values don't supports HiddenInput as input type, so use default hidden input widget for this field instead.

starball
  • 20,030
  • 7
  • 43
  • 238
christophe31
  • 6,359
  • 4
  • 34
  • 46
  • 2
    I end up with a `"" is not a valid value for a primary key.` in the is_valid method after using this solution. – Jens Timmerman Jun 05 '14 at 15:21
  • It sounds weird. I think it's related to something else, are you displaying as HiddenInput the primary key of objects you are creating? If yes, you should not. – christophe31 Jun 05 '14 at 19:10
  • Maybe this goes without saying, but you'll need to import forms before this will work. `from django import forms` – teewuane Jul 30 '14 at 22:18
  • 4
    on 1.7 use this syntax : ```hidden_field_name = forms.CharField(label='reset', max_length=256, widget=forms.HiddenInput())``` where the key is the newer widget syntax on the end. Tweak for your needs. – Marc Oct 31 '14 at 22:27
87

an option that worked for me, define the field in the original form as:

forms.CharField(widget = forms.HiddenInput(), required = False)

then when you override it in the new Class it will keep it's place.

SuperBiasedMan
  • 9,814
  • 10
  • 45
  • 73
Shay Rybak
  • 1,193
  • 1
  • 9
  • 9
54

Firstly, if you don't want the user to modify the data, then it seems cleaner to simply exclude the field. Including it as a hidden field just adds more data to send over the wire and invites a malicious user to modify it when you don't want them to. If you do have a good reason to include the field but hide it, you can pass a keyword arg to the modelform's constructor. Something like this perhaps:

class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel
    def __init__(self, *args, **kwargs):
        from django.forms.widgets import HiddenInput
        hide_condition = kwargs.pop('hide_condition',None)
        super(MyModelForm, self).__init__(*args, **kwargs)
        if hide_condition:
            self.fields['fieldname'].widget = HiddenInput()
            # or alternately:  del self.fields['fieldname']  to remove it from the form altogether.

Then in your view:

form = MyModelForm(hide_condition=True)

I prefer this approach to modifying the modelform's internals in the view, but it's a matter of taste.

rych
  • 1,157
  • 2
  • 9
  • 12
  • 12
    just simple tip, kwargs.pop('hide_condition', False) instead of kwargs['hide_condition']. you'll handle the no arg case, have a default and del in the same time. – christophe31 Jul 29 '11 at 11:55
  • 2
    thanks for the tip, christophe31. I've updated with your suggestion, as it makes the code much clearer. – rych Aug 01 '11 at 18:49
  • 2
    Is it possible to hide the field with this approach completely? Like if you set on `class Meta: exclude = ["fieldname"]`. Problem here is, that the Meta-approach is "static", but I need something dynamic. See http://stackoverflow.com/questions/20243735/django-show-admin-field-on-demand/20244351 – Themerius Nov 28 '13 at 12:50
  • You cab di def __init__(self, hide_condition=True, *args, **kwargs) which is the cleanest way... – Visgean Skeloru Mar 27 '15 at 17:09
39

For normal form you can do

class MyModelForm(forms.ModelForm):
    slug = forms.CharField(widget=forms.HiddenInput())

If you have model form you can do the following

class MyModelForm(forms.ModelForm):
    class Meta:
        model = TagStatus
        fields = ('slug', 'ext')
        widgets = {'slug': forms.HiddenInput()}

You can also override __init__ method

class Myform(forms.Form):
    def __init__(self, *args, **kwargs):
        super(Myform, self).__init__(*args, **kwargs)
        self.fields['slug'].widget = forms.HiddenInput()
anjaneyulubatta505
  • 10,713
  • 1
  • 52
  • 62
9

If you want the field to always be hidden, use the following:

class MyForm(forms.Form):
    hidden_input = forms.CharField(widget=forms.HiddenInput(), initial="value")

If you want the field to be conditionally hidden, you can do the following:

form = MyForm()
if condition:
    form.fields["field_name"].widget = forms.HiddenInput()
    form.fields["field_name"].initial = "value"
Zags
  • 37,389
  • 14
  • 105
  • 140
  • 1
    @Ashley It's different in a critical way. ShayRybak's answer doesn't include how to add a value to the hidden input, which my answer does – Zags Jan 04 '21 at 03:08
  • @Ashley It was. The question asks "what is the least hacky way to make a hidden field". If the field is always hidden (as stipulated in my answer), it is far better to set the value in the field definition – Zags Jan 04 '21 at 03:15
3

Example of a model:

models.py

from django.db import models


class YourModel(models.Model):
    fieldname = models.CharField(max_length=255, default="default")

In your form, you can add widgets with ModelForm. To make it hidden add 'type': 'hidden' as shown below

forms.py

from .models import YourModel
from django import forms


class YourForm(forms.ModelForm):


    class Meta:
        model = YourModel
        fields = ('fieldname',)

        widgets = {
            'fieldname': forms.TextInput(attrs={'type': 'hidden'}),
        }

If you don't know how to add it to your views.py file, here is some videos about it.

If you use Function Based View:

https://www.youtube.com/watch?v=6oOHlcHkX2U


If you use Class Based View:

https://www.youtube.com/watch?v=KB_wDXBwhUA

AnonymousUser
  • 690
  • 7
  • 26
2
{{ form.field}}
{{ form.field.as_hidden }}

with this jinja format we can have both visible form fields and hidden ones too.

  • 1
    The solution to use `{{ form.field.as_hidden }}` was already given in [this answer](https://stackoverflow.com/a/7490785/2745495). – Gino Mempin Nov 23 '21 at 02:46
2

if you want to hide and disable the field to protect the data inside. as others mentioned use the hiddenInput widget and make it disable

in your form init

example:

        if not current_user.is_staff:
           self.base_fields['pictureValid'].disabled = True
           self.base_fields['pictureValid'].widget = forms.HiddenInput()
Amir jodat
  • 569
  • 6
  • 13
1

With render_field is easy {% render_field form.field hidden=True %}

0

Disclaimer: I am a junior in Django. This answer is a working solutions; however, it may contain some sub-optimal practices. If that is the case, please let me know in the comments, and I will adjust it.

To expand on Rybak's and Zags's answers, if you want to use the HiddenInput field in multiple places, you could create a custom hidden field class.

class MyHiddenCharField(forms.CharField):
    def __init__(self, *, required=False, **kwargs):
        self.required = required
        self.widget = forms.HiddenInput()
        super().__init__(required=False, **kwargs)
Jakub Holan
  • 303
  • 1
  • 8
-4

You can just use css :

#id_fieldname, label[for="id_fieldname"] {
  position: absolute;
  display: none
}

This will make the field and its label invisible.

dwitvliet
  • 7,242
  • 7
  • 36
  • 62
user20310
  • 31
  • 1