Search code examples
djangodjango-formsdjango-admin

get_form_kwargs being omitted


I have a simple admin form:

class SomeForm(forms.ModelForm):
    
    class Meta:
        model = Process
        fields = ["start", "end", "result", "description", "user"]

    def __init__(self, user=None, *args, **kwargs):
        user = kwargs.pop("user", None)    
        super().__init__(*args, **kwargs)
        self.fields["user"].initial = user

The form is being instanciated by a normal ModelAdmin:

class SomeAdmin(admin.ModelAdmin):
    form = SomeForm

    def get_form_kwargs(self, request):
        return {"user": request.user}
    
    def get_form(self, request, obj=None, change=False, **kwargs):
        form = super().get_form(request, obj, change, **kwargs, **self.get_form_kwargs(request))
        return form

The output of the print statement is never visible in the terminal. Why? I want to be able to access the "user" as an initial value in the form:

Edit: Code updated according to @Willem Van Onsem's input (still not working: Error: TypeError saying modelform_factory() got an unexpected keyword argument 'user'.)


Solution

  • Django's ModelAdmin has no get_form_kwargs, yes I know that is strange, since it has a .get_formset_kwargs(…) [Django-doc]. But, well, the ModelAdmin is a bit of a misfeature, especially since it is a collection of different views, but it basically violates all patterns the Django views implement. For example it does not make an instance of the view, so self.request is not accessible, since that is the ModelAdmin, not the view object.

    We can do this, but it is ugly, no, really. First we update the form to use self._user as attribute:

    class SomeForm(forms.ModelForm):
        _user = None
    
        class Meta:
            model = Process
            fields = ['start', 'end', 'result', 'description', 'user']
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.fields['user'].initial = self._user

    and now we can each time subclass is and inject the user as attribute:

    class SomeAdmin(admin.ModelAdmin):
    
        def get_form(self, reqmuest, obj=None, change=False, **kwargs):
            class SubSomeForm(SomeForm):
                _user = request.user
            return SomeSubForm

    and that will be the working mechanism.