Search code examples
django-formswagtaildjango-widgetwagtail-admin

How to find out current logged-in user in widget in Django Wagtail


I have been looking for a way to find out who the current logged-in user is in Django Wagtail so that I could create a widget to render a base setting field to be editable/non-editable. I was able to get some basic logic working but couldn't figure out how to find who the current logged-in user is. Can someone help me find out what's the best and most secure way to go about this?

models.py

    @register_setting
    class AdminSetting(BaseSetting):
      ...
      permitted_retries = models.IntegerField(null=False, default=10)
      panels =[
         FieldPanel('permitted_retries', widget=PermittedRetriesWidget())
      ]
      base_form_class = AdminSettingForm

admin_setting_forms.py

 class AdminSettingForm(WagtailAdminPageForm):

    def __init__(self, user=None, *args, **kwargs):
        self.user = user
        super(AdminSettingForm, self).__init__(*args, **kwargs)
        self.fields['permitted_retries'].widget.user = 'me' # This goes to widget

    def clean(self):
        cleaned_data = super().clean()
        return cleaned_data

    def save(self, commit=True):
        page = super().save(commit=False)
        if commit:
            page.save()
        return page 

widgets.py

    class PermittedRetriesWidget(forms.Widget):
         ...
        def render(self, name, value, attrs=None, renderer=None):
            if self.user.is_superuser:
               return format_html(f'<input type="hidden" name="{name}" value="{value}" id="id_{name}">')
            else:
               output = f'<div style="padding: 1.2em;">{value}</div>'
               input = f'<input type="hidden" name="{name}" value="{value}" id="id_{name}">'
               return format_html(output + input)

Solution

  • I have found another way to do this! This is probably better than ThreadLocal as I have been hearing so much bad things about it. I hope this will help someone out in the future.

    panels.py

    class RequestBoundFieldPanel(FieldPanel):
        def on_request_bound(self):
            if self.widget:
                setattr(self.widget, 'request', self.request)
    

    models.py

    from .panels import RequestBoundFieldPanel(FieldPanel):
    
    @register_setting
    class AdminSetting(BaseSetting):
      ...
      permitted_retries = models.IntegerField(null=False, default=10)
      panels =[
         RequestBoundFieldPanel('permitted_retries', widget=PermittedRetriesWidget())
      ]
      base_form_class = AdminSettingForm
    

    admin_settings_form.py

     class AdminSettingForm(WagtailAdminPageForm):
    
        def __init__(self, user=None, *args, **kwargs):
            super().__init__(*args, **kwargs)
            is_superuser = self.fields['permitted_retries'].widget.request.user.is_superuser or False
    
        def clean(self):
            cleaned_data = super().clean()
            return cleaned_data
    
        def save(self, commit=True):
            page = super().save(commit=False)
            if commit:
                page.save()
            return page 
    

    widgets.py

    class PermittedRetriesWidget(forms.Widget):
         ...
        def __init__(self, attrs=None, *args, **kwargs):
            self.request = kwargs.pop('request', None)
            super().__init__(*args, **kwargs)
    
        def render(self, name, value, attrs=None, renderer=None):
            is_superuser = self.request.user.is_superuser or False
            if is_superuser:
               # Shows the input as it is
               return format_html(f'<input type="number" name="{name}" value="{value}" id="id_{name}">')
            else:
               # Hide the input and show the value as uneditable 
               output = f'<div style="padding: 1.2em;">{value}</div>'
               input = f'<input type="hidden" name="{name}" value="{value}" id="id_{name}">'
               return format_html(output + input)