[Fixed]-Django Forms: Hidden model field?


A hidden field that returns a model? So a model instance ID?

The forms.HiddenInput widget should do the trick, whether on a FK field or CharField you put a model instance ID in.

class MyForm(forms.Form):
    hidden_2 = forms.CharField(widget=forms.HiddenInput())
    hidden_css = forms.CharField(widget=forms.MostWidgets(attrs={'style': 'display:none;'}))

I suppose the fastest way to get this working is

class MyForm(forms.Form):
    model_instance = forms.ModelChoiceField(queryset=MyModel.objects.all(), widget=forms.HiddenInput())

form = MyForm({'model_instance': '1'})

But I don’t like the idea of supplying MyModel.objects.all() if you’re going to specify one item anyways.

It seems like to avoid that behavior, you’d have to override the form __init__ with a smaller QuerySet.

I think I prefer the old fashioned way:

class MyForm(forms.Form):
    model_instance = forms.CharField(widget=forms.HiddenInput())

    def clean_model_instance(self):
        data = self.cleaned_data['model_instance']
        if not data:
            raise forms.ValidationError()
            instance = MyModel.objects.get(id=data)
        except MyModel.DoesNotExist:
            raise forms.ValidationError()
        return instance


The approach in Yuji’s answer uses a clean_model_instance method on the form which is fine if you’re only ever doing this once in your code base. If you do it more often, then you might benefit from implementing a custom model field.

This is the code I have:

from django import forms

class ModelField(forms.Field):

    Model = None

    def prepare_value(self, value):
        """Inject entities' id value into the form's html data"""
        if isinstance(value, self.Model):
            return value.id
        return value

    def to_python(self, value):
        """More or less stolen from ModelChoiceField.to_python"""

        if value in self.empty_values:
            return None

            value = self.Model.objects.get(id=value)
        except (ValueError, self.Model.DoesNotExist):
            raise forms.ValidationError('%s does not exist'
                                         % self.Model.__class__.__name__.capitalize())

        return value

If you use that as a base class and then specialise it with your own models then it becomes a useful based. For example:

# In app/fields.py
from .models import CustomModel

class CustomModelField(ModelField):

    Model = CustomModel

Then you can pair that with whatever widget you need at the time:

# in app/forms.py
class MyForm(forms.Form):

    hidden_custom_model_field = CustomModelField(widget=forms.HiddenInput())

    other_widget_custom_model_field = CustomModelField(widget=MyCustomWidget())

Leave a comment