4

How do you alter fields in each form of a Django formset using the clean method?

class MyInlineFormSet(BaseInlineFormSet):

    def clean(self):
        if self.cleaned_data['inputted'] == self.cleaned_data['answer']:
            self.cleaned_data['is_correct'] = True
        return self.cleaned_data

This isn't working and I've seen people iterate over each form but they only validate and not alter. If I iterate over each form how do I then return the cleaned_data? In other words:

class MyInlineFormSet(BaseInlineFormSet):

    def clean(self):    
        for form in self.forms:
            if form.cleaned_data['inputted'] == form.cleaned_data['answer']:
                form.cleaned_data['is_correct'] = True
        ...?
P̲̳x͓L̳
  • 3,615
  • 3
  • 29
  • 37
ssomnoremac
  • 729
  • 1
  • 8
  • 16

2 Answers2

2

Based on ssomnoremac comment, I used form.instance.field_i_wanted_to_change in the BaseModelFormSet clean method instead of form.cleaned_data['field_i_wanted_to_change'] and it worked. Something like

class MyInlineFormSet(BaseInlineFormSet):

def clean(self):
    for form in self.forms:
        if form.cleaned_data['inputted'] == form.cleaned_data['answer']:
            form.instance.is_correct = True

In my case, I had already called clean_field_i_wanted_to_change, so the order is clean_field > clean @ MyInlineFormSet Django 1.11

  • I am facing an exact similar situation. In my formset one of the fields is a boolean with default as `False`. Within the `for form in self.forms:` I am running a check and trying to **change** the boolean's status to `True` but not working. My code goes like this: `if someVar < someValue:` `if form.cleaned_data['myBool'] == False:` `form.instance.myBool = True`. Somehow I am unable to make this work. – Love Putin Not War Apr 27 '22 at 13:24
0

I believe you are on the right track by iterating through each form and setting the cleaned data (your second example). BaseFormSet has a property called cleaned_data that returns a list of the cleaned data for each form. Is that what you want? E.g.:

return self.cleaned_data

It literally returns:

[form.cleaned_data for form in self.forms]

which should have the correct data (as modified), if I'm reading the code correctly.

If you are only interested in saving the value in your model, I suggest you avoid the clean method and instead override the save methods:

def save_new(self, form, commit=True):
    form.instance.is_correct = ...
    return super(...).save_new(...)

def save_existing(...)
DavidM
  • 1,417
  • 1
  • 13
  • 16
  • 2
    David, thanks. Your answer is right about self.cleaned_data but that still didn't change the field. The problem was cleaned_data is only an accessor not a modifier. What I needed instead: 'form.instance.is_correct = True' form.instance actually modifies the field as explained in the docs [https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#overriding-clean-on-a-modelformset] – ssomnoremac Mar 31 '14 at 17:03
  • Added to my answer. I'm glad you figured it out and I think this is a useful question, since inline forms need to be handled a bit differently than normal forms. Feel free to submit your own answer if mine doesn't say what you want. – DavidM Mar 31 '14 at 19:00