Customizing dynamically the edit_handler depending of the type of user

1k views Asked by At

My app have some models that can be edited with modelAdmin. Is it possible that some fieldpanels are hidden to some types of users?

I can't find in the docs how to modify dynamically the edit_handler depending of the type of user.

5

There are 5 answers

1
inostia On

You can sub-class FieldPanel and override the render_as_field and/or render_as_object methods. Within those methods you will have access to the request, which is bound to the model in bind_to_instance (see https://github.com/wagtail/wagtail/blob/master/wagtail/admin/edit_handlers.py#L137).

Here's an example:

from wagtail.admin.edit_handlers import FieldPanel


class CustomFieldPanel(FieldPanel):

    def render_as_field(self):
        if not self.request.user.is_superuser:
            return ''
        return super().render_as_field()
0
Dzmitry Makhrachou On

There is an another way which I found recently (also faced with this problem). If you don't need to hide panel but only make it read-only, you can just create let's say NewFieldPanel inherited from base FieldPanel and override bind_to_instance method (originally found the tip here).

The example of implementation:

class NewFieldPanel(FieldPanel):
    def bind_to_instance(self, instance=None, form=None, request=None):
        # form.fields['managers'].widget = HiddenInput()
        form.fields['managers'].disabled = True
        return super().bind_to_instance(
            instance=instance, form=form, request=request
        )
1
Mike Robinson On

... now, if it were me, I would probably opt to set up two entirely different panels, even though they would be maintained together and would look the same. Because, "sooner or sooner," one view will diverge from the other, and this can add complexity very quickly. Therefore, appealing though it may be to approach this problem by "selectively hiding things," you might come to wish that you hadn't done it this way. I think it's better to have two redundant panels, with a clean implementation for each, than to have two pieces of code that become littered with if-statements ... but that is strictly my opinion.

0
Dzmitry Makhrachou On

In addition to the answer above (can't add comment to it sorry).

Instead of render_as_field sometimes you should use render_as_object. It depends.

0
Neil On

Another approach. Make the required_fields method return an empty list.

# panels.py
from wagtail.admin.edit_handlers import FieldPanel


class PermissionFieldPanel(FieldPanel):
    def __init__(self, *args, permission: str, **kwargs):
        super().__init__(*args, **kwargs)
        self.permission = permission

    def clone_kwargs(self):
        kwargs = super().clone_kwargs()
        kwargs['permission'] = self.permission
        return kwargs

    def required_fields(self):
        if self.request and self.request.user.has_perm(self.permission):
            return super().required_fields()
        return []

# models.py
from wagtail.core.models import Page

form panels import PermissionFieldPanel


class ArticlePage(Page):
    admin_notes = models.TextField(blank=True)

    settings_panels = Page.settings_panels + [
         PermissionFieldPanel('admin_notes', permission='myapp__some_permission'),   
    ]