I've got a Form
. I want to include a hidden field that returns a model. I'll set it's value in the view; I just need it to be p开发者_Python百科osted along to the next page.
What field am I supposed to use in the form class?
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'})
form.cleaned_data['model_instance']
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()
try:
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
try:
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())
精彩评论