Opened 8 years ago

Last modified 8 years ago

#27240 closed New feature

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

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

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

enterprise = Enterprise()
AttachmentFormSet = generic_inlineformset_factory(Attachment, form=AttachmentForm, max_num=3, validate_max=True)
if request.method == 'POST':
    form = EnterpriseForm(request.POST, request.FILES, instance=enterprise, user=request.user)
    attachment_formset = AttachmentFormSet(request.POST, request.FILES, instance=enterprise, form_kwargs = {'user': request.user})
    # ...
else:
    form = EnterpriseForm(instance=enterprise, user=request.user)
    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
    readonly_fields = ('is_image', 'user', 'created_at')
    max_num = 3

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(MyCompareVersionAdmin):
    inlines = [AttachmentInline]

    def save_related(self, request, form, formsets, change):
        AttachmentForm.user = request.user
        super(MyCompareVersionAdmin, 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 (0)

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