Opened 10 years ago

Closed 10 years ago

#25488 closed Bug (duplicate)

BaseGenericInlineFormSet runs validation methods before linking form instances to their related object

Reported by: Ariel Pontes Owned by: nobody
Component: contrib.contenttypes Version: 1.8
Severity: Normal Keywords: BaseGenericInlineFormSet clean validation
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I have a generic inline FormSet class generated like this:

ProductImageInlineFormset = generic_inlineformset_factory(
    Image, form=ProductImageForm, extra=1)

and initialized like this:

product = get_object_or_404(Product.objects.by_id(id))
        image_formset = ProductImageInlineFormset(
            request.POST, request.FILES, instance=product)

When the individual forms that compose the FormSet are initialized, the "product" object is not linked to their instances. This is only done in the BaseGenericInlineFormSet.save_new method:

def save_new(self, form, commit=True):
    setattr(form.instance, self.ct_field.get_attname(),
        ContentType.objects.get_for_model(self.instance).pk)
    setattr(form.instance, self.ct_fk_field.get_attname(),
        self.instance.pk)
    return form.save(commit=commit)

This causes problem when the Image class needs to do validation across fields:

class Image(models.Model):
    ...
    def clean(self):
        related_class = self.content_type.model_class()
        print(self.content_type.model_class())

The above code results in the following error when trying to save ProductImageInlineFormsets:

django.db.models.fields.related.RelatedObjectDoesNotExist: Image has no content_type.

The linking of Image to Product should be done in the form initialization instead. At first sight, after a quick experiment, overriding the _construct_form instead of the save_new seems to solve the problem:

 def _construct_form(self, i, **kwargs):
     form = super()._construct_form(i, **kwargs)
     setattr(form.instance, self.ct_field.get_attname(),
         ContentType.objects.get_for_model(self.instance).pk)
     setattr(form.instance, self.ct_fk_field.get_attname(),
         self.instance.pk)
     return form

Change History (3)

comment:1 by Tim Graham, 10 years ago

It might be a duplicate of #25431 -- could you check if the problem exists on the stable/1.8.x branch, which will be soon released as 1.8.5?

comment:2 by Ariel Pontes, 10 years ago

The problem described is indeed very similar, but the example given was of a simple ModelFormset, not Generic or Inline. I installed stable/1.8.x and the problem persists. In a way it makes sense, I honestly don't understand how that commit would have solved the problem. It must solve the problem for ModelFormSet only, not BaseGenericInlineFormSet.

Version 0, edited 10 years ago by Ariel Pontes (next)

comment:3 by Tim Graham, 10 years ago

Resolution: duplicate
Status: newclosed

Thanks for looking into it. Upon further investigation, I think this a duplicate of #19255. If you'd like to submit a patch with tests, that will help move the issue forward. Thanks!

Note: See TracTickets for help on using tickets.
Back to Top