Django REST Framework Authentication and Permissions Part 2


In order to complete this tutorial you need to have completed the previous tutorial: Django REST Framework Authentication and Permissions Part 1.


After completing this tutorial you will know how to develop API endpoints so that only authenticated users can add/delete/update Data Entry objects and only provide read only acess for un-authenticated users.


We will now need to adjust the file to ensure that authenticated users will get read and write access and restrict unauthenticated users to only get read only access.

Django Rest Framework has a number of permission classes to restrict access. For our purposes we will want to use the IsAuthenticatedOrReadOnly. Add the following import statement into the file.

from rest_framework import permissions

Then add the following property to the DataRowList and DataRowDetail classes:

permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

If you go to the browsable API now: <docker-machine ip>:8000/datarows/ you will notice that now you are unable to post new data_entry objects.

Lets add a login view to enable authenticated users to login in order to create new data_entry objects. In the project's root add the following:

from django.conf.urls import include


urlpatterns += [
url(r'^api-auth/', include('rest_framework.urls',


If you navigate to the browsable API again you will notive a log in link at the top right of the page. Try logging in with one of the superusers you created in the previous tutorial. You should now be able to add new data entry objects through the browsable API.

Now we will enable object level authentication. This will ensure that only the owner/creator of the data row object is able to delete the object whilst all other users will only have read only access.

To do this in your project directory create a new file named and insert the following code :

from rest_framework import permissions

class IsOwnerOrReadOnly(permissions.BasePermission):
Custom permission to only allow owners of an object to edit it.

def has_object_permission(self, request, view, obj):
Return True if permission is granted, False otherwise.
if request.method in permissions.SAFE_METHODS: # SAFE_METHODS = GET,HEAD,OPTIONS
return True

# Write permissions are only allowed to the owner of the snippet.
return obj.owner == request.user

Next add the newly created custom permission to the DataRowDetail view:

permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly)

Don't forget to include the customer permission class in the file:

from .permissions import IsOwnerOrReadOnly

Test out the Browsable API urls again using the credentials of user1 and user2. You should only be able to delete and put forms if you are logged in as the user that made the data row entry.

Django provides default authentication mechanisms. You can test out whether you can programmatically post data into your api via the following command:

curl -d "date=2017-04-01&gender=M&favorite_number=123&owner=2&csrfmiddlewaretoken=[CSRF Token]" --cookie "csrftoken [CSRF Token]" http://[docker machine ip]:8000/datarows/
# You chould also use below curl command if you cannot find your CSRF Token.
curl -d "date=2017-04-01&gender=M&favorite_number=123&owner=2" http://[docker machine ip]:8000/datarows/

You should get the following data returned:

{"detail":"Authentication credentials were not provided."}

This is because you are now required to provide the user credentials when making a POST request. Try the following CURL command:

curl -d "date=2017-04-01&gender=M&favorite_number=123&owner=2" -u [username]:[password] http://[docker machine ip]:8000/datarows/
# {"id":[id_number],"date":"2017-04-01","gender":"M","favorite_number":123,"owner":[username]}


Now you should know how to make API endpoints and to implement Authentication and Permissions on your API end points. Next we will look into using hyperlinking for managing relationships between our data instead of relying solely on just primary keys.

Subscribe to our mailing list

* indicates required