Opened 8 years ago

Last modified 8 years ago

#27240 closed New feature

Docs - Passing custom parameters to formset forms in admin — at Version 5

Reported by: Alexey Rogachev Owned by: nobody
Component: contrib.admin Version: dev
Severity: Normal Keywords: admin, form, formset, parameter
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Alexey Rogachev)

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:

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 docs (code omitted for brevity).

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:

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:

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:

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.

Change History (5)

comment:1 by Alexey Rogachev, 8 years ago

Description: modified (diff)

comment:2 by Alexey Rogachev, 8 years ago

Description: modified (diff)

comment:3 by Alexey Rogachev, 8 years ago

Description: modified (diff)

comment:4 by Alexey Rogachev, 8 years ago

Description: modified (diff)

comment:5 by Alexey Rogachev, 8 years ago

Description: modified (diff)
Note: See TracTickets for help on using tickets.
Back to Top