I have a table that contains various types of settings. I want to display and validate each setting differently in a form. For example if the setting is for an integer or for a string.
This is my model
class Setting(models.Model):
SETTING_TYPES = (
(u'1', u'Decimal'),
(u'2', u'Integer'),
(u'3', u'String'),
)
type = models..CharField(max_length=2, choices=SETTING_TYPES)
name = models.CharField(max_length=50, unique=True)
value = models.CharField(max_length=200)
So if the type is 1 I want to restrict form entry and validate against the fact that I'm expecting a decimal. But if the type is 3, I need to show a bigger entry form and validate against the fact im expecting a string.
A few places I can see with possibility to do this is:
- In a custom widget
- By overriding the BaseModelFormSet class to change field properties on init (http://snippets.dzone.com/posts/show/7936)
- by using a custom template filter that will evaluate what the type is and then render the form manually via a custom template for that setting type
- store the type and value together in a jsonfield and use something like http://www.huyng.com/archives/django-custom-form-widget-for-dictionary-and-tuple-key-value-pairs/661/ to alter the display and validation of the setting value in one place..
With option 1, i'm not sure if I use a custom widget on the 'value' field if it will be able to access the 'type' field to determine how to represent the 'value'
I tried option 2, and while I could access the form elements, I could not access the form values to determine the type of the setting (maybe they weren't bound yet?). I think this route might be the simpliest but I will need access to form values..
class BaseSettingFormset(BaseModelFormSet):
def __init__(self, *args, **kwargs):
super(BaseSettingFormset, self).__init__(*args, **kwargs)
for form in self.forms:
# here i would access the type value and then change the widget propeties below
if form.fields['type'] == 3: # DOESN"T WORK :(
# change the widget and field properties
form.fields['value'].help_text='some text'
form.fields['value'].widget = CustomWidget() # or switch from decimal to string widgets..
def editProfile(request, strategy_id):
settingModelFormset = modelformset_factory(profile, formset=BaseSettingFormset)
... retrieve the values and show them..
(while posting this i did find a post that may allow me to bind the form during the init and therefore have access to the value, see django - how can I access the form field from inside a custom widget )
Option 3 works for displaying the field, but not for validating any data. I think I would need to combine it with option 2 to validate it during save.
#Custom template filter
@register.filter(name='show_setting')
def show_setting(form):
setting = field_value(form['type']) # calls another function to retrieve value (works ok)
# render page using custom template that can alter the form to show a small field or text area etc.
# can also add js validations here.. (but no server validations)
if setting:
return render_to_string('setting-'+str(setting)+'.html', { 'form': form })
.
Which method would be best (or is there another way), and how do I complete it? Or am I going about this the wrong way, is there a more djangoesc way to solve my problem?