Object level permissions in Django admin

Viewed 7197

I have a model which looks like this:

class Change(models.Model):
    RFC = models.CharField(max_length=10)
    Ticket_Number = models.CharField(max_length=10)
    Plan_Owner = models.ForeignKey(User)

I then register the model in the Django admin via this:

class ChangeAdmin(admin.ModelAdmin):
    search_fields = ('RFC', 'Ticket_Number','Plan_Owner')
    list_display = ('RFC', 'Ticket_Number','Plan_Owner')

    fieldsets = [
        ('Ticket Details', {
            'fields': ['RFC', 'Ticket_Number', 'Plan_Owner']}),
    ]

admin.site.register(Change, ChangeAdmin)

What I want to achieve is to ensure that the Plan_owner for a particular change is the only one who can edit it apart from a superuser. Everyone can view it, but the plan owner is the only one who can make changes to it.Also by editing I mean, he can do ever thing but delete a row. I have had a look at Django guardian and it does exactly what I want but one has to manually set the permissions in guardian for each row. I am looking for a solution wherein these permissions are automatically set as per my requirements ...

2 Answers

You can easily do this by overriding the get_queryset() of ModelAdmin class. So get_queryset() is the place where querying all the objects to display in the Admin Site. For example if you return Change.objects.all() in get_queryset(), will display all the objects in you Change model in Admin Site. If you return Change.objects.none() in get_queryset(), will not display any values in Change model in Admin Site.

This is what documentation mention about get_queryset().

Returns the queryset that will be used to retrieve the object that this view will display. By default, get_queryset() returns the value of the queryset attribute if it is set, otherwise it constructs a QuerySet by calling the all() method on the model attribute’s default manager.

I just override get_queryset() in your ChangeAdmin class.

class ChangeAdmin(admin.ModelAdmin):
    model = Change
    search_fields = ('RFC', 'Ticket_Number','Plan_Owner')
    list_display = ('RFC', 'Ticket_Number','Plan_Owner')

        fieldsets = [
        (
            'Ticket Details', {
                'fields': ['RFC', 'Ticket_Number', 'Plan_Owner']
            }
        ),
    ]

    def get_queryset(self, request):
        if request.user.is_superuser:
            return Change.objects.all()
        
        try:
            return Change.objects.filter(plan_owner_id=request.user.id)
        except:
            return Change.objects.none()


admin.site.register(Change, ChangeAdmin)

According to this example, if the superusers logged into the admin site they will see all the objects in the Change model. If other users who are in the Change table will display their own objects (because in this example, it's filter from according to the Plan_Owner of Change model), otherwise nothing display in Admin Site.

Related