5

I've got a form like this:

class SomeForm(forms.Form):
 first = forms.IntegerField(max_value= DontWantToSetYet)
 second = forms.IntegerField(max_value= DontWantToSetYet)
 third = forms.IntegerField(max_value= DontWantToSetYet)

How can I set the max_values at runtime? I.E

if request.method == 'POST':
    form = SomeForm(request.POST, max_values = {'first':10,'second':50,'third':666})
    [...]
Robus
  • 8,067
  • 5
  • 47
  • 67

2 Answers2

9

you can set the max values on fields in the __init__ method, as shown here

class SomeForm(forms.Form):
    def __init__(self, max_values, *args, **kwargs):
        super(SomeForm, self).__init__(*args, **kwargs)
        self.fields['first'] = forms.IntegerField(max_value=max_values['first'])
        ...

    first = forms.IntegerField(max_value= DontWantToSetYet)
    second = forms.IntegerField(max_value= DontWantToSetYet)
    third = forms.IntegerField(max_value= DontWantToSetYet)

edit:

self.fields['first'].max_value = max_values['first']

didn't worked when I tried, redefining the field definition like this works

self.fields['first'] = forms.IntegerField(max_value=max_values['first'])
Ashok
  • 10,373
  • 3
  • 36
  • 23
  • 5
    I have a place where I do this from the count of a foreign key set. I do it like this: `self.fields['field_name'].widget.attrs.update({'min': 0, 'max': self.instance.foreignobject_set.count()})`. This way you don't have to instantiate a new widget, and using `.update()` on `attrs`, ensures that you don't overwrite values set elsewhere. – beruic Oct 12 '15 at 13:12
  • 2
    @beruic answer should be accepted one, because it does not overwrite created object – Igor Yalovoy Mar 14 '17 at 19:24
  • @beruic This answer is spot on, just remember to validate the input coming back from the client as this won't apply server-side logic to ACTUALLY restrict the value that is posted (via form.is_valid()). – slumtrimpet Aug 07 '20 at 13:49
3

After reading django source, I came up with something like this:

def __init__(self, max_values, *args, **kwargs):
    super(SendFleetFormOne, self).__init__(*args, **kwargs)
    for name, value in max_values.items():
        if name not in self._done:
            self.fields[name].validators.append(validators.MaxValueValidator(value))
            self._done.append(name)

The checking part is because it would sometimes add the same validator several times (No idea why)

[edit] After checking again, this isn't working as it should. Apparently it always uses the max_values of the first person to use the form - it doesn't make much sense really.

Robus
  • 8,067
  • 5
  • 47
  • 67