#27240: Passing custom parameters to formset forms in admin -------------------------------------+------------------------------------- Reporter: arogachev | Owner: nobody Type: Uncategorized | Status: new Component: Documentation | Version: master Severity: Normal | Resolution: Keywords: admin, form, | Triage Stage: formset, parameter | Unreviewed Has patch: 0 | Needs documentation: 0 Needs tests: 0 | Patch needs improvement: 0 Easy pickings: 0 | UI/UX: 0 -------------------------------------+------------------------------------- Changes (by arogachev):
* component: contrib.admin => Documentation Old description: > I have `Enterprise` model and related model `Attachment`. Attachments are > managed using formsets in both frontend and backend. > > I use custom form to handle attachments, and it uses additional `user` > kwarg: > > {{{#!python > def __init__(self, *args, **kwargs): > self.user = kwargs.pop('user', None) > super(AttachmentForm, self).__init__(*args, **kwargs) > }}} > > I need to fill this parameter with `request.user` value. In frontend I > use the method recommended in > [https://docs.djangoproject.com/en/1.9/topics/forms/formsets/#passing- > custom-parameters-to-formset-forms docs] (code omitted for brevity). > > {{{#!python > enterprise = Enterprise() > AttachmentFormSet = generic_inlineformset_factory(Attachment, > form=AttachmentForm, max_num=3, validate_max=True) > if request.method == 'POST': > attachment_formset = AttachmentFormSet(request.POST, request.FILES, > instance=enterprise, form_kwargs = {'user': request.user}) > else: > attachment_formset = AttachmentFormSet(instance=enterprise, > form_kwargs = {'user': request.user}) > }}} > > But docs do not cover how achieve the same thing in backend using Django > Admin. > > In admin I have: > > {{{#!python > class AttachmentInline(GenericTabularInline): > model = Attachment > form = AttachmentForm > > class EnterpriseAdmin(MyCompareVersionAdmin): > inlines = [AttachmentInline] > }}} > > It's unclear where and how we need to grab and pass `request.user` > parameter to `AttachmentForm`. After some trial and error, I ended up > with this workaround: > > {{{#!python > class EnterpriseAdmin(admin.ModelAdmin): > inlines = [AttachmentInline] > > def save_related(self, request, form, formsets, change): > AttachmentForm.user = request.user > super(EnterpriseAdmin, self).save_related(request, form, > formsets, change) > }}} > > Related modifications in `AttachmentForm`: > > {{{#!python > user = None > > def __init__(self, *args, **kwargs): > user = kwargs.pop('user', None) > if user: > self.user = user > super(AttachmentForm, self).__init__(*args, **kwargs) > }}} > > So I turned `user` to class attribute and set it from kwargs only if it's > passed and it's not `None`. > > It works, but I don't like this approach and It looks like a hack for me. > > I think the solution on how to properly do it should be added to the docs > in the same section along with frontend solution. New description: I have `Enterprise` model and related model `Attachment`. Attachments are managed using formsets in both frontend and backend. I use custom form to handle attachments, and it uses additional `user` kwarg: {{{#!python def __init__(self, *args, **kwargs): self.user = kwargs.pop('user', None) super(AttachmentForm, self).__init__(*args, **kwargs) }}} I need to fill this parameter with `request.user` value. In frontend I use the method recommended in [https://docs.djangoproject.com/en/1.9/topics/forms/formsets/#passing- custom-parameters-to-formset-forms docs] (code omitted for brevity). {{{#!python enterprise = Enterprise() AttachmentFormSet = generic_inlineformset_factory(Attachment, form=AttachmentForm, max_num=3, validate_max=True) if request.method == 'POST': attachment_formset = AttachmentFormSet(request.POST, request.FILES, instance=enterprise, form_kwargs = {'user': request.user}) else: attachment_formset = AttachmentFormSet(instance=enterprise, form_kwargs = {'user': request.user}) }}} But docs do not cover how achieve the same thing in backend using Django Admin. In admin I have: {{{#!python class AttachmentInline(GenericTabularInline): model = Attachment form = AttachmentForm class EnterpriseAdmin(MyCompareVersionAdmin): inlines = [AttachmentInline] }}} It's unclear where and how we need to grab and pass `request.user` parameter to `AttachmentForm`. After some trial and error, I ended up with this workaround: {{{#!python class EnterpriseAdmin(admin.ModelAdmin): inlines = [AttachmentInline] def save_related(self, request, form, formsets, change): AttachmentForm.user = request.user super(EnterpriseAdmin, self).save_related(request, form, formsets, change) }}} Related modifications in `AttachmentForm`: {{{#!python user = None def __init__(self, *args, **kwargs): user = kwargs.pop('user', None) if user: self.user = user super(AttachmentForm, self).__init__(*args, **kwargs) }}} So I turned `user` to class attribute and set it from kwargs only if it's passed and it's not `None`. It works, but I don't like this approach and It looks like a hack for me. I think the solution on how to properly do it should be added to the docs in the same section along with frontend solution. I'm not sure If I can't find the proper way to do that or it's really not implemented for admin. -- -- Ticket URL: <https://code.djangoproject.com/ticket/27240#comment:7> Django <https://code.djangoproject.com/> The Web framework for perfectionists with deadlines. -- You received this message because you are subscribed to the Google Groups "Django updates" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-updates+unsubscr...@googlegroups.com. To post to this group, send email to django-updates@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-updates/067.59af14ee834798b578854d53dd6a798b%40djangoproject.com. For more options, visit https://groups.google.com/d/optout.