I want to get the user's detail information:
class UserDetailAPIView(RetrieveAPIView):
"""
User detail information
"""
queryset = User.objects.filter(is_valid=True).exclude(status=4)
serializer_class = UserDetailSerializer
lookup_field = "username"
I want to limit other users to access this APIView, I want only admin user and the user it self to access that.
How to limit this?
you should define your own permission class.something like this:
from rest_framework import permissions
class OwnerProfilePermission(permissions.BasePermission):
"""object lvl permissions for owner """
def has_object_permission(self, request, view, obj):
return obj.user == request.user
and in your views include permission_classes .see DRF documention.
http://www.tomchristie.com/rest-framework-2-docs/api-guide/permissions
and the class base views you choose is important.
http://www.tomchristie.com/rest-framework-2-docs/api-guide/generic-views
Related
At my question, my problem is
How to log in and check, if user is staff, can access to url or use a views class ?
I want to user login on website (Not admin-console) and user is staff (in admin-console) can post.
And someone just have a account create on web (they dont have permission staff) thay just can login.
Thank you so much !
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ['title','content']
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
If you want only the staff user can access the view then you can use the UserPassesTestMixin and LoginRequiredMixin like this:
class StaffRequiredMixin(LoginRequiredMixin, UserPassesTestMixin):
def test_func(self):
return self.request.user.is_staff
Now in your PostCreateView you can implement like this:
class PostCreateView(StaffRequiredMixin, CreateView):
......
You can use user.is_staff to check this.
Ref: https://docs.djangoproject.com/en/dev/ref/contrib/auth/#django.contrib.auth.models.User.is_staff
Create a file named: permissions.py
And then you can do something like below:
from rest_framework.permissions import BasePermission
class PermissionMixin:
'''
Initializes user permissions
'''
def __init__(self):
self._actions = ()
self._user = False
self._admin = False
def _initialize_permissions(self, request):
self._actions = settings.ALLOWED_ACTIONS
self._user = request.user and request.user.is_active
self._admin = self._user and request.user.is_superuser
class AdminsOnlyPermission(BasePermission, PermissionMixin):
'''
Determines operations that can be performed by admins only
'''
def has_permission(self, request, view):
self._initialize_permissions(request)
if view.action in self._actions:
return self._admin
else:
return False
If you are using DRF, you can use IsAdminUser:
from rest_framework import mixins, viewsets
from rest_framework.permissions import IsAdminUser
from my_serializers import SomeSerializer
class SomeView(mixins.ListModelMixin, viewsets.GenericViewSet):
serializer_class = SomeSerializer
queryset = SomeSerializer.Meta.model.objects.all()
permission_classes = [IsAdminUser]
It checks that there is a user logged in and that is has is_staff in true.
I'm creating a simple web app and I cannot find any way to forbid other users from changing your password. This is minimal code:
# serializers.py
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
def create(self, validated_data):
# have to use custom create method because default method calls `User.objects.create()` which doesn't take care of password hashing and other important stuff
return User.objects.create_user(**validated_data)
class Meta:
model = User
fields = ('id', 'username', 'email', 'password')
read_only_fields = ('id', 'username')
# password is set to write_only because I don't want to send it to anybode (even though it's just a hash)
extra_kwargs = {'password': {'write_only': True}}
# views.py
from .serializers import UserSerializer
from rest_framework import generics
from django.contrib.auth.models import User
class UserDetails(generics.RetrieveUpdateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
I could take care of this myself by using APIView.
# views.py
from .serializers import UserSerializer
from rest_framework.views import APIView
from django.contrib.auth.models import User
class UserDetails(APIView):
def put(self, request, format=None):
serialized = UserSerializer(data=request.DATA)
if not serialized.is_valid():
return # probably HTTP 400 Error code
if request.user.id != serialized.data['id']:
# this if is what I'm trying to achieve
return # probably HTTP 403 Error code
user = User.objects.update(
id=serialized.data['id'],
email=serialized.data['email']
)
if 'password' in request.DATA:
user.set_password(request.DATA['password'])
return # probably HTTP 200 Error code
Unfortunately, that would have caused that scheme generated by rest_framework.schemas.get_schema_view would be incomplete. And I use for communication CoreAPI (which cannot communicate with something that is not described in the scheme) so I cannot do that. I haven't found anything in the official documentation.
This seems to be a too basic problem that has a super easy solution that I missed. Thanks for any ideas or places where to look.
PS: I'm using django2.1 with python3.6
Edit: osobacho's solutions is clean and works like charm. Anyway I also need to allow modifications (let's say of TODO-list) only to creator of that todo list. Thought that solution for password problem would be applicable but it's not.
You can get the user in the request. That way each user will only be able to change their own password.
class UserDetails(generics.RetrieveUpdateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
def get_object(self):
return self.request.user
For your second question take a look at django_restframework http://www.django-rest-framework.org/api-guide/permissions/ permissions here is an example:
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
Object-level permission to only allow owners of an object to edit it.
Assumes the model instance has an `owner` attribute.
"""
def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request,
# so we'll always allow GET, HEAD or OPTIONS requests.
if request.method in permissions.SAFE_METHODS:
return True
# Instance must have an attribute named `owner`.
return obj.owner == request.user
then you need to add to your view:
permission_classes = (IsOwnerOrReadOnly,)
hope it helps
I'm using Django User model in my Django project. my user view is:
from django.contrib.auth.models import User
from django.dispatch import receiver
from django.db.models.signals import post_save
from rest_framework import generics
from rest_framework import permissions
from rest_framework import status
from rest_framework.authtoken.models import Token
from rest_framework.response import Response
from myapp.serializers.user import UserSerializer, UserListSerializer
class UserList(generics.ListCreateAPIView):
model = User
permission_classes = (permissions.IsAuthenticated, )
_ignore_model_permissions = True
serializer_class = UserListSerializer
queryset = User.objects.exclude(pk=-1)
def post(self, request, *args, **kwargs):
userName = request.DATA.get('username', None)
userPass = request.DATA.get('password', None)
user = User.objects.create_user(username=userName, password=userPass)
if not user:
return Response({'message': "error creating user"}, status=status.HTTP_200_OK)
return Response({'username': user.username}, status=status.HTTP_201_CREATED)
class UserDetail(generics.RetrieveUpdateDestroyAPIView):
model = User
permission_classes = (permissions.IsAuthenticated, )
_ignore_model_permissions = True
serializer_class = UserSerializer
queryset = User.objects.exclude(pk=-1)
When I try to view users page logged in as a superuser, I can see the list of all the users. But when I try to access it with a non-superuser, I get an empty list.
I like every user to be able to view the user list but only its own user detail if it is non superuser. I tried using signals (such as post_migrate) but the problem is that for each user I need to give view permission to every other user every time I migrate.
Is there any easier way to do this?
I can see the list of all the users. But when I try to access it with a non-superuser, I get an empty list.
From your code you should be able to access UserList even if you are not superuser.
I like every user to be able to view the user list but only its own user detail if it is non superuser.
Try custom permission.
class IsOwner(permissions.BasePermission):
"""
Custom permission to only allow owners of an object to edit it.
"""
def has_object_permission(self, request, view, obj):
return obj == request.user
class UserDetail(generics.RetrieveUpdateDestroyAPIView):
model = User
permission_classes = (permissions.IsOwner, )
_ignore_model_permissions = True
serializer_class = UserSerializer
queryset = User.objects.exclude(pk=-1)
Now only owner can see their details
Suppose I have the following model -
class Person(models.Model):
name = models.CharField(max_length=200)
clubs = models.ManyToManyField(Club,related_name = 'people')
date = models.DateTimeField(default=datetime.now)
def __str__(self):
return self.name
used to create a rest api.
views.py
class PersonDetail(generics.RetrieveUpdateDestroyAPIView):
serializer_class = PersonSerializer
def get_object(self):
person_id = self.kwargs.get('pk',None)
return Person.objects.get(pk=person_id)
How do I add permissions so that only authenticated user can add,update delete or retrieve objects from the person list in the api. And read-only permissions for non authorized users. I tried going through the docs but it is all very confusing. Can someone explain?
You need to add IsAuthenticatedOrReadOnly permission class to PersonDetail view.
From the DRF Docs:
The IsAuthenticatedOrReadOnly will allow authenticated users to perform any request. Requests for unauthorised users will only be permitted if the request
method is one of the "safe" methods; GET, HEAD or OPTIONS.
from rest_framework.permissions import IsAuthenticatedOrReadOnly
class PersonDetail(generics.RetrieveUpdateDestroyAPIView):
serializer_class = PersonSerializer
permission_classes = (IsAuthenticatedOrReadOnly,) # specify the permission class in your view
def get_object(self):
person_id = self.kwargs.get('pk',None)
return Person.objects.get(pk=person_id)
I am trying to create a simple service which allows anonymous users to submit their name and email. I want to AllowAny on adding their info, and IsAuthenticated on everything else. I'm having trouble getting this granularity.
models.py
from django.db import models
class Invitee(models.Model):
name = models.CharField(max_length=255)
email = models.EmailField(max_length=70,blank=True)
modified = models.DateTimeField(auto_now=True)
serializers.py
class InviteeSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Invitee
fields = ('name', 'email')
def create(self, validated_data):
return Invitee(**validated_data)
views.py
class InviteeViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows groups to be viewed or edited.
"""
queryset = Invitee.objects.all()
serializer_class = InviteeSerializer
What and where should I put to make it so users can submit their name and email, but only admins can read, update, delete? Thanks any help.
The easiest and safest way to do this is with multiple serializers, one of each user class you need. You will also need to use custom permissions to enforce the read/write difference between authenticated and anonymous users.
class InviteeSerializer(serializers.HyperlinkedModelSerializer):
def create(self, validated_data):
return Invitee(**validated_data)
class LimitedInviteeSerializer(InviteeSerializer):
class Meta:
model = Invitee
fields = ('name', 'email', ) # a limited subset of the fields
class FullInviteeSerializer(InviteeSerializer):
class Meta:
model = Invitee
fields = ('name', 'email', "modified", ) # all of the fields
While right now it only looks like you need read/write, if you need full read/write/delete permissions I would recommend reading this Stack Overflow question.
You will also need to control what serializer is being used on the view level. This needs to be done using a combination of permissions and overridden view methods.
class InviteeViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows groups to be viewed or edited.
"""
queryset = Invitee.objects.all()
serializer_class = LimitedInviteeSerializer
def get_serializer_class(self):
if self.request.user.is_active:
return FullInviteeSerializer
return super(InviteeViewSet, self).get_serializer_class()
On the view you will need to override get_serializer_class to determine what serializer should be used based on if the user is active. Anonymous users should never be marked as active, so this is the best way to check while excluding deactivated accounts.
You will also need to create a custom permissions class that will do the opposite of the built-in IsAuthenticatedOrReadOnly permission. You are looking for authenticated users to do everything, and anonymous users to only be write-only. I've called this class IsAuthenticatedOrWriteOnly to match the other permission class.
class IsAuthenticatedOrWriteOnly(BasePermission):
"""
The request is authenticated as a user, or is a write-only request.
"""
def has_permission(self, request, view):
WRITE_METHODS = ["POST", ]
return (
request.method in WRITE_METHODS or
request.user and
request.user.is_authenticated()
)
You just need to add this your existing list of permission classes, or override it manually it on the view using permission_classes.