Behaviour of Django's forms.ModelForm.save(): Why does models.save_instance not work via parent?

StackOverflow https://stackoverflow.com/questions/22113844

  •  18-10-2022
  •  | 
  •  

Question

I am using class based views, but the forms have two underlying models, instead of one. So the "main" form (the Employee, the view knows about) has another form object.

The model of the Shift has a pkey, referencing one element of the Employees.

I would like to know, why this is not working:

class ShiftSubForm(forms.ModelForm):

   def __init__(self, *args, **kwargs):
     super( ShiftSubForm, self).__init__(*args, **kwargs)
     ... some adjustment of widgets, deleting and adding form fields

   class Meta:
      model=Shift


class EmployeeForm(forms.ModelForm):
   second_form = None

   def __init___(self, *args, **kwargs):
     kwargs.update({'instance': kwargs['shift']})
     del kwargs['shift']
     self.second_form = ShiftSubForm(*args, **kwargs)

   def save(self):
      employee = super(ShiftSubForm, self).save()
      self.second_form.cleaned_data.update({'employee': employee})
      self.second_form.save()

   class Meta:
      model = Employee

I'd expect the save() in the Parents of ShiftSubForm to call models.save_instance(..) and to save the data. But it fails, with an integrity error because employee_id is Null. So the employee object didn't make it into the save.

But, if i call it directly, it works:

class ShiftSubForm(forms.ModelForm):
   ... as above ...

   def save(self):
      return models.save_instance(self, self.instance, self._meta.fields, 
            fail_message, True, exclude=self._meta.exclude)  

What am i missing?

EDIT: Can't answer myself, so here ...

Think that this might be the best way?

class ShiftSubForm(forms.ModelForm):
   ... as above ...

   def createInstanceWith(self,employee):
       self.save(commit=False)              # prepares self.instance
       self.instance.employee = employee

class EmployeeForm(forms.ModelForm):
   ...

   def save(self):
      employee = super(ShiftSubForm, self).save()
      self.second_form.full_clean()   # populates its self.cleaned_data
      self.second_form.createInstanceWith(employee)
      self.second_form.save()

PS: Ignore typos - this is not the real code. But it has everything, that fumbles around with the forms

Était-ce utile?

La solution

Don't update the cleaned_data. Call save() with commit=False, set the employee then save it to the db.

class EmployeeForm(forms.ModelForm):
    second_form = None

    def save(self):
        employee = super(ShiftSubForm, self).save()
        shift = self.second_form.save(commit=False)
        shift.employee = employee
        shift.save()
        return employee

    class Meta:
        model = Employee
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top