Search code examples
djangodjango-formsdjango-admin

Django - How to set the request in the admin form?


I have a form that uses the request object:

class FooForm(forms.ModelForm):

    class Meta:
        model = Foo
        fields = ('title', )

    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop('request')
        super().__init__(*args, **kwargs)

In my views, whenever I want to instantiate the form, it is as easy as doing the following:

class FooCreateView(LoginRequiredMixin, CreateView):
    model = Foo
    form_class = FooForm

    def get_form_kwargs(self):
        kwargs = super(FooCreateView, self).get_form_kwargs()
        kwargs.update({'request': self.request})
        return kwargs

Now, I want to use the same form in the admin panel, so I do the following:

class FooAdmin(admin.ModelAdmin):
    form = FooForm

But Boom! It dies:

KeyError at /admin/foo/foo/add/
'request'

I tried to do the following, but it didn't work

def get_form(self, request, *args,  **kwargs):
    form = super(FooAdmin, self).get_form(request, *args, **kwargs)
    form.request = request
    kwargs['request'] = request
    return form

In summary, is there a way to pass the request to the admin form?


Solution

  • The get_form() method only returns the class, not an instance of it. The instantiation of the form is hidden in the add_view and change_view methods of the ModelAdmin. You can somehow work your way around that with creating a new form class in the get_form method:

    def get_form(self, request, obj=None, **kwargs):
    
        FooForm = super(FooAdmin, self).get_form(request, obj, **kwargs)
    
        class RequestFooForm(FooForm):
            def __new__(cls, *args, **kwargs):
                kwargs['request'] = request
                return FooForm(*args, **kwargs)
    
        return RequestFooForm
    

    Otherwise if you just need access during saving you probably can also have a look at the model admin's save_form and save_model methods.