jrief / django-formset

The missing widgets and form manipulation library for Django
https://django-formset.fly.dev/
MIT License
317 stars 30 forks source link

FormCollection self.instance bug due to FormCollection.full_clean() #159

Open codematsing opened 1 month ago

codematsing commented 1 month ago

Given

#models.py
class ParentModel(self):
    name = models.CharField

class ChildModel(self):
    parent = models.ForeignKey(Parent, related_name='children', on_delete=models.CASCADE)
    name = models.CharField

#forms.py
class ChildForm(ModelForm):
  class Meta:
    model = ChildModel()
    fields = '__all__'

class ParentChildFormCollection(FormCollection):
    child_formset = ChildForm()

class UpdateView(SingleObjectMixin, FormCollectionView):
    model = ParentModel
    collection_class = ParentChildFormCollection()

    def get_initial():
      parent_object = self.get_object()
      initial = [
        {"child_form": {child.name for child in parent.children.all()}}
      ]
      return initial

Expectation:

#forms.py
class ParentChildFormCollection():
  def save(self):
    logger.info(self.instance.name)
    logger.info(type(self.instance))
    ...

Actual Results:

Observations:

# in class FormCollection
    def full_clean(self):
       ...
        logger.info(instance) #print parent_name
        if holder.is_valid():
            valid_holders[name] = holder
            logger.info(instance) #prints_child_name
      ...

Note: I'll to replicate this in django-formset using the repo. I'll get back to you on this as I'm swamped at the moment.

codematsing commented 1 month ago

Replicated: https://github.com/jrief/django-formset/compare/releases/1.5...codematsing:django-formset-debug:releases/1.5

How to test:

image

Notes: I did add my workaround so that form collection functionality will not interfere with self.instance data but I bet there's a better approach to this

image

Why is this important:

How I stumbled upon this issue

class CompanyDepartmentUpdateView(SingleObjectMixin, FormCollectionView):
     model = Company
     collection_class = CompanyDepartmentFormset

     def form_collection_valid(self, form_collection):
          form_collection.save()

class FormCollection(FormCollection):
     department_formset = DepartmentForm()

     def save(self):
         for department_kwargs in self.cleaned_data['department_formset']:
               Department.objects.create(company=self.instance, **deparment_kwargs)
jrief commented 1 month ago

Thanks for creating a runnable demo, appreciate that. I'll have a look at it.

codematsing commented 1 month ago

Sure thing! I really love using your library and happy to help on improving on it!