Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Object level permissions in Django admin

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 ...

like image 789
Amistad Avatar asked Dec 21 '13 19:12

Amistad


People also ask

What is object level permissions in Django?

Object level permissions are used to determine if a user should be allowed to act on a particular object, which will typically be a model instance.

How do I give permission to admin in Django?

The Django admin site uses permissions as follows: Access to view objects is limited to users with the “view” or “change” permission for that type of object. Access to view the “add” form and add an object is limited to users with the “add” permission for that type of object.

Does DRF have object permissions?

In DRF, object level permissions are used to decide if a user should be allowed to interact with a particular object. The object is usually simply a model instance.

How do I restrict access to parts of Django admin?

Django admin allows access to users marked as is_staff=True . To disable a user from being able to access the admin, you should set is_staff=False . This holds true even if the user is a superuser. is_superuser=True .


1 Answers

I wouldn't use object-level permission for something as simple as your requirement. You just need to have an owner ForeignKey to your Model and only allow the owner of each object to modify it (you can use the Plan_Owner -- PLEASE change it to plan_owner and Ticket_Number to ticket_number to be compatible with pep 8 and django style guide).

I have written a post that describes how to do this in django:

http://spapas.github.io/2013/11/05/django-authoritiy-data/

Actually I am describing how to use authorities that users belong to and each user can edit the objects of his authority but your requirement is covered.

Update

For completeness, I am adding the implementation here:

Your Create and Update Class Based Views have to pass the request to your forms and also your Detail and Update CBV should allow only getting objects that belong to the user (let's suppose that your model is named UserData:

class UserDataCreateView(CreateView):
  model=models.UserData

  def get_form_kwargs(self):
      kwargs = super(UserDataCreateView, self).get_form_kwargs()
      kwargs.update({'request': self.request})
      return kwargs

class UserDataDetailView(DetailView):
  def get_object(self, queryset=None):
      obj = super(UserDataDetailView, self).get_object(queryset)
      if not user_has_access(obj, self.request):
          raise Http404(u"Access Denied")
      return obj

class UserDataUpdateView(UpdateView):
  model=models.AuthorityData

  def get_form_kwargs(self):
      kwargs = super(UserDataUpdateView, self).get_form_kwargs()
      kwargs.update({'request': self.request})
      return kwargs

  def get_object(self, queryset=None):
      obj = super(UserDataUpdateView, self).get_object(queryset)
      if not user_has_access(obj, self.request):
          raise Http404(u"Access Denied")
      return obj

It checks if the request.user has permission (is the owner of the object) and also passes the request to the ModelForm. The has_access function defined above just checks if the current user is the owner of the object:

def has_access(obj, req):
    if req.user == obj.owner:
        return True
    return False

Yot ModelForm should be like this (same for create/update):

class UserDataModelForm(forms.ModelForm):
    class Meta:
      model = models.UserData
      exclude = ('owner',)

    def __init__(self, *args, **kwargs):
      self.request = kwargs.pop('request', None)
      super(ActionModelForm, self).__init__(*args, **kwargs)

    def save(self, force_insert=False, force_update=False, commit=True):
      obj = super(UserDataModelForm, self).save(commit=False)
      if obj:
          obj.owner = self.request.user
          obj.save()
      return obj

It removes request from kwargs and sets it as an attribute and at save it sets the owner of the object to the reqest.user.

like image 103
Serafeim Avatar answered Sep 20 '22 18:09

Serafeim