GRB
GRB

Reputation: 445

Show fields in admin page only if user has specific rights

I'm working on the Django admin site of an online shop, and I'm asked to enable a refund button only to a limited group of admins. The current situation, extremely simplified, is the following:

models.py

class ItemOrder(models.Model)
    [various fields and functions]

admin.py

class ItemOrderAdmin(admin.ModelAdmin):
    fieldsets = [
        ...
        ('Actions', {'fields': ['created', 'modified', 'refund_link']}),
        ]
    ...
    readonly_fields = [..., 'created', 'modified', 'refund_link']

    [other functions]

    def refund_link(self, order):
        ...

At the moment every user with the right to see this page can click on the refund link and refund the order. I need to restrict its visibility/usability only to users who have a specific right. I tried with the @permission_required decorator, but the link is unusable for every user (it becomes "-" for anyone, even superusers). I also tried adding the get_form method to the ItemOrderAdmin class, but the refund link disappears completely for every user. This is how it was implemented:

admin.py

class ItemOrderAdmin(admin.ModelAdmin):
    fieldsets = [
        ...
        ('Actions', {'fields': ['created', 'modified']}),
        ]
    ...
    readonly_fields = [..., 'created', 'modified', 'refund_link']

    def get_form(self, request, obj=None, **kwargs):
        if request.user.is_superuser:  # Will be changed with a more specific right later
            kwargs['form'] = EventTicketOrderPersonForm
        return super().get_form(request, obj, **kwargs)

    [other functions]

    def refund_link(self, order):
        ...

forms.py

class ItermOrderForm(forms.ModelForm):
    class Meta:
        model = ItemOrder
        fields = '__all__'

class Meta:
    model = ItemOrder
    fieldsets = [
        ...
        ('Actions', {'fields': ['created', 'modified', 'refund_link']}),
        ]

This was copied from the official documentation. I tried various variations of this. Mainly I tried removing the second Meta class in forms.py and the refund_link from the readonly_fields in admin.py, but the result is always that the link is missing for every user.

I have to say I'm quite new to Django, and some of the connections it makes between modules are still a bit magical to me. I suspect I'm missing something basic, but I can't find out what it is.

Edit: I managed to make forms work by commenting fieldsets and readonly_fields, but the result is far from what I need. Some fields are missing (the ones defined as functions inside ItemOrderAdmin, e.g. refund_link), all the fields are editable (only a few should be), and they are not divided into sets. It looks to me that forms are not what I'm looking for, but I'm open to suggestions.

Upvotes: 1

Views: 755

Answers (1)

GRB
GRB

Reputation: 445

I may have found the answer. Instead of specifying the fieldsets variable at the beginning of the class, I can define the get_fieldsets method, in this way:

admin.py

class ItemOrderAdmin(admin.ModelAdmin):

    ...
    readonly_fields = [..., 'created', 'modified', 'refund_link']

    [other functions]

    def get_fieldsets(self, request, obj=None):
        fieldsets = [
            ...
            ('Actions', {'fields': ['created', 'modified', 'refund_link']}),
            ]
        if request.user.is_superuser:
            fieldsets[4][1]['fields'].append('refund_link')  # The 4 depends on the fieldsets structure.
        return fieldsets

    def refund_link(self, order):
        ...

I'll wait a few hours before approving my answer, in case someone comes up with a better solution, or there are major flaws in mine.

Upvotes: 2

Related Questions