Django BaseGenericInlineFormSet forms not inheriting FormSet instance as form instance related_object -
i'm using django 1.8 , have image class looks this:
# `child` class class image(models.model): content_type = models.foreignkey(contenttype) object_id = models.positiveintegerfield() related_object = genericforeignkey('content_type', 'object_id') image = models.imagefield(...) def clean(self): related_class = self.content_type.model_class() # validation relies on related_class
and "parent" class has genericrelation it:
# `parent` class class product(models.model): ... images = genericrelation('image')
this (simplified) view:
from django.shortcuts import render, get_object_or_404 django.views.generic import view django.contrib.contenttypes.forms import generic_inlineformset_factory productimageinlineformset = generic_inlineformset_factory( image, extra=1) class productimageview(view): ... def post(self, request, id): product = get_object_or_404(product.objects.by_id(id)) image_formset = productimageinlineformset( request.post, request.files, instance=product) # shouldn't need following 2 lines -> # form in image_formset: # form.instance.related_object = product import ipdb; ipdb.set_trace() if image_formset.is_valid(): image_formset.save() return render(request, self.template, context={'cid': id, 'formset': image_formset})
when inspect formset in ipdb, get:
ipdb> image_formset.forms[0].instance.related_object none true
this causing problems because when image.clean()
error:
django.db.models.fields.related.relatedobjectdoesnotexist: image has no content_type.
if uncomment 2 lines mentioned don't need, works , don't error anymore. isn't automatic linking of forms models , related models whole point of using basegenericinlineformset
? if have manually hack imageform instances , attach product
instance related_object
, might use simple modelformset. missing something?
update
if comment image.clean
out, code works without manual attachment of related objects. means basegenericinlineformset handle linking after all, after calls clean
on child model, not ok considering model.clean "should used provide custom model validation". i'm taking @ django source haven't yet figured out linking. tips welcome.
update 2
apparently linking done in inlineformset 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)
https://github.com/django/django/blob/master/django/contrib/contenttypes/forms.py#l46
as experiment, i've moved code custom _construct_form
method:
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
it solved problem. way don't have manual linking. haven't run tests or written patch first step if decides in future (perhaps myself @ 1 point).
for i'm keeping solution manual linking though. don't want work hacked version of django.
since i've got no feedback, i'll assume it's django bug, , seems case. filed ticket here: https://code.djangoproject.com/ticket/25488
the solution until solved either suggested earlier (i.e. iterating on forms in view , linking them product manually) or using fixed formset class, like:
class fixedbasegenericinlineformset(basegenericinlineformset): 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 productimageinlineformset = generic_inlineformset_factory( image, form=productimageform, formset=fixedbasegenericinlineformset, extra=1 )
Comments
Post a Comment