permissionswagtailmodeladmin

Is there a way to make data visible per user in wagtail modeladmin?


I'm adding a family tree manager in wagtail admin ModelAdmin, the structure is something like this:

Clients/
    Management
    Family Tree/
        Person/

So I need to make sure that every family tree and Person (members of the family tree) are available just to the user that input the data (and the admin).

It's my first time with wagtail, I just read the docs but any advice is welcome :)


Solution

  • Filtering on the model admin view

    On your ModelAdmin class, you should define get_queryset to filter the items shown on the list view as per your need.

    However it would only not display the items, a user would still be able to access other items by modifying the URL. To prevent that, you'll want to define a permission_helper_class and set the user_can_inspect, user_can_create, user_can_edit and user_can_delete methods to return True/False accordingly.

    Assigning the user to the created object

    Based on your comment below, let's assume you have the following model definition:

    from django.conf import settings
    from django.db import models
    
    class FamilyTree(models.Model):
        managed_by = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=False)
        # Some other fields.
    

    Note that null=False will fail if you already have some entries in the database. If that's the case, you'll have to create some custom migrations.

    In order to assign the user creating an object with the object itself, you'll have to override the CreateView of the model admin with a custom one.

    from django.forms.widgets import HiddenInput
    from wagtail.contrib.modeladmin.views import CreateView
    
    class FamilyTreeCreateView(CreateView):
        def get_form(self):
            form = super().get_form()
            form.fields['managed_by'].widget = HiddenInput()
            return form
    
        def get_form_kwargs(self):
            kwargs = super().get_form_kwargs()
            kwargs['data']['managed_by'] = self.request.user  # Add the data so the form validates properly.
            return kwargs
    

    Note that this way, it will output a hidden managed_by form field which you later set to the correct value. If that's an issue for you, you would have to exclude the field and then overwrite the form_valid method. I chose not to because you would have to overwrite the method completely (and experience shows that a given update of Wagtail will differ from your copied implementation and you won't notice), not just override/extend it as the initial method calls form.save() which would fail as the required managed_by field is missing.

    And then set this view on your model admin:

    from wagtail.contrib.modeladmin.options import ModelAdmin
    from myviews import FamilyTreeCreateView
    
    class FamilyTreeAdmin(ModelAdmin):
        create_view_class = FamilyTreeCreateView